Rails アプリ内のデータベース クエリの一部を最適化しようとしているのですが、行き詰まっているものがいくつかあります。それらはすべてIN
in theWHERE
句を使用しており、適切なインデックスが配置されているように見えても、すべてテーブル全体のスキャンを実行しています。
例えば:
SELECT `user_metrics`.* FROM `user_metrics` WHERE (`user_metrics`.user_id IN (N,N,N,N,N,N,N,N,N,N,N,N))
完全なテーブルスキャンを実行し、EXPLAIN
次のように出力します。
select_type: simple
type: all
extra: using where
possible_keys: index_user_metrics_on_user_id (which is an index on the user_id column)
key: (none)
key_length: (none)
ref: (none)
rows: 208
ステートメントが使用されるときにインデックスは使用されないのでしょうIN
か、それとも何か別の方法で行う必要があるのでしょうか? ここでのクエリは Rails によって生成されるため、関係の定義方法を再検討できますが、まずは DB レベルでの潜在的な修正から始めようと思いました。
ベストアンサー1
MySQLがまだ実行しているかどうかも検証します完全なテーブルスキャンテーブルに 2000 行程度を追加した後user_metrics
。小さなテーブルでは、インデックスによるアクセスは実際にはテーブル スキャンよりもコストがかかり (I/O の観点から)、MySQL のオプティマイザはこれを考慮する場合があります。
前回の投稿とは反対に、MySQLもコストベースのオプティマイザーを使用するANALYZE
これは非常に良いニュースです。つまり、データベース内のデータ量が十分であると思われるときに少なくとも1回は実行すれば、代表将来の日常的な使用について。
コストベースのオプティマイザ(Oracle、Postgresなど)を扱う場合は、定期的に実行する必要があります。ANALYZE
さまざまなテーブルのサイズが 10 ~ 15% 以上増加すると、さまざまなテーブルでこの処理が実行されます (Postgres はデフォルトでこれを自動的に実行しますが、他の RDBMS ではこの処理を DBA、つまりユーザーに任せます)。統計分析により、ANALYZE
さまざまな実行プランの候補を選択する際に、オプティマイザがどの程度の I/O (およびソートに必要な CPU などのその他の関連リソース) が必要になるかをより正確に把握できるようになります。実行に失敗すると、ANALYZE
非常に貧弱で、場合によっては悲惨な計画決定につながる可能性があります (たとえば、数ミリ秒のクエリが、場合によっては数時間かかるなど)。不適切なネストループオンJOIN
s。
を実行した後もパフォーマンスが不十分な場合はANALYZE
、通常、ヒント( など)を使用して問題を回避できますFORCE INDEX
が、他の場合にはMySQLのバグに遭遇した可能性があります(例:年上の方、Rails の を使用すると、問題が発生する可能性がありましたnested_set
。
今、RailsアプリなのでActiveRecord
、生成されたクエリを引き続き使用するのではなく、ヒントを使用してカスタム クエリを発行するのは面倒です (また、 の目的に反します) ActiveRecord
。
Railsアプリケーションで言及したように全て SELECT
クエリは Postgres に切り替えた後 100 ミリ秒未満に短縮されましたが、MySQL 5.1 では、インデックスが使用可能であっても、内部テーブル スキャンによるネストされたループが原因で、生成される複雑なActiveRecord
結合の一部に 15 秒以上かかることがありました。完璧なオプティマイザーは存在しないため、オプションについて知っておく必要があります。クエリ プランの最適化以外に注意すべき潜在的なパフォーマンスの問題は、ロックです。ただし、これは問題の範囲外です。