2

実行速度が非常に遅い (20 秒以上) 結合のない単純なクエリがあります。クエリ対象のテーブルには約 40 万行があり、where 句で使用されるすべての列にインデックスが付けられています。

SELECT deals.id, deals.title, 
       deals.amount_sold * deals.sale_price   AS total_sold_total
FROM deals  
WHERE deals.country_id = 33 
  AND deals.target_approved = 1 
  AND deals.target_active = 1 
  AND deals.finished_at >= '2012-04-01' 
  AND deals.started_at <= '2012-04-30'
ORDER BY total_sold_total DESC 
LIMIT 0, 10

先週からこれに苦労しています。助けてください:)

更新 1

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  deals   index_merge NewIndex3,finished_at_index,index_deals_on_country_id,index_deals_on_target_active,index_deals_on_target_approved   index_deals_on_target_active,index_deals_on_target_approved,index_deals_on_country_id   2,2,5   \N  32382   Using intersect(index_deals_on_target_active,index_deals_on_target_approved,index_deals_on_country_id); Using where; Using filesort
4

1 に答える 1

3

選択を改善するには、WHERE 句の列を指定された順序で使用して、次の複合インデックスを作成します。

(country_id, target_approved, target_active, finished_at)
(country_id, target_approved, target_active, started_at)

最初にカーディナリティの高い列が必要で、範囲が最後になります。MySQL は、最初の範囲を超えるキー部分を使用できません。そのため、WHERE 句 (>=および<=) の範囲で分岐する 2 つの個別のインデックスがあります。

MySQL がインデックス マージによって両方のインデックスを使用しない場合は、いずれかのインデックスを削除することを検討してください。

残念ながら、MySQL は行を並べ替える前に、total_sold_total を計算してすべての行を返す必要があります。つまり、MySQL はデータセット全体を取得した後、行を手動でソートする必要があります。

ソートにかかる時間は、結果セットのサイズに正比例します。

ソート後に LIMIT が適用されるため、LIMIT 最適化は使用できません。

残念ながら、WHERE 句に範囲があると、事前に計算された total_sold_total 列をインデックスの最後に追加して、結果を既に順序どおりに返すことができなくなり、手動の並べ替えができなくなります。

于 2012-06-01T18:38:46.473 に答える