しかし、すべてのマニュアルにも繰り返し説明されている1つのポイントがありますが、何らかの理由で誰もがそれを忘れています。
結合を含むクエリでのORDER BYの最適化。
言い訳:検索を使用して、見つけられませんでした!
ほとんどの人は、ORDER BYがインデックスによって発生する場合、問題はないと考えていますが、常にそうであるとは限りません。 最近、適切な場所にあるすべてのインデックスのように見えますが、データベースを大幅に遅くする1つのクエリを処理しました。 ORDER BYは私が最後に突っ込んだ場所で、問題はそこにありました。
最適化マニュアルからの短い抜粋:
===
MySQLがORDER BYを最適化する方法
以下は、MySQLがインデックスを使用してORDER BYを実行できない場合です。
...
いくつかのテーブルがリンクされており、列によって
ORDER BYソート、最初の非定数にのみ適用されません
(定数)行のフェッチに使用されるテーブル(これが最初のテーブルです
EXPLAIN出力では、定数、const、string fetchメソッドを使用しません)。
...
===
ORDER BYの場合、ソートを実行するテーブルが最初にあることが重要です。 ただし、デフォルトでは、テーブルを結合する順序に関係なく、mysqlに組み込まれたオプティマイザーは、必要と思われる順序でテーブルを再配置します。 つまり、クエリで最初に目的のテーブルを配置した場合、実際に最初のテーブルになるという意味ではありません。
幸いなことに、mysqlオプティマイザーは、指定した順序でテーブルを結合するように指示できます。そのためには、STRAIGHT_JOINコマンドをSELECTに追加する必要があります。
SELECT STRAIGHT_JOIN ... FROMテーブルJOIN ....... ORDER BY table.row
約300,000件の投稿を含むフォーラムPHPBB3のmysqlデータベースを確認してください。
SELECT t.*, p.*, u.username FROM phpbb3_topics as t, phpbb3_posts as p, phpbb3_users as u WHERE t.topic_replies>0 AND p.poster_id=u.user_id AND topic_first_post_id<>p.post_id AND topic_approved=1 AND p.topic_id=t.topic_id AND t.forum_id='16' AND p.post_id<'244103' ORDER by post_id desc LIMIT 40
クエリには12.2571秒かかりました
説明で私たちはひどいものを見ます:whereを使用します; 一時的な使用; ファイルソートの使用
テーブルの順序を変更します(マッスルキャッシュは再起動によりリセットされました):
SELECT STRAIGHT_JOIN t.*, p.*, u.username FROM phpbb3_posts as p, phpbb3_topics as t, phpbb3_users as u WHERE t.topic_replies>0 AND p.poster_id=u.user_id AND topic_first_post_id<>p.post_id AND topic_approved=1 AND p.topic_id=t.topic_id AND t.forum_id='13' AND p.post_id<'234103' ORDER by post_id desc LIMIT 40
クエリには0.0447秒かかりました
説明:whereを使用します。
このようにテーブルを強制的に並べ替えることで、クエリを300倍高速化しました!
これは、常にSTRAIGHT_JOINを使用して、テーブルの順序を自分で追跡する必要があるという意味ではありません。 しかし、場合によってはこれが必要です。
PSこのクエリは、Yandexがphpbbフォーラムのインデックスに使用します。 最適化の前に、Yandex-botはphp.ruサーバーを毎晩数時間置きます(サーバーはあまり強力ではありません)。 Yandexブログにはこのトピックに関する議論がありましたが、数年前に閉じられ、そこで決定は発表されませんでした。