MySQLが遅くなるのは、クエリの構築が不十分だったり、インデックスがなかったり、コンフィギュレーションが合わなかったり、リソースが不足しているときだ。 mysqlのパフォーマンスを最適化する を効果的に行います。具体的な診断ステップと実践的な解決策を紹介し、真の原因を突き止め、的を射た方法でボトルネックを解消できるようにします。
中心点
- クエリ そして指標を正しく設計する
- 構成 仕事量に合わせる
- リソース モニターとスケール
- モニタリング スローログを使用する
- メンテナンス および計画の更新
MySQLが遅い理由:原因を認識する
私はまず、クエリーの問題、欠落の問題を区別する。 インデックス設定エラーとリソース制限。非効率的な SELECT、乱暴な JOIN チェーン、SELECT * はデータ量を増やし、ランタイムを延長する。適切なインデックスがない場合、MySQL は大きなテーブルをスキャンしなければならず、トラフィックが多い場合は著しく遅くなります。innodb_buffer_pool_size が小さすぎると、システムは常にディスクから読み込むことになり、待ち時間が長くなります。さらに、古いバージョンや新しいリリースの有効化されたクエリキャッシュは パフォーマンス 不必要だ。
素早くチェック症状と測定値
私はまず、遅いクエリーログ、パフォーマンススキーマ、システムメトリックスから始めて、最大の問題を特定します。 ブレーキ を見ることができる。CPUが高く、I/Oが低い場合は、クエリやインデックスの欠落を示すことが多い。IOPSが多くCPUが低い場合は、バッファ・プールのサイズが小さすぎるか、データが断片化されていることを示しています。Handler_read_rnd_nextの値が高い場合は、テーブルのフルスキャンが頻繁に行われていることを示している。負荷のピーク時にレイテンシが増加する場合、スレッド、接続、ストレージのボトルネックが明らかになります。
ロック、トランザクション、分離を理解する
完璧なインデックスであっても、セッションが互いにブロックし合っていれば、あまり役に立たないからだ。長いトランザクションはアンドゥ・ログに古いバージョンを残し、バッファ・プールの圧力を高め、そして ロックの待ち時間.デッドロック(SHOW ENGINE INNODB STATUS)、待ち時間、パフォーマンス・スキーマの影響を受けるオブジェクト(data_locks、data_lock_wait)をチェックします。典型的なパターンは、JOINカラムにインデックスがない(広範囲ロック)、複数のテーブルにまたがる一貫性のないアクセス・シーケンス、LIMITなしの大きなUPDATE/DELETEバッチなどです。
READ COMMITTEDはギャップ・ロックを減らしてホットスポットを緩和し、REPEATABLE READはより安全なスナップショットを提供します。メンテナンス作業では、グループ・コミットが有効になりロックが短くなるように、より小さなトランザクション・パッケージを使用します。可能であれば、バックグラウンドジョブにはNOWAITかSKIP LOCKEDを使い、キューにはまらないようにしている。ロック待ち時間(innodb_lock_wait_timeout)を意図的に設定して、アプリケーションがエラーを素早く認識し、きれいに再試行できるようにしている。
EXPLAINを正しく読み、正しく使う
EXPLAINを使用すると、MySQLがどのようにクエリを実行し、意味のある アクセスパス が存在する。タイプ(例えばALLかrefか)、キー、行、そしてUsing filesortやUsing temporaryのような追加要素に注意を払う。インデックスのない行はすべてチューニングの候補となる。次に、WHERE、JOIN、ORDERの条件をチェックし、適切なインデックスを作成します。以下の小さなマトリックスは、典型的なシグナルをより迅速に分類し、対策を導き出すのに役立つ。
| 信号 | 推定原因 | ツール/チェック | 速いアクション |
|---|---|---|---|
| タイプ = ALL | フルテーブルスキャン | EXPLAIN、スローログ | WHERE/JOINカラムのインデックス |
| ファイルソートの使用 | インデックスに一致しないソート | EXPLAIN エキストラ | ORDER BY orderのインデックス |
| 一時的な使用 | GROUP BYの中間テーブル | EXPLAIN エキストラ | コンバインド・インデックス、シンプル・アグリゲート |
| 高い行数 | フィルターが遅すぎる/ぼやけすぎている | EXPLAIN行 | より選択的なWHEREとインデックスの順序 |
| ハンドラー_read_rnd_next high | 多くの連続スキャン | ステータス表示 | インデックスの追加、クエリの書き換え |
計画を安定させる統計、ヒストグラム、ヒント
統計情報を最新に保ち、選択性を現実的にモデル化することで、良い計画を確実にします。ANALYZE TABLEはInnoDBの統計情報を更新します。大きく偏ったデータに対しては、オプティマイザがカーディナリティをより良く推定できるように、重要な列のヒストグラムを作成します。計画がインデックス間でジャンプする場合、永続的な統計情報をチェックし、ヒストグラムを特別に更新し、有害であれば削除します。例外的なケースでは、オプティマイザのヒント(例えば、USE INDEX、JOIN_ORDER)を設定したり、リスクを負わずに効果をテストするために、最初にインデックスを不可視にします。EXPLAIN ANALYZEを使用して、演算子レベルでの実際の実行時間を確認し、誤った判断を発見します。
クエリーの加速:具体的なステップ
まず、データ量を減らす:必要なカラムのみ、明確なWHEREフィルター、意味のあるもの、など。 リミット.そして、ネストしたサブクエリを単純化するか、適切なインデックスを持つJOINに置き換える。可能であれば、WHEREのカラムの高価な関数を事前に計算されたフィールドに移動させる。頻度の高いレポートは、アプリケーション・レベルでキャッシュすることで、より小さなクエリに分割する。メソッドのコンパクトな紹介については、以下を参照されたい。 MySQL戦略これは、まさにそのようなステップを構造的に束ねたものである。
ORMとアプリケーションレイヤーの練習
典型的なORMの罠を取り除く:グループ化されたスローログエントリーを介してN+1クエリーを認識し、明示的なJOINやバッチロードファンクションに置き換える。SELECT *を無駄のないプロジェクションに置き換えます。オフセットが大きくなればなるほど遅くなる大きなオフセットの代わりに、シークメソッドとしてページネーションを構築します(WHERE id > last_id ORDER BY id LIMIT n)。プリペアドステートメントを使用し、クエリプランをキャッシュすることで、パーサーの負担を減らす。接続プールは、何千ものアイドル接続でデータベースを溢れさせたり、アプリをキューに入れたりしないように設定する。
インデックス:作成、チェック、片付け
私は、WHERE、JOIN、ORDER BYに登場するカラムに特別にインデックスを設定し、次の点に注意している。 シーケンス.私は、最も頻度の高いクエリの選択性と利用計画に従って複合インデックスを選択する。インデックスを追加するたびに書き込み処理が遅くなるので、インデックスの過剰作成は避ける。使用統計から未使用のインデックスを特定し、テスト後に削除します。TEXTやJSONフィールドについては、バージョンがサポートしていれば、パーシャルインデックスやファンクションインデックスをチェックする。
スキーマ設計、プライマリ・キー、保存形式
私はすでにデータ・モデルのパフォーマンスを考えています:InnoDBはプライマリ・キー(クラスタ化インデックス)に従ってデータを物理的に格納します。単調キー(AUTO_INCREMENT、タイムシェア付きULID)はページ分割を避け、断片化を減らす。純粋なUUIDv4キーはBツリー全体にランダム性をばらまき、キャッシュのローカリティを悪化させる。UUIDが必要な場合は、ソート可能なコンポーネントを持つバリアントを使うか、よりコンパクトなインデックスのためにバイナリ形式(UUID_TO_BIN)で保存する。RAMとI/Oを節約するために、小さくて適切なデータ型(INT対BIGINT、DECIMAL対FLOAT)を選ぶ。ユニコードでは、実用的な照合順序(例えば_0900_ai_ci)でutf8mb4を選択し、大文字小文字を区別しない比較が必要かどうかをチェックする。
行のフォーマット(DYNAMIC)は、ページ外ストレージを効率的に利用するのに役立つ。必要であれば、非常に広い行をスリムなホットテーブルとコールド詳細テーブルに分割する。JSONの場合は、構造化されていない検索ロジックをすべてのクエリで繰り返すのではなく、生成されたカラム(バーチャル/パーシステッド)を設定し、それらにインデックスを作成する。圧縮は、CPUが使用可能であれば、非常に大きなテーブルで役立ちます。私は、解凍コストとターゲットハードウェアでのI/O節約のバランスを測定します。
設定をカスタマイズ:InnoDB など
私は通常、innodb_buffer_pool_sizeを50-70の%のRAMに設定し、頻繁な データ をメモリに保存する。innodb_log_file_sizeを書き込み負荷とリカバリーのターゲットに合わせて調整する。innodb_flush_log_at_trx_commitを使って、リスク許容度に応じて、耐久性と待ち時間をコントロールする。スレッドと接続のパラメーターを調整して、キューがないようにする。現在のバージョンでは、古いクエリキャッシュを一貫して無効にしている。
書き込み負荷をより効率的に
INSERTのたびに自動コミットするのではなく、制御されたトランザクションに書き込みをバンドルしている。これによりfsyncを減らし、グループ・コミットを可能にしている。バルク・データについては、バルク・メソッド(複数のVALUESリストまたはLOAD DATA)を使用し、完全性が許せば外部キー・チェックとセカンダリ・インデックスを一時的にオーバーライドし、それらを再構築します。ROWフォーマットはレプリケーションのためにより安定し、sync_binlogは耐久性を制御します。innodb_flush_log_at_trx_commitと組み合わせることで、セキュリティとスループットの妥協点を見つけることができます。また、innodb_io_capacity(_max)をチェックして、フラッシュスレッドがI/Oを詰まらせたり、遅くしたりしないようにしている。
リソースとハードウェア:いつ規模を拡大するか?
新しいチューニングを加える前に、まずソフトのチューニングが終わっているかどうかをチェックする。 ハードウェア を買う。最適化が十分でない場合は、RAMを拡張し、SSD/NVMeストレージを使用し、並列処理のためにCPUコアを増やします。適切な調整ネジを選ぶために、ネットワークのレイテンシーとストレージのスループットを別々に測定します。高負荷のピークには、レプリカによる水平リリーフを計画する。これにより、負荷の高いシナリオの概要を把握できる。 高荷重用ガイド私はこれをチェックリストとして使っている。
クラウドでの運用:IOPS、クレジット、制限
私はクラウドの仕様を考慮に入れている。ネットワークバウンド・ブロックストレージはIOPSとスループットに制限があり、それをチェックして予約している。CPUクレジットを持つインスタンスタイプは、継続的な負荷がかかるとスロットルする。ボリュームのバースト・バッファは短期的にしか隠せない。予測可能なパフォーマンスには、プロビジョニングされたIOPS/スループットが必須だ。レイテンシ・ジッターを測定し、チェックポイントやバックアップがレッドエリアに入らないようにヘッドルームを計画する。オペレーティング・システム側では、ファイル・システムとスケジューラの設定、NUMAと透過的な巨大ページをチェックして、InnoDBが安定して動作するようにします。
恒久的なモニタリングの確立
私はパフォーマンス・スキーマ、システム関連のメトリクス、そして一元化された ダッシュボード トレンドのために私は低速クエリログを継続的に実行し、似たようなクエリをまとめています。レイテンシー、アボート、接続数、I/Oピークのアラームが問題を早期に報告します。履歴曲線は、変更が本当にパフォーマンスを向上させたかどうかを示してくれる。モニタリングなしでは、チューニングはスナップショットのままであり、新しいコードによってその効果を失う。
テスト、ロールアウト、回帰保護
私は決して "やみくもに "変更を実施することはない。まずベースラインを測定し、それからセットスクリューを個別に調整し、再度測定する。実際のシナリオでは、本番データのスナップショット(匿名化)と典型的なワークロードをマッピングするロードジェネレーターを使用する。クエリーの再生は、プランとレイテンシーへの影響を確認するのに役立つ。ロールアウト時には、問題が発生した場合にすぐに切り替えられるように、カナリアと機能フラグを頼りにしている。スキーマの変更については、オンラインプロシージャを使用し(試行錯誤を重ねたツールなど)、レプリケーションの遅延を監視し、明確なロールバックプランを立てています。プライマリとレプリカ間のチェックサムによって、データの一貫性が保たれるようにしている。
パーティショニングとキャッシュを正しく使用する
私はスキャンやメンテナンスを容易にするために、非常に大きなテーブルを日付やキーでパーティション分けしている。 やわらげる.ウォームデータはより小さなパーティションに、コールドデータはアクセス頻度の低いメモリ領域に保存する。アプリケーションレベルでは、インメモリーキャッシュを使ってクエリーの繰り返しを減らす。頻繁に行われる集計は、マテリアライズド・ビューとして保存するか、価値があればテーブルを事前に計算しておく。私は、高負荷に対する戦略の構造化された概要を、日々の運用で実証されたパターンで補足する。
成長のための建築的決断
レポートやAPIなど、大量のアクセスを必要とするものについては、リードスレーブによるレプリケーションで書き込みアクセスを緩和している。 読む.顧客グループや地域ごとのシャーディングは、グローバルなアプリケーションに便利です。MySQLをキューとして乱用する代わりに、バッチジョブを非同期ワーカーに移行する。異なるアクセスパターンを持つ重要なテーブルを分離し、ホットスポットを避ける。極端な要件に対しては、特定のデータ型に特化したストレージ・フォームをチェックする。
レプリケーションの詳細な調整
GTIDを使用し、ビンログサイズとフラッシュストラテジーを適切に調整し、レプリカの並列化を有効にすることで、レプリケーションの安定性を保っています。 ワークロードが独立したトランザクションを許容する限り、replica_parallel_workers(またはアプライアスレッド)を増やします。半同期レプリケーションはデータロスを減らすことができますが、レイテンシが増加します。そうしないと、読み取りワークロードは古いデータを見ることになるので、私はレプリカの遅延を監視しています。「書き込みを読み取る」ためには、書き込みセッションを一時的にプライマリにルーティングするか、アプリのロジックで遅延ウィンドウを使用します。Binlogとレプリカが遅れないように、長いDDLを計画します。
メンテナンスとアップデート
私は、MySQLのバージョンとプラグインを常に最新の状態にしている。 エラー そして古いブレーキを避ける。統計とバックアップを効率化するため、明確化した後に未使用のテーブルを削除する。アーカイブやロールアップは、スキャンを高速に保つために、関連する履歴だけを残す。選択したテーブルに対して定期的にANALYZE/OPTIMIZEを行うことで、統計と断片化に目を光らせる。その他の実用的なヒントは、以下のコンパクトなファイルにまとめてある。 SQLのヒント 日常生活のために。
簡単にまとめると
私はクエリーを作ることでボトルネックを見つける、 インデックスコンフィギュレーションとリソースを一緒に。EXPLAIN、低速ログ、モニタリングは、勘ではなく、信頼できるデータを提供してくれる。SELECT *の削除、結合インデックスの設定、バッファプールの拡大といった小さなステップで、すぐに顕著な効果が得られます。そして、ハードウェアやアーキテクチャの変更が必要かどうかを判断する。このように進めば、MySQL データベースを高速化し、円滑に稼動させることができます。


