記述した SQL クエリが遅いのはなぜですか?作成したインデックスが頻繁に失敗するのはなぜですか?この章では、MySQL のパフォーマンス低下の理由、インデックスの概要、インデックス作成の原則、explain コマンドの使用、explain 出力フィールドの意味について学習します。インデックスを理解し、インデックスを分析し、インデックスを使用してパフォーマンスの高い SQL ステートメントを記述するのに役立ちます。何を待っていますか?袖をまくって仕事に取り掛かりましょう! ケーススタディ まず、非リレーショナル データベースとリレーショナル データベースの違いを簡単に理解しましょう。 MongoDB は NoSQL の一種です。 NoSQL の正式名称は、SQL だけではなく、非リレーショナル データベースです。高いパフォーマンス、強力なスケーラビリティ、柔軟なモードが特徴で、特に同時実行性の高いシナリオで優れたパフォーマンスを発揮します。しかし、現時点ではリレーショナル データベースの補足に過ぎず、データの一貫性、データのセキュリティ、クエリの複雑さの点で、リレーショナル データベースとの間にはまだ一定のギャップがあります。 MySQL は、強力なクエリ機能、高いデータ一貫性、高いデータ セキュリティ、およびセカンダリ インデックスのサポートを備えたリレーショナル データベースです。ただし、特に 100 万を超えるデータの場合、そのパフォーマンスは MongoDB に比べてわずかに劣り、クエリが遅くなる可能性があります。このとき、クエリが遅い理由を分析する必要があります。一般的に、これはプログラマーの SQL の書き方が下手、キー インデックスが不足、またはインデックスが無効であることが原因で発生します。 同社のERPシステムデータベースは主にMongoDB(リレーショナルデータに最も近いNoSQL)で、次にRedisが続き、MySQLはごく一部を占めるに過ぎません。現在、Alibaba の Qimen システムと Jushita システムのおかげで、私たちは再び MySQL を使用しています。すでに注文数が100万件を超えていることを考えると、MySQLのパフォーマンス分析は特に重要です。 2つの簡単な例から始めましょう。各パラメータの機能と重要性については後ほど詳しく紹介します。 注: 必要な SQL は GitHub に配置されています。気に入ったら星をクリックしてください。 https://github.com/ITDragonBlog/daydayup/tree/master/MySQL/ シナリオ 1: 注文をインポートし、取引番号による注文の重複を回避する ビジネス ロジック: 注文をインポートする場合、注文の重複を避けるために、通常はトランザクション番号を使用してデータベースを照会し、注文が既に存在するかどうかを判断します。 最も基本的なSQL文 mysql> itdragon_order_list から * を選択し、 transaction_id = "81X97310V32236260E" を指定します。 +-------+---------------------+-------+-------+----------+--------------+------------+------------------+--------------+-------------+--------------+--------------+ | id | transaction_id | gross | net | stock_id | order_status | descript | finance_descript | create_type | order_level | input_user | input_date | +-------+---------------------+-------+-------+----------+--------------+------------+------------------+--------------+-------------+--------------+--------------+ | 10000 | 81X97310V32236260E | 6.6 | 6.13 | 1 | 10 | ok | ok | 自動 | 1 | itdragon | 2017-08-18 17:01:49 | +-------+---------------------+-------+-------+----------+--------------+------------+------------------+--------------+-------------+--------------+--------------+ mysql> explain select * from itdragon_order_list where transaction_id = "81X97310V32236260E"; +----+-------------+---------------------+------------+-------+---------------+-------+-------+---------+-----------+-------------+ | id | select_type | テーブル | パーティション | タイプ | 可能なキー | キー | キー長 | ref | 行 | フィルター済み | 追加 | +----+-------------+---------------------+------------+-------+---------------+-------+-------+---------+-----------+-------------+ | 1 | SIMPLE | itdragon_order_list | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 33.33 | where の使用 | +----+-------------+---------------------+------------+-------+---------------+-------+-------+---------+-----------+-------------+ クエリ自体には問題はなく、オフラインテスト環境にも問題はありません。ただし、関数が起動されると、クエリが遅くなるという問題が発生します。数億または数千万の注文の場合、完全なテーブルスキャンを使用しますか?ああ?鼻で笑う! SQL が完全なテーブルスキャンであることをどうやって知るのですか? explain コマンドを使用すると、MySQL が SQL ステートメントをどのように処理するかを明確に表示できます。印刷された内容は次のとおりです。
データベースにはレコードが 3 つしかないため、行とフィルタリングされた情報はあまり役に立ちません。ここで理解すべき重要な点は、type が ALL の場合、フル テーブル スキャンのパフォーマンスが最悪になるということです。データベースに数百万のデータがあると仮定すると、インデックスの助けがなければ非常に遅くなります。 予備的な最適化: transaction_id のインデックスを作成する mysql> itdragon_order_list (transaction_id) に一意のインデックス idx_order_transaID を作成します。 mysql> explain select * from itdragon_order_list where transaction_id = "81X97310V32236260E"; +----+-------------+-----------+---------+---------------------+---------------------+---------------------+-------+-------+--------+--------+ | id | select_type | テーブル | パーティション | タイプ | 可能なキー | キー | キー長 | ref | 行 | フィルター済み | 追加 | +----+-------------+-----------+---------+---------------------+---------------------+---------------------+-------+-------+--------+--------+ | 1 | SIMPLE | itdragon_order_list | NULL | const | idx_order_transaID | idx_order_transaID | 453 | const | 1 | 100 | NULL | +----+-------------+-----------+---------+---------------------+---------------------+---------------------+-------+-------+--------+--------+ ここで作成されるインデックスは通常のインデックスではなく、一意のインデックスです。 一意のインデックスによって印刷される型値は const です。一度インデックスすることで見つけられることを示します。値が見つかると、スキャンは終了し、クエリ結果が返されます。 通常のインデックスによって印刷される型値は ref です。一意でないインデックス スキャンを示します。値が見つかった場合は、インデックス ファイルが完全にスキャンされるまでスキャンを続行します。 (ここにはコードは掲載されていません) 再度最適化: カバーインデックス mysql> explain itdragon_order_list から transaction_id を選択します。ここで、transaction_id は "81X97310V32236260E" です。 +----+-------------+-----------+---------+-----------------------+---------------------+---------------------+-------+--------+--------+---------+ | id | select_type | テーブル | パーティション | タイプ | 可能なキー | キー | キー長 | ref | 行 | フィルター済み | 追加 | +----+-------------+-----------+---------+-----------------------+---------------------+---------------------+-------+--------+--------+---------+ | 1 | SIMPLE | itdragon_order_list | NULL | const | idx_order_transaID | idx_order_transaID | 453 | const | 1 | 100 | インデックスを使用 | +----+-------------+-----------+---------+-----------------------+---------------------+---------------------+-------+--------+--------+---------+ ここで、select * from は select transaction_id from に変更され、Extra には Using index と表示され、クエリがカバーリング インデックスを使用していることが示されます。これは非常に良いニュースであり、SQL ステートメントのパフォーマンスが非常に良好であることを示しています。プロンプトが「Using filesort (内部ソートを使用)」および「Using temporary (一時テーブルを使用)」の場合、SQL をすぐに最適化する必要があることを意味します。 ビジネス ロジックによれば、transaction_id を返すクエリ構造はビジネス ロジックの要件を満たすことができます。 シナリオ 2: 注文管理ページ、注文レベルと注文入力時間による並べ替え ビジネス ロジック: 注文レベルが高く、入力時間が長い注文を優先します。 最も基本的なSQL文 mysql> explain select * from itdragon_order_list order by order_level,input_date; +----+-------------+---------------------+------------+-------+---------------+-------+-------+------+------+----------------+ | id | select_type | テーブル | パーティション | タイプ | 可能なキー | キー | キー長 | ref | 行 | フィルター済み | 追加 | +----+-------------+---------------------+------------+-------+---------------+-------+-------+------+------+----------------+ | 1 | SIMPLE | itdragon_order_list | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 100 | filesort を使用 | +----+-------------+---------------------+------------+-------+---------------+-------+-------+------+------+----------------+ まず、完全なテーブルスキャンを使用することは合理的ではなく、filesort を使用するとパフォーマンスがさらに低下します。 MySQL 4.1 より前のバージョンでは、ファイルのソートに双方向ソート アルゴリズムが使用されていました。ディスクが 2 回スキャンされるため、I/O に時間がかかりすぎていました。その後、単一パスソートアルゴリズムに最適化されました。その本質はスペースと時間をトレードすることですが、データ量が大きすぎてバッファスペースが不足すると、複数の I/O が発生します。効果はさらに悪くなります。運用および保守の同僚に MySQL 構成の変更を依頼するのではなく、自分でインデックスを構築することをお勧めします。 予備的な最適化: order_level、input_date の複合インデックスを作成する mysql> itdragon_order_list (order_level,input_date) に idx_order_levelDate インデックスを作成します。 mysql> explain select * from itdragon_order_list order by order_level,input_date; +----+-------------+---------------------+------------+-------+---------------+-------+-------+------+------+----------------+ | id | select_type | テーブル | パーティション | タイプ | 可能なキー | キー | キー長 | ref | 行 | フィルター済み | 追加 | +----+-------------+---------------------+------------+-------+---------------+-------+-------+------+------+----------------+ | 1 | SIMPLE | itdragon_order_list | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 100 | filesort を使用 | +----+-------------+---------------------+------------+-------+---------------+-------+-------+------+------+----------------+ 複合インデックスを作成した後、インデックスを作成しなかった場合と同じであることに驚かれるかもしれません。 ? ?すべて完全なテーブルスキャンであり、すべてファイルのソートを使用します。インデックスは無効ですか?それともインデックスの作成に失敗しましたか?次の印刷物を見てみましょう mysql> explain select order_level,input_date from itdragon_order_list order by order_level,input_date; +----+-------------+---------------------+------------+--------+---------------+----------------------+--------+--------+----------+------------+-------------+ | id | select_type | テーブル | パーティション | タイプ | 可能なキー | キー | キー長 | ref | 行 | フィルター済み | 追加 | +----+-------------+---------------------+------------+--------+---------------+----------------------+--------+--------+----------+------------+-------------+ | 1 | SIMPLE | itdragon_order_list | NULL | インデックス | NULL | idx_order_levelDate | 68 | NULL | 3 | 100 | インデックスの使用 | +----+-------------+---------------------+------------+--------+---------------+----------------------+--------+--------+----------+------------+-------------+ select * from を select order_level,input_date from に変更した後。タイプは all から index にアップグレードされ、完全なインデックス スキャンを示します。Extra は、カバー インデックスが使用されていることも示します。しかし、それは正しくありません! ! ! !検索は高速化しましたが、返されるコンテンツには order_level と input_date の 2 つのフィールドしか含まれません。ビジネス パートナーはこれをどのように使用できますか?各フィールドに複合インデックスを作成する必要がありますか? MySQL はそんなに愚かではありません。force index を使用して、指定したインデックスを強制することができます。元の SQL ステートメントの force index(idx_order_levelDate) を変更するだけです。 mysql> explain select * from itdragon_order_list force index(idx_order_levelDate) order by order_level,input_date; +----+-------------+---------------------+------------+--------+---------------+-----------------------+-------+------+------+------+------+ | id | select_type | テーブル | パーティション | タイプ | 可能なキー | キー | キー長 | ref | 行 | フィルター済み | 追加 | +----+-------------+---------------------+------------+--------+---------------+-----------------------+-------+------+------+------+------+ | 1 | シンプル | itdragon_order_list | NULL | インデックス | NULL | idx_order_levelDate | 68 | NULL | 3 | 100 | NULL | +----+-------------+---------------------+------------+--------+---------------+-----------------------+-------+------+------+------+------+ 再度最適化: 注文レベルを本当に並べ替える必要があるでしょうか? 実際のところ、順序レベルをソートしても意味はほとんどなく、順序レベルにインデックスを追加しても意味はほとんどありません。 order_level に指定できる値は、low、medium、high、expedited のみであるためです。このように繰り返し均等に分散されたフィールドの場合、並べ替えやインデックス作成はほとんど役に立ちません。 まず order_level の値を修正してから input_date をソートできますか?クエリの効果が明らかな場合は、ビジネス上の同僚にこのクエリ方法を使用するように推奨できます。 mysql> explain select * from itdragon_order_list where order_level=3 order by input_date; +----+-------------+-----------+--------+----------------------+----------------------+-------+----------------------+-------+----------------------+ | id | select_type | テーブル | パーティション | タイプ | 可能なキー | キー | キー長 | ref | 行 | フィルター済み | 追加 | +----+-------------+-----------+--------+----------------------+----------------------+-------+----------------------+-------+----------------------+ | 1 | SIMPLE | itdragon_order_list | NULL | ref | idx_order_levelDate | idx_order_levelDate | 5 | const | 1 | 100 | インデックス条件の使用 | +----+-------------+-----------+--------+----------------------+----------------------+-------+----------------------+-------+----------------------+ 以前の SQL と比較すると、型がインデックスから ref (非一意インデックス スキャン) にアップグレードされます。インデックスの長さが 68 から 5 に変更され、1 つのインデックスのみが使用されていることが示されています。 ref も定数です。追加はインデックス条件の使用です。つまり、重要な値に基づいてインデックス スキャンまたはフル テーブル スキャンが自動的に選択されます。一般的に、パフォーマンスは以前の SQL よりもはるかに優れています。 上記の 2 つのケースは、簡単な紹介にすぎません。1 つ覚えておかなければならないのは、最適化はビジネス ロジックに基づいているということです。最適化の目的で、ビジネス ロジックを許可なく変更してはなりません。もちろん、変更できればベストです。 索引 はじめに 公式定義: インデックスは、MySQL がデータを効率的に取得するのに役立つデータ構造です。 インデックスがデータ構造である理由と、それがクエリ速度をどのように向上させるかについては、誰もが興味を持っているはずです。最も一般的に使用されるバイナリ ツリーを使用して、インデックスがどのように機能するかを分析してみましょう。 次の画像を見てください。 インデックスを作成する利点 1 データ取得速度の向上とデータベース IO コストの削減: インデックスを使用する利点は、テーブル内でクエリする必要があるレコードの数を減らすことで、検索を高速化できることです。 2 データのソートのコストを削減し、CPU 消費を削減します。インデックスの検索が高速なのは、データが最初にソートされるためです。フィールドをソートする必要がある場合、ソートのコストが大幅に削減されます。 インデックス作成のデメリット 1 ストレージ スペースを占有します。インデックスは、実際には主キーとインデックス フィールドを記録するテーブルであり、通常はインデックス ファイルの形式でディスクに保存されます。 2 テーブルの更新速度を低下させる: テーブル内のデータが変更されると、対応するインデックスも変更する必要があり、更新速度が低下します。そうしないと、インデックスによって指し示される物理データが正しくなくなる可能性があり、これもインデックス障害の原因の 1 つとなります。 3. 高品質のインデックスを作成するのは難しい: インデックスの作成は 1 日で完了する作業ではなく、また、変更されないものでもない。ユーザーの行動や特定のビジネスロジックに基づいて、最適なインデックスを頻繁に作成する必要があります。 インデックス分類 私たちがよく参照するインデックスは、通常、BTree (多方向検索ツリー) 構造で編成されたインデックスです。集計インデックス、セカンダリインデックス、複合インデックス、プレフィックスインデックス、ユニークインデックスなどがあり、これらを総称してインデックスと呼びます。もちろん、B+ツリー以外にもハッシュインデックスなども存在します。
実際の開発では、複合インデックスを使用することが推奨され、1 つのテーブルに作成されるインデックスの数は 5 を超えないようにしてください。 基本的な構文: 作成する: tableName (columnName...) に [一意の] インデックス indexName を作成します テーブル名を変更して、[一意の] インデックス [インデックス名] を (列名...) に追加します 消去: tableName のインデックス [indexName] を削除します チェック: テーブル名からインデックスを表示 どのような場合にインデックスを作成する必要がありますか? 1 主キー、一意のインデックス どのような状況ではインデックスを作成しないのですか? 1. テーブルのレコード数が少なすぎます。100 万未満のデータに対してはインデックスを作成する必要はありません。 パフォーマンス分析 MySQL自身のボトルネック MySQL 自体のパフォーマンスの問題には、ディスク容量不足、ディスク I/O の大きさ、サーバー ハードウェアのパフォーマンスの低さなどがあります。 explainはSQL文を分析します explain キーワードを使用すると、オプティマイザーをシミュレートして SQL クエリ ステートメントを実行し、MySQL が SQL ステートメントを処理する方法を理解できます。 +----+-------------+--------+-----------+-------+---------------+-----+-------+-------+------+------+------+ | id | select_type | テーブル | パーティション | タイプ | 可能なキー | キー | キー長 | ref | 行 | フィルター済み | 追加 | +----+-------------+--------+-----------+-------+---------------+-----+-------+-------+------+------+------+ id 選択クエリのシーケンス番号には、クエリ内で SQL ステートメントが実行される順序を示す繰り返し可能な番号のセットが含まれます。一般的には、次の 3 つの状況が考えられます。 選択タイプ 選択クエリのタイプは、主に通常のクエリ、結合クエリ、ネストされた複雑なクエリを区別するために使用されます。 パーティション テーブルで使用されるパーティションでは、10 年間の会社の注文量をカウントする場合、データを各年ごとに 1 つずつ、合計 10 個のパーティションに分割できます。これにより、クエリの効率が大幅に向上します。 タイプ これは非常に重要なパラメータ、接続タイプです。一般的なものは、all、index、range、ref、eq_ref、const、system、null、8 レベルです。 可能なキー クエリ ステートメントで使用される可能性のあるインデックス (1 つ以上または null) を表示します。これらのインデックスは、実際にはクエリによって使用されない可能性があります。参考用です。 鍵 クエリ ステートメントで実際に使用されるインデックスを表示します。 null の場合、インデックスは使用されないことを意味します。 キーの長さ インデックスで使用されるバイト数を表示します。key_len を使用して、クエリで使用されるインデックスの長さを計算できます。インデックスの長さが短いほど、精度を失わずに良くなります。 key_len によって表示される値は、実際に使用される長さではなく、インデックス フィールドの最も可能性の高い長さです。つまり、key_len はテーブル定義に基づいて計算され、テーブルから取得されるものではありません。 参照 インデックス列の値を検索するために使用されるインデックスの列または定数を示します。 行 テーブルの統計とインデックスの選択に基づいて、必要なレコードを見つけるために読み取る必要がある行数を大まかに推定します。値が大きいほど、状況は悪くなります。 余分な filesort の使用: MySQL がテーブル内のインデックスの順序でデータを読み取るのではなく、外部インデックスを使用してデータをソートすることを示します。インデックスを使用して実行できない MySQL でのソート操作は、「ファイル ソート」と呼ばれます。このような場合は、すぐに SQL を最適化する必要があります。 フィルター 行列の値と一緒に使用されるパーセンテージ値は、クエリ実行プラン (QEP) 内の前のテーブルの結果セットを推定し、結合操作の反復回数を決定できます。小さなテーブルが大きなテーブルを駆動し、結合の数を減らします。 explain のパラメータ導入により、次のことを知ることができます。 パフォーマンス低下の理由 プログラマーの視点から サーバーの観点から 要約する 1 インデックスは、ソートされ、高速に検索できるデータ構造です。その目的は、クエリの効率を向上させることです。 これで、MySQL インデックスの最適化分析は終了です。何か間違っている点が見つかった場合は、指摘してください。良いと思ったらクリックしておすすめできます。 以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。 以下もご興味があるかもしれません:
|
>>: コンパイル/サーバーなしでブラウザにCommonJSモジュールを実装する
<br />今は情報爆発の時代であるだけでなく、サービス爆発の時代でもあります。それはす...
マイクロソフトIIS (Internet Information Server) は、Microso...
CentOS7 システムを使用するのは今回が初めてで、ネットワーク構成を行う際に多くの問題が発生し...
時刻、文字列、タイムスタンプ間の変換は、日常生活でよく使用されます。よく使用されますが、私は使用する...
詳細な手順は次のとおりです。 1. ディスク容量を確認します。 [root@localhost バッ...
目次1. はじめに2. 本文2.1 Where句の位置2.2 演算子2.3 NULL値1. はじめに...
序文Crond は Linux のスケジュール実行ツール (Windows のスケジュールされたタス...
目次Linux の MariaDB データベースについて1. データベースとは何ですか? 2. デー...
Kubernetes チームは最近、最新バージョンの Docker でサポートされている機能を廃止...
初めての投稿ですので、間違いや問題点などありましたら、コメント欄で指摘していただければ、今後改善させ...
W3C では、さまざまなタグの規定を設定するだけでなく、Web ページの作成者が実際に W3C 規...
ヒントこのプラグインは https プロトコルでのみアクセスできます。http プロトコルはうまく機...
目次1. トラバーサルクラス1. 各2. 地図3. すべての4. いくつか5. フィルター6. 減ら...
目次1. docker-maven-pluginの紹介2. 環境とソフトウェアの準備3. デモ例3....
成果を達成する実装コードhtml <div クラス = 'ラッパー'> ...