2013-07-07 53 views
1

很慢我有一個複合鍵表CUSTOMER_PRODUCT_XREFMySQL查詢運行復合鍵表

__________________________________________________________________ 
|CUSTOMER_ID (PK NN VARCHAR(191)) | PRODUCT_ID(PK NN VARCHAR(191))| 
------------------------------------------------------------------- 

在我的批處理程序,我需要選擇500個更新的客戶,也得到了PRODUCT_ID的由逗號分隔的客戶購買並更新我們的SOLR索引。在我詢問我選擇500個客戶,做左連接到CUSTOMER_PRODUCT_XREF

SELECT 
    customer.*, group_concat(xref.PRODUCT_ID separator ', ') 
FROM 
    CUSTOMER customer 
LEFT JOIN CUSTOMER_PRODUCT_XREF xref ON customer.CUSTOMER_ID=xref.CUSTOMER_ID 
group by customer.CUSTOMER_ID 
LIMIT 500; 

編輯:運行上面的查詢,20分鐘後EXPLAIN QUERY

id select_type table type possible_keys key  key_len ref  rows Extra 
1 SIMPLE  customer ALL  PRIMARY  NULL  NULL  NULL 74236 Using where; Using temporary; Using filesort 
1 SIMPLE  xref index  NULL   PRIMARY 1532  NULL 121627 Using where; Using index; Using join buffer (Block Nested Loop) 

我迷路了連接異常。

我試着用下面的(子查詢),它需要1.7秒來得到結果,但仍然很慢。

SELECT 
customer.*, (SELECT group_concat(PRODUCT_ID separator ', ') 
    FROM CUSTOMER_PRODUCT_XREF xref 
     WHERE customer.CUSTOMER_ID=xref.CUSTOMER_ID 
     GROUP BY customer.CUSTOMER_ID) 
FROM 
CUSTOMER customer 
LIMIT 500; 

編輯:解釋查詢產生

id select_type   table  type possible_keys key key_len ref  rows Extra 
1 PRIMARY    customer  ALL  NULL  NULL NULL NULL 74236 NULL 
2 DEPENDENT SUBQUERY xref  index  NULL  PRIMARY 1532 NULL 121627 Using where; Using index; Using temporary; Using filesort 

問題

CUSTOMER_PRODUCT_XREF已經有兩列設置爲PRIMARY_KEY和NOT_NULL偏偏是我的查詢還是很慢?我認爲在列上使用主鍵就足以爲它創建索引。我需要進一步索引嗎?

DATABASE INFO:

  • 所有的ID在我的數據庫是VARCHAR(191),因爲id也可以包含英文字母。
  • 我正在使用utf8mb4_unicode_ci字符編碼
  • 我正在使用SET group_concat_max_len:= @@ max_allowed_pa​​cket獲取每個客戶的最大數量的product_ids。建議在一個主要查詢中使用group_concat,這樣我就不必爲多個客戶執行多個單獨的查詢來獲取產品。
+3

運行使用查詢【解釋】(http://dev.mysql.com/doc/refman/5.6/en /explain.html)並將該命令的結果添加到問題中,這將有助於人們(和您)瞭解正在發生的事情。但嚴重的是,191個字符的主鍵?你確定這不是一個過分的矯枉過正? :-) – fvu

+0

嘗試在CUSTOMER_PRODUCT_XREF上創建一個非唯一索引,僅包括customer_id列。 – Tarik

+2

使用INT主鍵可能更有效率(通過LONG方式),使用INT鍵而不是長鍵,您的191字符鍵是不同的列,而您的相關表使用INT鍵。 – Kickstart

回答

0

當我在CUSTOMER_PRODUCT_XREF表中的CUSTOMER_ID上創建了一個索引時,我的問題中查詢的速度已經上升。

所以我有兩個指標現在 PRIMARY_KEY_INDEX上PRODUCT_ID和CUSTOMER_ID CUSTOMER_ID_INDEX上CUSTOMER_ID

0

您的原始版本的查詢先執行join,然後對所有結果數據進行排序 - 這可能相當大,因爲這些字段的大小有多大。

首先選擇500個客戶,然後做可以「修復」該版本的加入:

SELECT c.*, group_concat(xref.PRODUCT_ID separator ', ') 
FROM (select c.* 
     from CUSTOMER customer c 
     order by c.customer_id 
     limit 500 
    ) c LEFT JOIN 
    CUSTOMER_PRODUCT_XREF xref 
    ON c.CUSTOMER_ID=xref.CUSTOMER_ID 
group by c.CUSTOMER_ID ; 

,可能會或可能不會有大的影響將是由客戶做聚集的替代子查詢和加入,如在:

SELECT c.*, xref.products 
FROM (select c.* 
     from CUSTOMER customer c 
     order by c.customer_id 
     limit 500 
    ) c LEFT JOIN 
    (select customer_id, group_concat(xref.PRODUCT_ID separator ', ') as products 
     from CUSTOMER_PRODUCT_XREF xref 
    ) xref 
    ON c.CUSTOMER_ID=xref.CUSTOMER_ID; 

你所發現的是,MySQL優化不承認這種情況(其中限制對性能有很大的影響)。在這種情況下,一些其他數據庫引擎在優化方面做得更好。

+0

第一次查詢花了1.45秒,第二次查詢沒有返回任何結果。在我的問題中,第一個查詢耗時1.30秒,第二個查詢耗時54秒。我已經將CUSTOMER_PRODUCT_XREF主鍵的VARCHAR ID長度更改爲20個字符,但仍然很慢:( – hajime

+0

@CMR ...我不確定你爲什麼皺眉頭,你正在瞭解MySQL優化器的工作原理, m並不感到意外,相關的子查詢在MySQL中運行良好 - 這並不意味着它可以在其他數據庫中正常工作。 –