MySQL のスロー クエリ (正式名はスロー クエリ ログ) は、MySQL によって提供されるログ レコードで、応答時間が MySQL のしきい値を超えたステートメントを記録するために使用されます。静的について紹介しますので、必要に応じて参照してください。
1 遅い SQL とは何ですか?
これは MySQL の遅いクエリを指し、具体的には実行時間が long_query_time 値を超える SQL を指します。
一般的な MySQL バイナリ ログには、binlog、リレー ログ、relaylog、REDO ロールバック ログ、redolog、undolog などが含まれるとよく聞きます。スロー クエリの場合は、スロー クエリ ログ、slowlog もあります。これは、応答時間が MySQL のしきい値を超えたステートメントを記録するために使用されます。
スロー クエリという名前に惑わされず、スロー クエリ ログには選択ステートメントのみが記録されると考えてください。実際には、実行時間が設定されたしきい値を超える挿入、更新、その他の DML ステートメントも記録されます。 long_query_time までに。
# 查看慢SQL是否开启 show variables like "slow_query_log%"; # 查看慢查询设定的阈值 单位:秒 show variables like "long_query_time";
私たちが使用する AliSQL-X-Cluster (XDB) では、スロー クエリがデフォルトで有効になっており、long_query_time は 1 秒に設定されています。
2 クエリが遅いと失敗するのはなぜですか?
実際に遅い SQL には、多くの場合、大量の行スキャン、一時ファイルの並べ替え、または頻繁なディスク フラッシュが伴います。直接的な影響は、ディスク IO が増加し、通常の SQL が遅い SQL になり、大規模な実行がタイムアウトになることです。 。
昨年のダブル 11 の後、技術面で明らかになった問題に対応して、Cainiao CTO ラインは複数の特別なガバナンス プロジェクトを立ち上げました。CTO-D はそれぞれ 1 つをスポンサーとして受け入れました。私の大規模なチームが責任を負いました。遅い SQL ガバナンスの特別なプロジェクト。
1 アプリケーション内の遅い SQL の重大度を測定するにはどうすればよいですか?
マイクロ平均
sum(aone应用慢SQL执行次数) ----------------------- sum(aone应用SQL执行次数)
値が大きいほど影響は大きいと考えられますが、値が小さいほど影響は小さい可能性があります。 。
極端な場合は、アプリケーションで実行されるすべての SQL はすべて遅い SQL であり、値は 1 ですが、アプリケーションで実行されるすべての SQL は遅い SQL ではなく、値は 0 です。
しかし、このインジケーターによってもたらされる問題は、特に SQL の場合、識別が適切ではないことです。QPS は非常に高く、ほとんどの場合、SQL は遅いクエリではありません。時折遅い SQL が発生すると、圧倒されてしまいます。
別の質問ですが、時折現れる遅い SQL は本当に遅い SQL なのでしょうか?遅いクエリ ログには多くの SQL が記録されますが、実際には、他の遅い SQL、MySQL ディスク ジッター、オプティマイザの選択などの理由の影響を受ける可能性があるため、通常のクエリのパフォーマンスは明らかに遅い SQL ではなく、遅いSQLになります。
マクロ平均
sum(慢SQL 1执行次数) sum(慢SQL n执行次数) ----------------- + ------------------ sum(SQL 1执行次数) sum(SQL n执行次数) --------------------------------------- n
このアルゴリズムは、検出された遅い SQL が一定回数実行されるという事実に基づいており、これにより誤った遅い SQL の影響を軽減できます。
一部のアプリケーションの QPS が非常に低い場合、つまり 1 日に実行される SQL の回数が非常に少ない場合、誤った SQL が発生すると統計エラーが発生します。
実行数
sum(aone应用慢SQL执行次数) ----------------------- 7
過去 1 週間の 1 日あたりの遅い SQL 実行の平均数をカウントすると、マクロの平均化によって引き起こされる誤った SQL の問題を排除できます。
遅い SQL テンプレートの数
上記のディメンションにはすべて時間制限があります。遅い SQL の履歴処理を追跡するために、次のグローバル ディメンションも導入しました。遅い SQL テンプレートの数。
count(distinct(aone应用慢SQL模板) )
2 目標
コア アプリケーション: 遅い SQL をすべて解決する
3 CTO レポート
CTO-D に基づく上記の多次元指標の統計集計アプリケーションの加重平均に基づいて、ユニットを低位から高位までランク付けし、上位 3 つをハイライトし、毎週放送します。 三 なぜそれを行う必要があるのか この推測は私の経歴に関連している可能性があります。私は C/C のバックグラウンドを持っています。私は企業レベルのリモート マルチの設計と実装を担当していました。 -前の会社でアクティブなアーキテクチャを担当しており、MySQL については少し知っています。 また、利害とは関係ないかもしれませんが、私の小規模チームのビジネスはまだ始まったばかりで、遅い SQL がないので、さまざまなビジネスラインに挿入できます。 4 アクション サポート1 グループ MySQL プロトコル
インデックス プロトコルからの抜粋:[必須】3テーブル以上の参加は禁止です。結合する必要があるフィールドのデータ型は完全に一貫している必要があります。複数テーブルの相関をクエリする場合は、相関するフィールドにインデックスが必要であることを確認してください。 注: 二重テーブルを結合する場合でも、テーブルのインデックスと SQL のパフォーマンスに注意を払う必要があります。 [必須] varchar フィールドにインデックスを作成するときは、インデックスの長さを指定する必要があります。フィールド全体にインデックスを付ける必要はありません。インデックスの長さは、実際のテキストの区別に基づいて決定されます。 注: インデックスの長さと区別は矛盾しています。一般に、文字列型データの場合、長さ 20 のインデックスは 90% 以上の区別を持ちます。 count(distinct left(列名、インデックスの長さ))/count(*) の区別によって決定されます。 【必須】ページ内検索では左ぼかしや全ぼけは厳禁ですので、必要に応じて検索エンジンを使用して解決してください。 注意: インデックスファイルはB-Treeの左端のプレフィックスマッチング機能を持っており、左端の値が不定の場合、このインデックスは使用できません。 [推奨] 異なるフィールド型によって引き起こされる暗黙的な変換を防止し、インデックスの失敗を引き起こします。 [参考] インデックスを作成するときは、次のような極端な誤解を避けてください:1) インデックスは不足するよりも多すぎる方が良いです
认为一个查询就需要建一个索引。
2) 吝啬索引的创建
认为索引会消耗空间、严重拖慢更新和新增速度。
3) 抵制唯一索引
认为唯一索引一律需要在应用层通过“先查后插”方式解决。
2 DB变更标准
DDL需要控制变更速度,注意灰度和并发控制,变更发布需要在规定的变更发布窗口内。
1 数据分布不均匀
1)分库分表不合理
该业务数据分了8个库,每个库分了16张表,通过查看表空间可以看到数据几乎都分布在各个库的某2张表中。分库分表的策略有问题,另外过高预估了业务增量,这个持保留意见。
2)索引不合理
单表创建了idx_logistics_corp_id_special_id的联合索引,但即便这样区分度依然太低,根据实验及业务反馈(logistics_corp_id,transport_type_id)字段组合区分度非常高,且业务存在transport_type_id的单查场景。
2 索引问题
SELECT COUNT(0) AS `tmp_count` FROM( SELECT `table_holder`.`user_id`, `table_holder`.`sc_item_id`, SUM( CASE `table_holder`.`inventory_type` WHEN 1 THEN `table_holder`.`quantity` ELSE 0 END ) AS `saleable_quantity`, SUM( CASE `table_holder`.`inventory_type` WHEN 1 THEN `table_holder`.`lock_quantity` ELSE 0 END ) AS `saleable_lock_quantity`, SUM( CASE `table_holder`.`inventory_type` WHEN 401 THEN `table_holder`.`quantity` ELSE 0 END ) AS `transfer_on_way_quantity`, `table_holder`.`store_code`, MAX(`table_holder`.`gmt_modified`) AS `gmt_modified` FROM `table_holder` WHERE(`table_holder`.`is_deleted` = 0) AND(`table_holder`.`quantity` > 0) AND `table_holder`.`user_id` IN(3405569954) AND `table_holder`.`store_code` IN('ZJJHBHYTJJ0001', '...1000多个') GROUP BY `table_holder`.`user_id`, `table_holder`.`sc_item_id` ORDER BY `table_holder`.`user_id` ASC, `table_holder`.`sc_item_id` ASC ) `a`;
这个case对应的表有store_code索引,因此认为没问题,没办法优化了。实则通过执行计划,我们发现MySQL选择了全表扫描。针对该case实践发现,当范围查询的个数超过200个时,索引优化器将不再使用该字段索引。
最终经过拉取最近一段时间的相关查询SQL,结合业务的数据分布,我们发现采用(is_deleted,quantity)即可解决。
判断执行计划采用的索引长度:key_len的长度计算公式(>=5.6.4)
char(10)允许NULL = 10 * ( character set:utf8mb4=4,utf8=3,gbk=2,latin1=1) + 1(NULL) char(10)不允许NULL = 10 * ( character set:utf8mb4=4,utf8=3,gbk=2,latin1=1) varchr(10)允许NULL = 10 * ( character set:utf8mb4=4,utf8=3,gbk=2,latin1=1) + 1(NULL) + 2(变长字段) varchr(10)不允许NULL = 10 * ( character set:utf8mb4=4,utf8=3,gbk=2,latin1=1) + 2(变长字段) int允许NULL = 4 + 1(NULL) int不允许NULL = 4 timestamp允许NULL = 4 + 1(NULL) timestamp不允许NULL = 4 datatime允许NULL = 5 + 1(NULL) datatime不允许NULL = 5
3 被人影响
用到了索引却依然被爆出扫描2千万行:
索引字段区分度很高:
同时期常规SQL变为了慢查询:
DB数据盘访问情况:
排查共用物理机其他实例的情况,发现有个库在问题时间附近有很多慢sql需要排序,写临时文件刚好写入了2GB:
多个MySQL实例leader节点混合部署在同一台物理机,虽然通过docker隔离了CPU、MEM等资源,但目前还没有做到buffer io的隔离。
4 无法解决
通过汇总分析高频的查询并结合业务得出合适的索引往往能够解决日常遇到的慢查询,但这并不是万能的。
比如有可能索引越加越多,乃至成了这样:
有些场景,比如支持多个字段组合查询,又没有必填项,如果都要通过索引来支持显然是不合理的。
查询场景下,将区分度较高的字段设定为必填项是个好习惯;查询组合很多的情况下考虑走搜索支持性更好的存储或者搜索引擎。
随着各个CTO-D线的深入治理,各项指标较之前均有非常大的改观,比如核心应用完成慢查询清零,影响最大的一些慢SQL被得以解决,而我所在的团队排名也由最初的尾部top3进入到头部top3。
慢SQL治理进入日常化,通过每周固定推送慢SQL工单、owner接手处理、结单,基本形成了定期清零的习惯和氛围,慢SQL治理专项也被多次点名表扬。
遅ればせながらのまとめですが、今振り返ってみると、戦略策定、問題分析、解決のプロセスは、皆さんと共有する価値があると感じています。
関連する推奨事項: 「mysql チュートリアル 」
以上が役立つ情報をシェアしましょう! MySQL の遅いクエリの実践的な分析のまとめの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。