2011-04-27 154 views
1

這裏的查詢:如何優化此查詢?

SELECT p.name p_name, 
c.name c_name, 
p.line1, 
p.zip, 
c.line1, 
p.zip 
FROM 

(SELECT c.name, 
ad.line1, 
ad.zip 
FROM customer c 
JOIN account a ON a.customer_id = c.id 
JOIN account_address aa ON aa.account_id = a.id 
JOIN address ad ON aa.address_id = ad.id 
JOIN account_import ai ON a.account_import_id = ai.id 
JOIN generic_import gi ON ai.generic_import_id = gi.id 
JOIN import_bundle ib ON gi.import_bundle_id = ib.id 
WHERE gi.active = 1 
AND ib.active = 1 
AND ib.bank_id = 8 
LIMIT 1000) c 

JOIN 
(SELECT p.name, 
a.line1, 
a.zip 
FROM prospect p 
JOIN address a ON p.address_id = a.id) p 
ON 
0 
OR (p.zip = c.zip AND SUBSTRING(p.name, 1, 12) = SUBSTRING(c.name, 1, 12)) 
OR (p.zip = c.zip AND p.name = c.name) 
OR (p.zip = c.zip 
    AND SUBSTRING(p.name, 1, 4) = SUBSTRING(c.name, 1, 4) 
    AND SUBSTRING(SUBSTRING_INDEX(p.name, ' ', -1), 1, 4) = SUBSTRING(SUBSTRING_INDEX(c.name, ' ', -1), 1, 4)) 
OR (p.zip = c.zip 
    AND SUBSTRING(p.name, 1, 3) = SUBSTRING(c.name, 1, 3) 
    AND SUBSTRING(SUBSTRING_INDEX(p.name, ' ', -1), 1, 3) = SUBSTRING(SUBSTRING_INDEX(c.name, ' ', -1), 1, 3) 
    AND SUBSTRING(p.line1, 1, 4) = SUBSTRING(c.line1, 1, 4)) 

這裏的EXPLAIN

*************************** 1. row *************************** 
      id: 1 
    select_type: PRIMARY 
     table: <derived2> 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 1000 
     Extra: 
*************************** 2. row *************************** 
      id: 1 
    select_type: PRIMARY 
     table: <derived3> 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 15030 
     Extra: Using where; Using join buffer 
*************************** 3. row *************************** 
      id: 3 
    select_type: DERIVED 
     table: p 
     type: ALL 
possible_keys: address_id 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 15067 
     Extra: 
*************************** 4. row *************************** 
      id: 3 
    select_type: DERIVED 
     table: a 
     type: eq_ref 
possible_keys: PRIMARY,index_address_id 
      key: PRIMARY 
     key_len: 8 
      ref: mcif.p.address_id 
     rows: 1 
     Extra: 
*************************** 5. row *************************** 
      id: 2 
    select_type: DERIVED 
     table: ib 
     type: index_merge 
possible_keys: PRIMARY,bank_id,fk_bank_id,index_import_bundle_id,index_import_bundle_bank_id,index_import_bundle_active 
      key: index_import_bundle_active,fk_bank_id 
     key_len: 1,8 
      ref: NULL 
     rows: 1 
     Extra: Using intersect(index_import_bundle_active,fk_bank_id); Using where; Using index 
*************************** 6. row *************************** 
      id: 2 
    select_type: DERIVED 
     table: gi 
     type: ref 
possible_keys: PRIMARY,import_bundle_id,index_generic_import_id,index_generic_import_import_bundle_id,index_generic_import_active 
      key: import_bundle_id 
     key_len: 8 
      ref: mcif.ib.id 
     rows: 34 
     Extra: Using where 
*************************** 7. row *************************** 
      id: 2 
    select_type: DERIVED 
     table: ai 
     type: ref 
possible_keys: PRIMARY,generic_import_id,index_account_import_generic_import_id 
      key: generic_import_id 
     key_len: 8 
      ref: mcif.gi.id 
     rows: 1 
     Extra: Using index 
*************************** 8. row *************************** 
      id: 2 
    select_type: DERIVED 
     table: a 
     type: ref 
possible_keys: PRIMARY,fk_account_customer_id,index_account_customer_id,index_account_id,index_account_account_import_id 
      key: index_account_account_import_id 
     key_len: 9 
      ref: mcif.ai.id 
     rows: 1482 
     Extra: Using where 
*************************** 9. row *************************** 
      id: 2 
    select_type: DERIVED 
     table: c 
     type: eq_ref 
possible_keys: PRIMARY,index_customer_id 
      key: PRIMARY 
     key_len: 8 
      ref: mcif.a.customer_id 
     rows: 1 
     Extra: 
*************************** 10. row *************************** 
      id: 2 
    select_type: DERIVED 
     table: aa 
     type: ref 
possible_keys: fk_account_address_account_id,fk_account_address_address_id,index_account_address_account_id,index_account_address_address_id 
      key: fk_account_address_account_id 
     key_len: 8 
      ref: mcif.a.id 
     rows: 1 
     Extra: 
*************************** 11. row *************************** 
      id: 2 
    select_type: DERIVED 
     table: ad 
     type: eq_ref 
possible_keys: PRIMARY,index_address_id 
      key: PRIMARY 
     key_len: 8 
      ref: mcif.aa.address_id 
     rows: 1 
     Extra: 
11 rows in set (0.10 sec) 

我不知道從哪裏開始。我想大多數情況下我只需要有人解釋EXPLAIN

+2

這是一個醜陋的查詢,如果我見過一個。專注於嘗試刪除子選擇,並將其替換爲純連接。 – 2011-04-27 17:50:15

+0

查詢應該做什麼? – Pentium10 2011-04-27 18:12:45

+0

喬納斯,您的評論是我重寫查詢中最有用的。如果你說同樣的答案,我會接受。 – 2011-04-27 18:39:42

回答

0

解決方案是取出子查詢並僅使用連接重寫查詢。

0

數據庫引擎將嘗試儘快使用where子句刪除行。但是,在您的第一個子選擇中,不可能開始使用where子句刪除行,直到您加入表6表。你是指在where子句中的第一個表始終應你選擇第一個表,你是指在where條款的第二個表應該是你在加盟的第一個表。

所以儘量切換順序

SELECT 
    p.name AS p_name, 
    c.name AS c_name, 
    p.line1, 
    p.zip, 
    c.line1, 
    p.zip 
FROM (
    SELECT 
    c.name, 
    ad.line1, 
    ad.zip 
    FROM generic_import AS gi 
    JOIN import_bundle AS ib ON gi.import_bundle_id = ib.id 
    JOIN account_import AS ai ON ai.generic_import_id = gi.id 
    JOIN account AS a ON a.account_import_id = ai.id 
    JOIN account_address AS aa ON aa.account_id = a.id 
    JOIN address AS ad ON aa.address_id = ad.id 
    JOIN customer AS c ON a.customer_id = c.id 
    WHERE gi.active = 1 
    AND ib.active = 1 
    AND ib.bank_id = 8 
    LIMIT 1000) AS c 
    JOIN 
    (SELECT 
     p.name, 
     a.line1, 
     a.zip 
    FROM prospect AS p 
    JOIN address AS a ON p.address_id = a.id 
    ) AS p 
    ON (p.zip = c.zip 
    AND SUBSTRING(p.name, 1, 12) = SUBSTRING(c.name, 1, 12) 
     ) 
    OR (p.zip = c.zip AND p.name = c.name) 
    OR 
    (p.zip = c.zip AND SUBSTRING(p.name, 1, 4) = SUBSTRING(c.name, 1, 4) 
     AND SUBSTRING(SUBSTRING_INDEX(p.name, ' ', -1), 1, 4) = 
     SUBSTRING(SUBSTRING_INDEX(c.name, ' ', -1), 1, 4) 
    ) 
    OR 
    (p.zip = c.zip AND SUBSTRING(p.name, 1, 3) = SUBSTRING(c.name, 1, 3) 
    AND SUBSTRING(SUBSTRING_INDEX(p.name, ' ', -1), 1, 3) = 
     SUBSTRING(SUBSTRING_INDEX(c.name, ' ', -1), 1, 3) 
    AND SUBSTRING(p.line1, 1, 4) = SUBSTRING(c.line1, 1, 4) 
    ) 

是更快:在大內選擇:)

這裏是我的嘗試,但當然未經檢驗的,因爲我沒有在數據庫中的表? D:

0

您可以嘗試將prospect.name添加到prospect.address_id上的索引,因此您將在address_id,name上有一個索引。它應該會提高性能(至少從第3排explain)。 也行
OR (p.zip = c.zip AND p.name = c.name)似乎是多餘的 -
(p.zip = c.zip AND SUBSTRING(p.name, 1, 12) = SUBSTRING(c.name, 1, 12))包括所有行,其中p.name = c.name

1

這些子字符串正在破壞你使用索引的任何機會,你可以刪除它們並加入全名嗎?如果沒有,你可以添加一個額外的索引列到包含名稱子字符串的表中,然後加入那些?