オンラインSQLインデックス最適化とインデックス選択エラーの原理の分析

同僚が2日前に担当した注文モジュールのクエリで奇妙な問題が発生しました。フィルタ条件を追加すると、クエリタイムアウトの問題が発生します。すべての注文をクエリしても問題はありません。SQLは次のとおりです(データの感度が低く、MySqlが使用されています)。

SELECT
	a.consumer_code AS orderCode,
	a.rent_equipment_snid AS eqSn,
	a.powerbank_snid AS pbSn,
	a.rent_merchant_name AS rentMerchant,
	a.rent_merchant_address AS merchantAddress,
	a.rent_date AS rentTime,
	a.close_date AS returnTime,
	a.payment_money AS orderAmount,
	a.order_status AS orderStatus,
	a.consume_schema AS consumeSchema,
	a.transaction_status AS transStatus,
	a.rent_equipment_model AS eqModel 
FROM
	cp_consumer_order_2020_10 a 
WHERE
	a.agent_code = xxxx
	# 下面两个条件就是筛选时才会加上
	AND a.order_status = xxx 
	AND a.close_date IS NULL 
ORDER BY
	a.consumer_code desc

cp_consumer_order_2020_10は、ほぼ1,000万のデータを含む月次注文テーブルであり、consumer_codeがプライマリキーであり、agent_codeには通常のインデックスがあります。
上記のSQLをデータベースで実行したところ、agent_codeインデックスがなくなり、クエリの効率は正常でした。その後、フィルタ条件を削除しても、実行結果は同じでした。ここに写真の説明を挿入
ここに写真の説明を挿入

上記は条件付きと無条件の実行計画であり、違いがないことがわかります。現時点で
ここに写真の説明を挿入
は、コードに時間のかかる操作があるかどうか疑問に思いますこのコードには特に時間のかかる操作はないようです。getAgentOrderListはそのSQLを実行するためのものであり、getAgentStaffOrderListもページングのために、非常に迅速にクエリを実行しようとしました。ループの実行は特に遅くなることはありません。
別の「精神的な事件」が発生した可能性はありますか?このとき、突然、ページングが原因かと思いました。オフセットが非常に大きいと、制限によってクエリが遅くなることは誰もが知っていますが、最初のページであるページをまだめくっていないので、問題ありません。
また、以前に制限と順序を使用したときにインデックス選択エラーの問題が発生したと思ったので、制限0,30を持ってきて、データベースでSQLを実行しました。予想どおり、遅いSQLが表示されました。現時点では、実行計画を次のように
ここに写真の説明を挿入
確認します。Mysqlがこの時点でプライマリキーインデックス、つまり並べ替えるフィールドを使用していることがわかります。そのため、同僚が強制インデックスを使用して通常のインデックスを強制すると、クエリが通常に戻ることをお勧めします。
この時点でSQLの最適化は終了しましたが、制限を追加するとMysqlが間違ったインデックスを選択するのはなぜですか。また、プライマリキーインデックスの使用が非常に遅く、スキャンされる行の推定数が明らかに少ないのはなぜですか。「何が起こっているのかを知るだけでなく、その理由も知る」という原則に沿って、たくさんの情報をチェックしましたが、心の疑問を完全に解決することはできず、何度も試してみて、ようやく理解しました。

  • まず、通常のインデックスの使用が速く、プライマリキーインデックスの使用が遅いのはなぜですか?
    私のSQLはプライマリキーインデックスを逆の順序でクエリした結果であるため、インデックスは自然に順序付けられ、並べ替える必要はありません。したがって、実行プランのExtraフィールドには、通常のインデックスよりも高速なUsing filesortがないことがわかりますが、このSQLはwhere条件によってフィルタリングされます。はい、注文した結果を取得したら、agent_codeとwhere条件を1つずつ取り出して一致させる必要があります。これを見て、読者は基本的に理解する必要があると思います。制限がない場合、このSQLはテーブル全体をスキャンします。制限が0,30の場合、次の状況が発生します。まず、where条件に一致する30レコードが適切です。並べ替え後の最初の30アイテムの場合、mysqlは30アイテムをスキャンするだけで済みます。アイテムが30未満の場合、または並べ替えの最後に一致するレコードがある場合は、テーブル全体がスキャンされます。ただし、フィルター条件はagent_codeであり、すばやく一致させることができるため、通常のインデックスagent_codeにはこの問題はありません。
  • 制限が追加されたときにプライマリキーインデックスが使用されるのはなぜですか?
    プライマリキーインデックスを無制限に使用すると、前述のようにwhere条件に1つずつ一致しますが、返されるアイテムの数に制限はなく、テーブル全体のスキャンが実行されます(force index(primary)+ explainを使用して行を表示できます)これはテーブルの合計行数(1000w)であり、Mysqlは、通常のインデックスのスキャン行の推定数が1.8W未満であるため、通常のインデックスを使用する方が速いと考えています。ただし、制限を追加すると、プライマリキーインデックスのスキャン行の推定数は次のようになります。通常のインデックスのスキャンラインの推定数よりも少ないため、インデックス選択エラーが発生します。

おすすめ

転載: blog.csdn.net/l6108003/article/details/109382533