2011-02-08 25 views
1

私は長い間データベースを扱ってきましたが、私はクエリの最適化を初めて行っています。私は次のクエリを持っています(コード生成の一部):MySQLクエリの最適化とNoobのEXPLAIN

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 

これはかなり遅いです。私の開発サーバーでは、実行するのに約1分かかります。データがあるプロダクションサーバーでは、それを完了させることができません。私はEXPLAINの基本を知って

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

:ここでは次のようにEXPLAINが見えるものです。私はkeyの下のすべてのものに対してNULL以外の何かを持っていることが良いことを知っています。しかし、私は全体的に、私のクエリがどの程度改善の余地があるか分かりません。私はUsing temporary; Using filesortの下にExtraが悪いことを知っていますが、私はそれについて何をすべきか分かりません。

+0

参加するテーブルにインデックスがありますか? – pdiddy

+0

私は参加しているほとんどのテーブルのいくつかの列にインデックスを持っています。 –

+0

@jason swett - このクエリの関連する列は、あなたが参加する列です。下の私の答えを参照してください。 – JNK

答えて

2

ほとんどのJOINフィールドにはインデックスがないようです。 フィールドにJOINキーとして使用するフィールドに両方のテーブルのインデックスが付いていることを確認してください。

23個の結合と、関連する2つのインデックスだけが見える場合、パフォーマンスが低下する可能性があります。

参照するインデックスがない場合、クエリエンジンは両方のテーブルのすべての行を比較して比較していますが、明らかに非常に非効率的です。

編集:

たとえば、クエリで使用すると、

JOIN customer c ON a.customer_id = c.id

を持っているあなたはa.customer_idcustomer.idにインデックスを持っていることを確認してください。両方のテーブル(JOIN edフィールド)にインデックスを付けると、指数関数的にクエリが高速化されます。

+0

良いですから、明らかに改善の余地があります。 「すべてのフィールドに...両方のテーブルのインデックスがあることを確認してください」と言うとき、インデックスとはどういう意味ですか?私の限られた知識では、インデックスはテーブルにではなくカラムに追加するものです。 –

+0

@Jason - それは列にあります。詳細については解答を編集します。 – JNK

+0

ここに推測しておきます:「customer.id」と「account.customer_id」にインデックスを追加しますか?そして、同じアイデアをどこにでも適用してください。 –

1

@ JNKが索引を持っていることを確認する方法についての彼の答えに加えて、私はあなたの問合せを再構成し、トップに「STRAIGHT_JOIN」節を追加して、表が提示された順序で問合せを実行するようオプティマイザに指示しますそれに。

あなたのクエリは一般的なインポートに基づいているため、銀行にバンドルをインポートするために、私はリストの先頭に移動しました...ここで、そのすべてのアカウントを調べるのではなく、結果の一部になることはありません。これで、結合は、一般的なインポートから、同じ関係に続いてアカウントに戻っています。

また、それぞれのJOIN/ON条件を、可読性のために結合していたテーブルの直下に、テーブルの関係に従って、関連づけました。私はまた、ON句がTable1.ID = JoinedTable.IDを持つようにしました。逆のやり方でも大したことはありませんが、何かが他のものへのjoinに基づいていることを知るだけで、読みやすくなります。

したがって、それぞれのテーブルがどのキー列にもインデックスを持ち、このサンプルクエリから、GIテーブル(エイリアス)に "アクティブ"のインデックスが付いていることを確認してください。 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 
+0

ありがとうございます。私が混乱していることの1つは、クエリを実行しようとすると、「ai」は一意のエイリアスではなく、「JOIN account_import ai」が2回あるので真実ですが、私は何をすべきかわかりませんそれ。 –

+0

@ Jason Swett、改訂、私は2番目のインスタンスを取り出しました...それは、主なクエリ要素を逆転したときから複製されました...これを試してみてください。 – DRapp