私はよく同じ質問をされます。最適化が必要なクエリをどのように見つけることができますか。 結局、たとえば、pt-query-digestレポートを見ると、遅いクエリやシステムに大きな負荷を引き起こすクエリを簡単に見つけることができますが、このクエリを高速化する機会があるかどうかをどのように理解できますか? クエリを最適化する方法は多数あるため、この質問に対する完全な回答には、包括的な分析が必ず必要です。 ただし、適用できる非常に便利なメトリックが1つあります。クエリによって返される行の数と完了した行の関係です。
例があるとしましょう:
この場合のクエリは(一致するものがないため)0行を返しましたが、このために1,000万行を処理する必要がありました。 どのシナリオが望ましいでしょうか? 要求が最終的に返される行と同じ数の行を通過した場合。 この場合、インデックスをテーブルに配置すると、スロークエリログに次のエントリが記録され、すべてのスロークエリが該当します。
Rows_examined = 0の値は、Rows_sentと一致し、リクエストが非常に適切に最適化されていることを意味します。 この場合、データベースへのアクセスがまったく発生しないと思った場合は、間違っていることに注意してください。 インデックスはスキャンされますが、MySQLパーツによる処理のためにトップに戻されて返された行のみがカウントされるため、Rows_examinedの値はゼロのままです。
すべてが非常に単純に思えますが、これは速すぎる結論です。 このような数学は、集計関数/グループ化なしのクエリでのみ機能し、さらに1つのテーブルを通過するクエリでのみ機能します。 しかし、複数のテーブルに影響するクエリはどうでしょうか?
この場合、実際には2つのテーブルを結合しますが、テーブルへのアクセスのタイプが「定数」に設定されているため、MySQLは2つのテーブルへのアクセスを考慮しません。 「実際の」アクセスの場合、出力は次のようになります。
この場合、行セットごとに2行の分析行があります。これは、このクエリで2つの(論理)テーブルが使用されているためです。 リクエストにグループがある場合、このルールは機能しません。
このクエリは2行のみを返しますが、1000万件を通過します。結果をグループ化するにはすべての行を通過する必要があるため、このクエリを簡単に最適化することはできません。
この場合、group byおよび集約関数をリクエストから削除することを検討するかもしれません。 その後、リクエストは
“select * from sbtest”
に
“select * from sbtest”
、1000万行すべてが返されるため、単純な最適化方法はありません。
この方法は、明確な「はい」または「いいえ」の答えを提供するために作成されたものではありませんが、最終的にどのような最適化を達成できるかを大いに助けます。 1000行のインデックスを使用して10を返すクエリがあるとします。たとえば、結合インデックスを追加することで、通過する行数を100倍減らすことができます。
それでは、簡潔に-クエリを最適化する価値があるかどうかをどのようにしてすばやく見つけることができますか?
-group by、distinct、aggregate関数を削除した後にクエリが返す行数を確認する(A)
-渡された行の数を、結合内のテーブルの数で割ったものを取ります(B)
-BがA以下の場合、リクエストは「完璧」です
-B / Aが10以上の場合。 このリクエストは最適化の最も価値のある候補の1つです。
これは簡単な方法であり、平均値だけでなく境界値も報告するため、pt-query-digestと一緒に安全に使用できます。
元の記事:
こちら