2011-02-08 54 views
1

我一直在使用數據庫很長一段時間,但我是新的查詢優化。我有以下查詢(有些生成的代碼):MySQL查詢優化和解析爲noob

SELECT DISTINCT COALESCE(gi.start_time, '') start_time, 
COALESCE(b.name, '') bank, 
COALESCE(a.id, '') account_id, 
COALESCE(a.account_number, '') account_number, 
COALESCE(at.code, '') account_type, 
COALESCE(a.open_date, '') open_date, 
COALESCE(a.interest_rate, '') interest_rate, 
COALESCE(a.maturity_date, '') maturity_date, 
COALESCE(a.opening_balance, '') opening_balance, 
COALESCE(a.has_e_statement, '') has_e_statement, 
COALESCE(a.has_bill_pay, '') has_bill_pay, 
COALESCE(a.has_overdraft_protection, '') has_overdraft_protection, 
COALESCE(a.balance, '') balance, 
COALESCE(a.business_or_personal, '') business_or_personal, 
COALESCE(a.cumulative_balance, '') cumulative_balance, 
COALESCE(c.customer_number, '') customer_number, 
COALESCE(c.social_security_number, '') social_security_number, 
COALESCE(c.name, '') customer_name, 
COALESCE(c.phone, '') phone, 
COALESCE(c.deceased, '') deceased, 
COALESCE(c.do_not_mail, '') do_not_mail, 
COALESCE(cdob.date_of_birth, '') date_of_birth, 
COALESCE(ad.line1, '') line1, 
COALESCE(ad.line2, '') line2, 
COALESCE(ad.city, '') city, 
COALESCE(s.name, '') state, 
COALESCE(ad.zip, '') zip, 
COALESCE(o.officer_number, '') officer_number, 
COALESCE(o.name, '') officer_name, 
COALESCE(po.line1, '') po_box, 
COALESCE(po.city, '') po_city, 
COALESCE(po_state.name, '') po_state, 
COALESCE(po.zip, '') zip, 
COALESCE(br.number, '') branch_number, 
COALESCE(cd_type.code, '') cd_type, 
COALESCE(mp.product_number, '') macatawa_product_number, 
COALESCE(mp.product_name, '') macatawa_product_name, 
COALESCE(pt.name, '') macatawa_product_type, 
COALESCE(hhsc.name, '') harte_hanks_service_category, 
COALESCE(mp.hoh_hierarchy, '') hoh_hierarchy, 
COALESCE(cft.name, '') core_file_type, 
COALESCE(oa.line1, '') original_address_line1, 
COALESCE(oa.line2, '') original_address_line2, 
COALESCE(uc.code, '') use_class 
      FROM account a 
      JOIN customer c ON a.customer_id = c.id 
      JOIN officer o ON a.officer_id = o.id 
      JOIN account_address aa ON aa.account_id = a.id 
     LEFT JOIN account_po_box apb ON apb.account_id = a.id     
      JOIN address ad ON aa.address_id = ad.id 
      JOIN original_address oa ON oa.address_id = ad.id 
     LEFT JOIN address po ON apb.address_id = po.id 
      JOIN state s ON s.id = ad.state_id 
     LEFT JOIN state po_state ON po_state.id = po.state_id 
     LEFT JOIN branch br ON a.branch_id = br.id 
      JOIN account_import ai ON a.account_import_id = ai.id 
      JOIN generic_import gi ON gi.id = ai.generic_import_id 
      JOIN import_bundle ib ON gi.import_bundle_id = ib.id 
      JOIN bank b ON b.id = ib.bank_id 
     LEFT JOIN customer_date_of_birth cdob ON cdob.customer_id = c.id 
     LEFT JOIN cd_type ON a.cd_type_id = cd_type.id 
     LEFT JOIN account_macatawa_product amp ON amp.account_id = a.id 
     LEFT JOIN macatawa_product mp ON mp.id = amp.macatawa_product_id 
     LEFT JOIN product_type pt ON pt.id = mp.product_type_id 
     LEFT JOIN harte_hanks_service_category hhsc 
      ON hhsc.id = mp.harte_hanks_service_category_id 
     LEFT JOIN core_file_type cft ON cft.id = mp.core_file_type_id 
     LEFT JOIN use_class uc ON a.use_class_id = uc.id 
     LEFT JOIN account_type at ON a.account_type_id = at.id 

     WHERE 1 
      AND gi.active = 1 
      AND b.id = 8 AND ib.is_finished = 1 

     ORDER BY a.id 
      LIMIT 10 

而且這是非常緩慢的。在我的開發服務器上,運行大約需要一分鐘,並且在我的生產服務器上,有更多數據,我甚至無法完成。下面是一個EXPLAIN樣子:

http://i.stack.imgur.com/eR6lq.png

我知道EXPLAIN基礎。我知道在key之下的所有東西都有NULL以外的東西。但總的來說,我不知道我的查詢有多大改進空間。我知道在Extra下的Using temporary; Using filesort不好,但我不知道該怎麼做。

+0

你有加入表的索引嗎? – pdiddy 2011-02-08 15:02:58

+0

我在我加入的大多數表格的某些列上有索引。 – 2011-02-08 15:05:07

+0

@jason swett - 此查詢中的相關列是您加入的列。請參閱下面的答案。 – JNK 2011-02-08 15:07:14

回答

2

看起來您的JOIN字段中大部分都沒有索引。確保字段您使用作爲JOIN鍵在兩個表上都有一個索引。

有23個連接,看起來只有2個相關索引,可以預期性能不佳。

由於沒有可供引用的索引,查詢引擎正在檢查兩個表中的每一行以比較它們,這顯然非常低效。

編輯:

例如,在查詢你有

JOIN customer c ON a.customer_id = c.id

確保您有a.customer_idcustomer.id的索引。在兩個表上(在JOIN ed字段上)都有一個索引將以指數形式加速查詢。

1

除了@JNK在關於確保你有索引的回答中提到的內容之外,我重新構造了你的查詢並在頂部添加了「STRAIGHT_JOIN」子句,它告訴優化器按照表的順序進行查詢到它。

由於您的查詢基於通用導入,要將綁定導入銀行,我已將這些移動到列表的前面......在哪裏將預先限定THOSE記錄,而不是查看所有帳戶可能永遠不會成爲結果的一部分。所以,現在連接從通用導入轉回到您開始使用的相同關係之後的帳戶。

爲了提高可讀性和遵循表關係,我還將直接在它們加入的表下的JOIN/ON條件關聯起來。我也做了這樣的ON子句有Table1.ID = JoinedTable.ID ...雖然有些逆轉,否則沒有什麼大不了的,知道如何基於聯接INTO另一個只是允許更容易的可讀性。

因此,確保各個表都有索引,無論哪個鍵列是連接,並從此示例查詢中,確保您的GI表(別名)具有「Active」索引,並且您的IB(別名)具有索引在Is_Finished上。

最後,你的WHERE子句有WHERE 1 AND ...沒有「1」的目的,所以我把它刪除了。

SELECT STRAIGHT_JOIN DISTINCT 
     COALESCE(gi.start_time, '') start_time, 
     COALESCE(b.name, '') bank, 
     COALESCE(a.id, '') account_id, 
     COALESCE(a.account_number, '') account_number, 
     COALESCE(at.code, '') account_type, 
     COALESCE(a.open_date, '') open_date, 
     COALESCE(a.interest_rate, '') interest_rate, 
     COALESCE(a.maturity_date, '') maturity_date, 
     COALESCE(a.opening_balance, '') opening_balance, 
     COALESCE(a.has_e_statement, '') has_e_statement, 
     COALESCE(a.has_bill_pay, '') has_bill_pay, 
     COALESCE(a.has_overdraft_protection, '') has_overdraft_protection, 
     COALESCE(a.balance, '') balance, 
     COALESCE(a.business_or_personal, '') business_or_personal, 
     COALESCE(a.cumulative_balance, '') cumulative_balance, 
     COALESCE(c.customer_number, '') customer_number, 
     COALESCE(c.social_security_number, '') social_security_number, 
     COALESCE(c.name, '') customer_name, 
     COALESCE(c.phone, '') phone, 
     COALESCE(c.deceased, '') deceased, 
     COALESCE(c.do_not_mail, '') do_not_mail, 
     COALESCE(cdob.date_of_birth, '') date_of_birth, 
     COALESCE(ad.line1, '') line1, 
     COALESCE(ad.line2, '') line2, 
     COALESCE(ad.city, '') city, 
     COALESCE(s.name, '') state, 
     COALESCE(ad.zip, '') zip, 
     COALESCE(o.officer_number, '') officer_number, 
     COALESCE(o.name, '') officer_name, 
     COALESCE(po.line1, '') po_box, 
     COALESCE(po.city, '') po_city, 
     COALESCE(po_state.name, '') po_state, 
     COALESCE(po.zip, '') zip, 
     COALESCE(br.number, '') branch_number, 
     COALESCE(cd_type.code, '') cd_type, 
     COALESCE(mp.product_number, '') macatawa_product_number, 
     COALESCE(mp.product_name, '') macatawa_product_name, 
     COALESCE(pt.name, '') macatawa_product_type, 
     COALESCE(hhsc.name, '') harte_hanks_service_category, 
     COALESCE(mp.hoh_hierarchy, '') hoh_hierarchy, 
     COALESCE(cft.name, '') core_file_type, 
     COALESCE(oa.line1, '') original_address_line1, 
     COALESCE(oa.line2, '') original_address_line2, 
     COALESCE(uc.code, '') use_class    
    FROM 
     generic_import gi 
     JOIN import_bundle ib 
      ON gi.import_bundle_id = ib.id 
      JOIN bank b 
       ON ib.bank_id = b.id 
     JOIN account_import ai 
      ON gi.id = ai.generic_import_id 
     JOIN account a 
      ON ai.id = a.account_import_id 
      JOIN customer c 
       ON a.customer_id = c.id 
       LEFT JOIN customer_date_of_birth cdob 
        ON c.id = cdob.customer_id 
      JOIN officer o 
       ON a.officer_id = o.id 
      LEFT JOIN branch br 
       ON a.branch_id = br.id 
      LEFT JOIN cd_type 
       ON a.cd_type_id = cd_type.id 
      LEFT JOIN account_macatawa_product amp 
       ON a.id = amp.account_id 
       LEFT JOIN macatawa_product mp 
        ON amp.macatawa_product_id = mp.id 
        LEFT JOIN product_type pt 
        ON mp.product_type_id = pt.id 
        LEFT JOIN harte_hanks_service_category hhsc 
        ON mp.harte_hanks_service_category_id = hhsc.id 
        LEFT JOIN core_file_type cft 
        ON mp.core_file_type_id = cft.id 
      LEFT JOIN use_class uc 
       ON a.use_class_id = uc.id 
      LEFT JOIN account_type at 
       ON a.account_type_id = at.id 
      JOIN account_address aa 
       ON a.id = aa.account_id 
       JOIN address ad 
        ON aa.address_id = ad.id 
        JOIN original_address oa 
        ON ad.id = oa.address_id 
        JOIN state s 
        ON ad.state_id = s.id 
      LEFT JOIN account_po_box apb 
       ON a.id = apb.account_id 
       LEFT JOIN address po 
        ON apb.address_id = po.id 
        LEFT JOIN state po_state 
        ON po.state_id = po_state.id 
     WHERE 
       gi.active = 1 
      AND ib.is_finished = 1 
      AND b.id = 8 
     ORDER BY 
      a.id 
     LIMIT 
      10