MySQL チューニング ツールの詳細な説明と実践的な演習の説明 ツールの紹介の説明 分析例の説明 2 つのバリアントの説明 列インデックスの説明 最も実践的なインデックスの使用法のまとめ: ツールの紹介を説明するEXPLAIN キーワードを使用して、オプティマイザーをシミュレートし、SQL ステートメントを実行して、クエリ ステートメントまたは構造のパフォーマンス ボトルネックを分析します。select ステートメントの前に explain キーワードを追加すると、MySQL はクエリにマークを設定します。クエリを実行すると、SQL ステートメントを実行する代わりに、実行プラン情報が返されます。 分析例を説明する公式ドキュメントを参照してください 例の表: `actor` が存在する場合はテーブルを削除します。 テーブル「アクター」を作成する( `id` int(11) NULLではない、 `name` varchar(45) デフォルト NULL, `update_time` 日時 デフォルト NULL、 主キー (`id`) )ENGINE=InnoDB デフォルト文字セット=utf8; `actor` (`id`, `name`, `update_time`) に VALUES (1,'a','2017-12-22) を挿入します 15:27:18')、(2、'b'、'2017-12-22 15:27:18')、(3、'c'、'2017-12-22 15:27:18'); `film` が存在する場合はテーブルを削除します。 テーブル「film」を作成する( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(10) デフォルト NULL, 主キー (`id`)、 キー `idx_name` (`name`) )ENGINE=InnoDB デフォルト文字セット=utf8; `film` (`id`, `name`) に VALUES (3,'film0'),(1,'film1'),(2,'film2') を挿入します。 `film_actor` が存在する場合はテーブルを削除します。 テーブル「film_actor」を作成します( `id` int(11) NULLではない、 `film_id` int(11) NULLではない、 `actor_id` int(11) NULLではない、 `remark` varchar(255) デフォルト NULL, 主キー (`id`)、 キー `idx_film_actor_id` (`film_id`,`actor_id`) )ENGINE=InnoDB デフォルト文字セット=utf8; `film_actor` (`id`, `film_id`, `actor_id`) に値 (1,1,1),(2,1,2),(3,2,1); を挿入します。 mysql> explain select * from actor; クエリ内のテーブルごとに 1 行が出力されます。結合を介して 2 つのテーブルがクエリされた場合は、2 行が出力されます。 2つのバリエーションを説明する1) explain 拡張: explain に基づいて追加のクエリ最適化情報を提供します。次に、show warnings コマンドを使用して最適化されたクエリ ステートメントを取得し、オプティマイザーによって最適化された内容を確認できます。追加のフィルター列もあり、これは半分の比率の値です。行数 * フィルター/100 は、explain の前のテーブルと結合される行数を推定できます (前のテーブルとは、explain の ID 値が現在のテーブルの ID 値よりも小さいテーブルを指します)。 2)パーティションの説明: explain と比較すると、パーティション フィールドが追加されています。クエリがパーティション テーブルに基づいている場合、クエリがアクセスするパーティションが表示されます。 MySQL 5.7 以降の新しいバージョンでは、追加情報をクエリするために extend を実行する必要はありません。MySQL 8.0 以降では explain Extended コマンドは廃止されており、explain のみを使用する必要があります。 説明の列次に各列の情報を説明します。 id列 select_type列 mysql> explain select * from film where id = 2; 2).primary: 複雑なクエリの最も外側の選択 mysql> set session optimizer_switch='derived_merge=off'; #MySQL 5.7 で派生テーブルのマージ最適化を無効にします。 2 explain select (select 1 from actor where id = 1) from (select * from film where id = 1) der; 上記の select_type によってクエリされたグラフについて説明します。 mysql> set session optimizer_switch='derived_merge=on'; #デフォルト設定を復元 5).union: ユニオン内の2番目以降の選択 mysql> explain select 1 union all select 1; 3.表の列 この列は、explain の行がどのテーブルにアクセスしているかを示します。 4. タイプ列(より重要) この列は、関連付けタイプまたはアクセス タイプを示します。これは、MySQL がテーブル内の行を検索する方法と、検索するデータ行レコードのおおよその範囲を決定するものです。 最良から最悪まで、 system > const > eq_ref > ref > range > index > ALL の順です。 mysql> explain select min(id) from film; MySQL の基盤となるインデックス データ構造は B+ ツリーであり、これは前回の記事でも説明しましたので、ここで説明しておきます。 B+ ツリーの下部にあるリーフ ノードは、左から右に向かって増加する順序で配置されます。これが左端プレフィックスの原則です。したがって、最小値を照会するには、検索せずに左端のインデックスから直接取得できます。これは非常に効率的です。 const、system : MySQL はクエリの一部を最適化し、定数に変換できます (show warnings の結果を参照)。主キーまたは一意キーに使用されるすべての列が定数と比較されると、テーブルには最大で 1 つの一致する行があり、一度読み取られるため、高速になります。 System は const の特殊なケースです。テーブル内に一致するタプルが 1 つしかない場合は system です。 mysql> explain 拡張 select * from (select * from film where id = 1) tmp; mysql> 警告を表示します。 eq_ref : 主キーまたは一意キー インデックスのすべての部分が結合して使用され、条件を満たすレコードが最大 1 つ返されます。これはおそらく const 以外では最適な結合タイプであり、単純な選択クエリにはこのタイプは含まれません。 film_actor から * を選択して、 film_actor.film_id = film.id で film_actor を結合します。 説明すると、上記の film_actor の film_id フィールドは結合インデックスなので、セカンダリ インデックスに基づいて別のテーブルに対応するクラスター化インデックス クエリは非常に高速です。 mysql> explain select * from film where name = 'film1'; 2. 関連テーブルをクエリします。idx_film_actor_id は film_id と actor_id の結合インデックスです。ここでは film_actor の左プレフィックスが使用されます。 mysql> film_id を film から選択し、 film_actor を film.id = film_actor.film_id に結合します。 range : 範囲スキャンは通常、in()、between、>、<、>= などの操作で使用されます。インデックスを使用して、指定された範囲の行を取得します。 mysql> explain select * from actor where id > 1; index : インデックス全体をスキャンすることで結果を取得できます。通常はセカンダリ インデックスをスキャンします。このスキャンは、高速検索のためにインデックス ツリーのルート ノードから開始されるのではなく、セカンダリ インデックスのリーフ ノードを直接トラバースしてスキャンします。速度は依然として比較的低速です。このクエリでは通常、カバー インデックスが使用されます。セカンダリ インデックスは一般に小さいため、通常は ALL よりも高速です。 mysql> explain select * from film; セカンダリ インデックスは現在のインデックスのデータのみを格納しますが、クラスター化インデックスはすべてのテーブル データを格納するため、セカンダリ インデックスがクラスター化インデックスよりも小さくなる理由を説明します。 5. possible_keys列 この列には、クエリが検索に使用する可能性のあるインデックスが表示されます。 6.キー列 この列には、テーブルへのアクセスを最適化するために MySQL が実際に使用するインデックスが表示されます。 7. key_len列 この列には、MySQL がインデックスで使用するバイト数が表示されます。この値を使用して、インデックス内のどの列が使用されているかを計算することができます。 たとえば、film_actor の結合インデックス idx_film_actor_id は、film_id と actor_id の 2 つの int 列で構成され、各 int は 4 バイトです。結果の key_len=4 から、クエリは最初の列である film_id 列を使用してインデックス検索を実行していることが推測できます。 mysql> film_actor から film_id = 2 を選択して * を説明します。 key_len の計算規則は次のとおりです。
8.参照列 この列には、キー列レコードのインデックスでテーブル内の値を見つけるために使用される列または定数が表示されます。一般的なものは次のとおりです: const (定数)、フィールド名 (例: film.id) 9.行 この列は、MySQL が読み取りおよび検出すると推定する行数です。これは結果セット内の行数ではないことに注意してください。 10追加列 この列には追加情報が表示されます。共通の重要な値は次のとおりです。 mysql> film_id = 1 の場合、film_actor から film_id を選択します。 2) where句の使用: where句を使用して結果を処理し、クエリされた列はインデックスでカバーされません。 mysql> explain select * from actor where name = 'a'; ここでは、アクター テーブルの名前にインデックスは追加されません。 実際はもっとたくさんあるので、一つ一つ紹介することはしません。興味がある方は、MySQLの公式ドキュメントを自分で確認してみてください。 インデックス作成のベストプラクティス 例の表: テーブル「従業員」を作成します( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(24) NOT NULL DEFAULT '' COMMENT '名前', `age` int(11) NOT NULL デフォルト '0' コメント '年齢', `position` varchar(20) NOT NULL DEFAULT '' COMMENT '位置', `hire_time` タイムスタンプ NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '求人開始時間', 主キー (`id`)、 キー `idx_name_age_position` (`name`,`age`,`position`) BTREE の使用 ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='従業員記録テーブル'; 従業員にINSERT INTO(名前、年齢、役職、雇用時間) VALUES('LiLei'、22、'マネージャー'、NOW()); 従業員にINSERT INTO(名前、年齢、役職、雇用時間) VALUES('HanMeimei'、23、'dev'、NOW()); 従業員にINSERT INTO(名前、年齢、役職、雇用時間) VALUES('Lucy'、23、'dev'、NOW()); 完全な価値一致 EXPLAIN SELECT * FROM employees WHERE name= 'LiLei'; EXPLAIN SELECT * FROM employees WHERE name = 'LiLei' AND age = 22; EXPLAIN SELECT * FROM employees WHERE name = 'LiLei' AND age = 22 AND position = 'manager'; 2.左端プレフィックス ルール<br /> 複数の列にインデックスが付けられる場合は、左端プレフィックス ルールに従う必要があります。これは、クエリがインデックスの左端の列から開始され、インデックス内の列をスキップしないことを意味します。 EXPLAIN SELECT * FROM employees WHERE name = 'Bill' and age = 31; EXPLAIN SELECT * FROM employees WHERE age = 30 AND position = 'dev'; EXPLAIN SELECT * FROM employees WHERE position = 'manager'; 上記には 3 つの結果セットがあります。最初の SQL ステートメントのみが左端プレフィックスの原則に従い、クエリにインデックスを使用します。他の 2 つの SQL ステートメントは左端プレフィックスの原則に違反しています。つまり、クエリは名前フィールドから開始されないため、インデックスは使用されず、インデックス エラーが発生します。 EXPLAIN SELECT * FROM employees WHERE name = 'LiLei'; EXPLAIN SELECT * FROM employees WHERE left(name,3) = 'LiLei'; 最初の SQL はインデックスを使用し、2 番目の SQL はインデックスの失敗を引き起こします。 EXPLAIN SELECT * FROM employees WHERE name = 'LiLei' AND age = 22 AND position = 'manager'; 2 EXPLAIN SELECT * FROM employees WHERE name = 'LiLei' AND age > 22 AND position = 'manager'; varchar(n): 中国語の文字を格納する場合、長さは 3n + 2 バイトです。varchar は可変長文字列であるため、追加の 2 バイトは文字列の長さを格納するために使用されます。 EXPLAIN SELECT name,age FROM employees WHERE name = 'LiLei' AND age = 23 AND position = 'manager'; 6. MySQLは、等しくない(!=または<>)、含まれない、存在しない場合、インデックスを使用できないため、テーブル全体のスキャンが発生します。 null、nullではない 一般的に、インデックスは使用できません EXPLAIN SELECT * FROM employees WHERE name is null ワイルドカード文字 ('$abc...') で始まる場合、MySQL インデックスが無効になり、完全なテーブル スキャン操作が発生します。質問: '% string %' インデックスが使用されない問題を解決するにはどうすればよいですか? EXPLAIN SELECT name,age,position FROM employees WHERE name like '%Lei%'; b) カバーインデックスが使用できない場合は、検索エンジンを使用する必要があるかもしれません。 EXPLAIN SELECT * FROM employees WHERE name = '1000'; EXPLAIN SELECT * FROM employees WHERE name = 1000; または は控えめに使用してください。クエリに使用した場合、MySQL はインデックスを使用しない場合があります。MySQL の内部オプティマイザは、検索率やテーブル サイズなどの複数の要因に基づいてインデックスを使用するかどうかを評価します。詳細については、「範囲クエリの最適化範囲クエリの最適化Age への単一値インデックスの追加」を参照してください。 ALTER TABLE `employees` ADD INDEX `idx_age` (`age`) USING BTREE; age >=1 かつ age <=2000 の employees から * を選択することを説明します。 インデックスを使用しない理由: MySQL の内部オプティマイザは、検索率やテーブル サイズなどの複数の要素に基づいて、インデックスを使用するかどうかを評価します。たとえば、この例では、単一のデータ クエリが大きすぎるため、オプティマイザーはインデックス最適化方法を使用しないことを選択する場合があります。大きな範囲は複数の小さな範囲に分割できます。 age >=1 かつ age <=1000 の employees から * を選択することを説明します。 年齢 >=1001 かつ年齢 <=2000 の従業員から * を選択します。 元のインデックス状態を復元する テーブル `employees` を変更し、インデックス `idx_age` を削除します。 インデックスの使用の概要: MySQLチューニングExplainツールの詳しい説明と実践的な演習についてはこれで終わりです。MySQLチューニングExplainツールの関連コンテンツについては、123WORDPRESS.COMの過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも123WORDPRESS.COMをよろしくお願いいたします。 以下もご興味があるかもしれません:
|
目次運河マクスウェルデータバスAlibaba Cloud のデータ転送サービス (DTS)運河ポジシ...
JavaScript スクリプトは HTML 内のどこにでも埋め込むことができますが、いつ呼び出され...
データベースの統計を行う場合、多くの場合、年、月、日に基づいてデータを収集し、echart を使用し...
最近、コンピューターの電源を入れたところ、Geek Academy が新規ユーザーに 1 か月の無料...
1. レジストリについて公式 Docker ハブは、パブリックイメージを管理するのに適した場所です。...
目次React アップロードファイル表示の進行状況デモフロントエンドにReactアプリケーションを素...
目次非同期を理解するフェッチ(url)レスポンス.json() asyncとawaitを組み合わせる...
MySQL 5.0 は、いくつかの「高度な機能」があるため定番となっています。これは、Windows...
1. 原因要件は 2 行を表示することであり、余分なテキストは 3 つのドットに置き換えられるため、...
目次1. カウンターの実装2. 成果を達成する1. カウンターの実装ページにカウンターを実装するだけ...
この記事では、VueでEchartsをインポートして線散布図を実現する具体的なコードを参考までに共有...
目次1. インストール2. プロジェクトにインポートしてマウントする3. 使用Vue2.x はコンポ...
VNC はリモート デスクトップ プロトコルです。 VNC を使用して Ubuntu 20.04 を...
昨年末、Thinkpad T450 のデュアルシステムの opensuse を Manjaro に置...
目次1. クエリの最適化1. MySQLチューニングの概要2. 小さなテーブルが大きなテーブルを動か...