MySQL 8 の隠しインデックス、降順インデックス、関数インデックス1. 隠しインデックス1. 隠しインデックスの概要
以前のバージョンの MySQL では、インデックスは明示的にしか削除できませんでした。間違ったインデックスが削除されたことが判明した場合、削除されたインデックスはインデックスを作成することによってのみ追加することができました。データベース内のデータ量が非常に多い場合やテーブルが大きい場合、この操作のコストは非常に高くなりました。 MySQL 8.0 では、このインデックスを非表示インデックスとして設定するだけで、クエリ オプティマイザはこのインデックスを使用しなくなります。ただし、このインデックスは引き続き MySQL のバックグラウンドで維持される必要があります。このインデックスを非表示インデックスとして設定してもシステムに影響がないことが確認できたら、インデックスを完全に削除します。これはソフト削除機能です。 グレースケールリリースとは、インデックスを作成するときに、まずインデックスを非表示のインデックスとして設定し、次にクエリオプティマイザスイッチを変更して、非表示のインデックスをクエリオプティマイザに表示できるようにすることです。次に、explain を通じてインデックスをテストし、インデックスが有効であることを確認します。インデックスが特定のクエリで使用できる場合は、グレースケールリリースの効果を実現するために、表示可能なインデックスとして設定できます。 2. インデックス操作を非表示にする(1)MySQLにログインし、testdbデータベースを作成し、データベース内にテストテーブルt1を作成します。 mysql> データベースが存在しない場合は testdb を作成します。 クエリは正常、1 行が影響を受けました (0.58 秒) mysql> testdb を使用します。 データベースが変更されました mysql> テーブルが存在しない場合は作成します t1(i int, j int); クエリは正常、影響を受けた行は 0 行 (0.05 秒) (2)以下に示すようにフィールドiにインデックスを作成します。 mysql> t1(i) にインデックス i_idx を作成します。 クエリは正常、影響を受けた行は 0 行 (0.34 秒) レコード: 0 重複: 0 警告: 0 (3)フィールドjに隠しインデックスを作成します。隠しインデックスを作成するには、次に示すように、インデックスを作成するステートメントの後にinvisibleキーワードを追加するだけです。 mysql> t1(j) に非表示のインデックス j_idx を作成します。 クエリは正常、影響を受けた行は 0 行 (0.01 秒) レコード: 0 重複: 0 警告: 0 (4)以下に示すように、テーブルt1のインデックスステータスを確認します。 mysql> t1 \G からインデックスを表示 ************************** 1. 行 **************************** 表: t1 非ユニーク: 1 キー名: i_idx インデックス内のシーケンス: 1 列名: i 照合: A カーディナリティ: 0 サブパート: NULL パック: NULL ヌル: はい インデックスタイプ: BTREE コメント: インデックスコメント: 表示: はい 式: NULL ************************** 2. 行 **************************** 表: t1 非ユニーク: 1 キー名: j_idx インデックス内のシーケンス: 1 列名: j 照合: A カーディナリティ: 0 サブパート: NULL パック: NULL ヌル: はい インデックスタイプ: BTREE コメント: インデックスコメント: 表示: いいえ 式: NULL セットに2行(0.02秒) t1 テーブルには 2 つのインデックスがあり、1 つは i_idx、もう 1 つは j_idx であることがわかります。i_idx の Visible 属性は YES であり、このインデックスが表示されていることを示します。j_idx の Visibles 属性は NO であり、このインデックスが非表示であることを示します。 (5)クエリオプティマイザがこれら2つのインデックスをどのように使用するかを確認します。 まず、以下に示すようにフィールド i を使用してクエリを実行します。 mysql> t1 から select * を実行すると i = 1 \G になる ************************** 1. 行 **************************** id: 1 選択タイプ: シンプル テーブル: t1 パーティション: NULL タイプ: ref 可能なキー: i_idx キー: i_idx キーの長さ: 5 参照: 定数 行数: 1 フィルター: 100.00 追加: NULL セットに 1 行、警告 1 回 (0.02 秒) ご覧のとおり、クエリ オプティマイザーは最適化に i フィールドのインデックスを使用します。 mysql> t1 から select * を実行すると j = 1 \G になる ************************** 1. 行 **************************** id: 1 選択タイプ: シンプル テーブル: t1 パーティション: NULL タイプ: すべて 可能なキー: NULL キー: NULL キー長さ: NULL 参照: NULL 行数: 1 フィルター: 100.00 追加: where の使用 セットに 1 行、警告 1 件 (0.00 秒) クエリ オプティマイザーは、j フィールドの隠しインデックスを使用せず、完全なテーブル スキャンを使用してデータをクエリしていることがわかります。 (6)隠しインデックスをオプティマイザに表示させる MySQL 8.x では、オプティマイザのスイッチを介して設定をオンにして、非表示のインデックスをクエリ オプティマイザに表示できる新しいテスト メソッドが提供されています。 mysql> @@optimizer_switch \G を選択します ************************** 1. 行 **************************** @@optimizer_switch: index_merge=on、index_merge_union=on、index_merge_sort_union=on、index_merge_intersection=on、engine_condition_pushdown=on、index_condition_pushdown=on、mrr=on、mrr_cost_based=on、block_nested_loop=on、batched_key_access=off、materialization=on、semijoin=on、loosescan=on、firstmatch=on、duplicateweedout=on、subquery_materialization_cost_based=on、use_index_extensions=on、condition_fanout_filter=on、derived_merge=on、use_invisible_indexes=off、skip_scan=on、hash_join=on セット内の 1 行 (0.00 秒) ここでは、次のプロパティ値を確認できます。 非表示インデックスの使用=オフ オプティマイザーが非表示のインデックスを使用するかどうかを示します。デフォルトはオフです。 mysql> セッション optimizer_switch="use_invisible_indexes=on" を設定します。 クエリは正常、影響を受けた行は 0 行 (0.00 秒) 次に、クエリオプティマイザースイッチの設定を再度確認します。 mysql> @@optimizer_switch \G を選択します ************************** 1. 行 **************************** @@optimizer_switch: index_merge=on、index_merge_union=on、index_merge_sort_union=on、index_merge_intersection=on、engine_condition_pushdown=on、index_condition_pushdown=on、mrr=on、mrr_cost_based=on、block_nested_loop=on、batched_key_access=off、materialization=on、semijoin=on、loosescan=on、firstmatch=on、duplicateweedout=on、subquery_materialization_cost_based=on、use_index_extensions=on、condition_fanout_filter=on、derived_merge=on、use_invisible_indexes=on、skip_scan=on、hash_join=on セット内の 1 行 (0.00 秒) この時点で、use_invisible_indexes=on となっていることがわかります。これは、非表示のインデックスがクエリ オプティマイザーに表示されることを意味します。 以下に示すように、t1 テーブルの j フィールドを使用してデータを再度分析してみましょう。 mysql> t1 から select * を実行すると j = 1 \G になる ************************** 1. 行 **************************** id: 1 選択タイプ: シンプル テーブル: t1 パーティション: NULL タイプ: ref 可能なキー: j_idx キー: j_idx キーの長さ: 5 参照: 定数 行数: 1 フィルター: 100.00 追加: NULL セットに 1 行、警告 1 件 (0.00 秒) クエリ オプティマイザーは、j フィールドの隠しインデックスを使用してクエリを最適化していることがわかります。 (7)インデックスの可視性を設定する 以下に示すように、フィールド j の非表示インデックスを表示に設定します。 mysql> テーブル t1 を変更し、インデックス j_idx を可視に変更します。 クエリは正常、影響を受けた行は 0 行 (0.01 秒) レコード: 0 重複: 0 警告: 0 以下に示すように、フィールド j のインデックスを非表示に設定します。 mysql> テーブル t1 を変更し、インデックス j_idx を非表示にします。 クエリは正常、影響を受けた行は 0 行 (0.01 秒) レコード: 0 重複: 0 警告: 0 (8)MySQLの主キーは非表示のインデックスとして設定できない MySQL では、主キーを非表示に設定できないことに注意してください。 mysql> テーブル t2 を作成します (i int not null); クエリは正常、影響を受けた行は 0 行 (0.01 秒) 次に、次のようにt2テーブルに非表示の主キーを作成します。 mysql> テーブル t2 を変更し、主キー pk_t2(i) を非表示に追加します。 エラー 3522 (HY000): 主キー インデックスを非表示にすることはできません この時点で SQL ステートメントがエラーを報告しており、主キーを非表示のインデックスとして設定できないことがわかります。 2. 降順インデックス1. 降順指数の概要
2. 降順インデックス操作(1)MySQL 5.7でサポートされている構文 まず、MySQL 5.7 でテスト データベース testdb を作成し、次に示すように、データベース testdb にテスト テーブル t2 を作成します。 mysql> データベースが存在しない場合は testdb を作成します。 クエリは正常、影響を受けた行は 0 行 (0.71 秒) mysql> testdb を使用します。 データベースが変更されました mysql> テーブルが存在しない場合は作成します t2(c1 int, c2 int, index idx1(c1 asc, c2 desc)); クエリは正常、影響を受けた行は 0 行 (0.71 秒) t2 テーブルに idx1 という名前のインデックスが作成されます。インデックスの c1 フィールドは昇順でソートされ、c2 フィールドは降順でソートされます。 次に、以下に示すように、t2テーブルの作成情報を表示します。 mysql> show テーブル t2 \G を作成します ************************** 1. 行 **************************** 表: t2 テーブルの作成: CREATE TABLE `t2` ( `c1` int(11) デフォルト NULL, `c2` int(11) デフォルト NULL, キー `idx1` (`c1`,`c2`) ) エンジン=InnoDB デフォルト文字セット=utf8mb4 セット内の1行(0.16秒) MySQLバージョン5.7のテーブル作成情報では、フィールドc1とc2のソート情報がなく、デフォルトは昇順になっていることがわかります。 (2)MySQL 8.0でサポートされている構文 MySQL 8.xでは、次のようにt2テーブルを作成します。 mysql> テーブルが存在しない場合は作成します t2(c1 int, c2 int, index idx1(c1 asc, c2 desc)); クエリは正常、影響を受けた行は 0 行、警告は 1 件 (0.00 秒) 次に、以下に示すように、t2テーブルの作成情報を表示します。 mysql> show テーブル t2 \G を作成します ************************** 1. 行 **************************** 表: t2 テーブルの作成: CREATE TABLE `t2` ( `c1` int(11) デフォルト NULL, `c2` int(11) デフォルト NULL, キー `idx1` (`c1`,`c2` DESC) ) エンジン=InnoDB デフォルト文字セット=utf8mb4 照合=utf8mb4_0900_ai_ci セット内の 1 行 (0.00 秒) ご覧のとおり、MySQL 8.x では、作成されたインデックスにフィールドのソート情報が含まれています。 (3)MySQL 5.7のクエリオプティマイザによるインデックスの使用 まず、以下に示すようにテーブル t2 にデータを挿入します。 mysql> t2(c1, c2) に値 (1, 100)、(2, 200)、(3, 150)、(4, 50) を挿入します。 クエリは正常、4 行が影響を受けました (0.19 秒) 記録: 4 重複: 0 警告: 0 次に、以下に示すように t2 テーブル内のデータをクエリします。 mysql> t2 から * を選択します。 +------+------+ | c1 | c2 | +------+------+ | 1 | 100 | | 2 | 200 | | 3 | 150 | | 4 | 50 | +------+------+ セット内の 4 行 (0.00 秒) ご覧のとおり、t2 テーブルのデータが正常に挿入されました。 次に、クエリ オプティマイザーによるインデックスの使用を確認します。ここでは、クエリ ステートメントは、次に示すように、c1 フィールドで昇順、c2 フィールドで降順になっています。 mysql> explain select * from t2 order by c1, c2 desc \G ************************** 1. 行 **************************** id: 1 選択タイプ: シンプル テーブル: t2 パーティション: NULL タイプ: インデックス 可能なキー: NULL キー: idx1 キーの長さ: 10 参照: NULL 行数: 4 フィルター: 100.00 追加: インデックスの使用; ファイルソートの使用 セットに1行、警告1回(0.12秒) ご覧のとおり、MySQL 5.7 では、c2 フィールドはインデックスを使用せずに降順でソートされます。 (4)MySQL 8.xのクエリオプティマイザによる降順インデックスの使用。 クエリ オプティマイザーによる降順インデックスの使用を確認します。 mysql> t2(c1, c2) に値 (1, 100)、(2, 200)、(3, 150)、(4, 50) を挿入します。 クエリは正常、4 行が影響を受けました (0.00 秒) 記録: 4 重複: 0 警告: 0 次に、以下に示すように t2 テーブル内のデータをクエリします。 mysql> t2 から * を選択します。 +------+------+ | c1 | c2 | +------+------+ | 1 | 100 | | 2 | 200 | | 3 | 150 | | 4 | 50 | +------+------+ セット内の 4 行 (0.00 秒) ご覧のとおり、t2 テーブルのデータが正常に挿入されました。 MySQL で昇順インデックスを作成すると、クエリを指定するときに、昇順インデックスを使用できるように、クエリを昇順でのみ指定できるようになります。 次に、クエリ オプティマイザーによるインデックスの使用を確認します。ここでは、クエリ ステートメントは、次に示すように、c1 フィールドで昇順、c2 フィールドで降順になっています。 mysql> explain select * from t2 order by c1, c2 desc \G ************************** 1. 行 **************************** id: 1 選択タイプ: シンプル テーブル: t2 パーティション: NULL タイプ: インデックス 可能なキー: NULL キー: idx1 キーの長さ: 10 参照: NULL 行数: 4 フィルター: 100.00 追加: インデックスの使用 セットに 1 行、警告 1 件 (0.00 秒) ご覧のとおり、MySQL 8.x では、c2 フィールドはインデックスを使用して降順でソートされます。 以下に示すように、c1 フィールドを降順、c2 フィールドを昇順で並べ替えます。 mysql> t2 から c1 desc、c2 で * を選択して説明 \G ************************** 1. 行 **************************** id: 1 選択タイプ: シンプル テーブル: t2 パーティション: NULL タイプ: インデックス 可能なキー: NULL キー: idx1 キーの長さ: 10 参照: NULL 行数: 4 フィルター: 100.00 追加: 後方インデックススキャン; インデックスの使用 セットに 1 行、警告 1 件 (0.00 秒) ご覧のとおり、インデックスは MySQL 8.x でも引き続き使用でき、インデックスの逆スキャンが使用されます。 (5)MySQL 8.xではGROUP BY文を暗黙的にソートしなくなりました。 MySQL 5.7 で次のコマンドを実行して、c2 フィールドでグループ化し、各グループ内のレコード数を照会します。 mysql> count(*), c2 を t2 から group by c2 で選択します。 +----------+------+ | カウント(*) | c2 | +----------+------+ | 1 | 50 | | 1 | 100 | | 1 | 150 | | 1 | 200 | +----------+------+ セット4行(0.18秒) ご覧のとおり、MySQL 5.7 では、c2 フィールドに対してソート操作が実行されます。 MySQL 8.x で次のコマンドを実行して、c2 フィールドでグループ化し、各グループ内のレコード数を照会します。 mysql> count(*), c2 を t2 から group by c2 で選択します。 +----------+------+ | カウント(*) | c2 | +----------+------+ | 1 | 100 | | 1 | 200 | | 1 | 150 | | 1 | 50 | +----------+------+ セット内の 4 行 (0.00 秒) ご覧のとおり、MySQL 8.x では、c2 フィールドに対してソート操作は実行されません。 MySQL 8.x では、c2 フィールドをソートする必要がある場合、以下に示すように、order by ステートメントを使用してソート規則を明示的に指定する必要があります。 mysql> select count(*), c2 from t2 group by c2 order by c2; +----------+------+ | カウント(*) | c2 | +----------+------+ | 1 | 50 | | 1 | 100 | | 1 | 150 | | 1 | 200 | +----------+------+ セット内の 4 行 (0.00 秒) 3. 機能インデックス1. 機能インデックスの概要
2. 関数インデックス操作(1)テストテーブルt3を作成する 以下に示すように、testdb データベースにテスト テーブル t3 を作成します。 mysql> テーブルが存在しない場合は作成します t3(c1 varchar(10), c2 varchar(10)); クエリは正常、影響を受けた行は 0 行 (0.01 秒) (2)通常のインデックスを作成する c1フィールドに通常のインデックスを作成する mysql> t3(c1) にインデックス idx1 を作成します。 クエリは正常、影響を受けた行は 0 行 (0.01 秒) レコード: 0 重複: 0 警告: 0 (3)機能インデックスを作成する 以下に示すように、フィールド値を大文字に変換する c2 フィールドに機能インデックスを作成します。 mysql> t3 ((UPPER(c2))) にインデックス func_index を作成します。 クエリは正常、影響を受けた行は 0 行 (0.02 秒) レコード: 0 重複: 0 警告: 0 (4)以下に示すように、t3テーブルのインデックス情報を表示します。 mysql> t3 からインデックスを表示 \G ************************** 1. 行 **************************** 表: t3 非ユニーク: 1 キー名: idx1 インデックス内のシーケンス: 1 列名: c1 照合: A カーディナリティ: 0 サブパート: NULL パック: NULL ヌル: はい インデックスタイプ: BTREE コメント: インデックスコメント: 表示: はい 式: NULL ************************** 2. 行 **************************** 表: t3 非ユニーク: 1 Key_name: func_index インデックス内のシーケンス: 1 列名: NULL 照合: A カーディナリティ: 0 サブパート: NULL パック: NULL ヌル: はい インデックスタイプ: BTREE コメント: インデックスコメント: 表示: はい 式: upper(`c2`) セットに2行(0.01秒) (5)クエリオプティマイザが2つのインデックスをどのように使用しているか確認する まず、以下に示すように、c1 フィールドの大文字の値が特定の値と等しいかどうかを確認します。 mysql> t3 から select * を実行します。この場合、upper(c1) は 'ABC' です。\G ************************** 1. 行 **************************** id: 1 選択タイプ: シンプル テーブル: t3 パーティション: NULL タイプ: すべて 可能なキー: NULL キー: NULL キー長さ: NULL 参照: NULL 行数: 1 フィルター: 100.00 追加: where の使用 セットに 1 行、警告 1 件 (0.00 秒) ご覧のとおり、インデックスは使用されず、完全なテーブルスキャン操作が実行されます。 次に、以下に示すように、c2 フィールドの大文字の値が特定の値と等しいかどうかを確認します。 mysql> t3 から select * を実行します。この場合、upper(c2) は 'ABC' です。\G ************************** 1. 行 **************************** id: 1 選択タイプ: シンプル テーブル: t3 パーティション: NULL タイプ: ref 可能なキー: func_index キー: func_index キーの長さ: 43 参照: 定数 行数: 1 フィルター: 100.00 追加: NULL セットに 1 行、警告 1 件 (0.00 秒) ご覧のとおり、機能インデックスが使用されています。 (6) JSONデータの関数インデックス まず、テスト テーブル emp を作成し、以下に示すように JSON データにインデックスを付けます。 mysql> テーブルが存在しない場合は作成します emp(data json, index((CAST(data->>'$.name' as char(30))))); クエリは正常、影響を受けた行は 0 行 (0.02 秒) 上記の SQL ステートメントは次のように説明されます。
簡単に言えば、名前ノードの値を取得してchar(30)型に変換します。 次に、以下に示すように、emp テーブルのインデックス ステータスを確認します。 mysql> emp \G からインデックスを表示 ************************** 1. 行 **************************** テーブル: emp 非ユニーク: 1 キー名: functional_index インデックス内のシーケンス: 1 列名: NULL 照合: A カーディナリティ: 0 サブパート: NULL パック: NULL ヌル: はい インデックスタイプ: BTREE コメント: インデックスコメント: 表示: はい 式: cast(json_unquote(json_extract(`data`,_utf8mb4\'$.name\')) as char(30) charset utf8mb4) セット内の 1 行 (0.00 秒) (7)機能インデックスは仮想列に基づいて実装される まず、以下に示すように、t3 テーブルの情報を表示します。 mysql> desc t3; +-------+-------------+------+------+--------+-------+ | フィールド | タイプ | Null | キー | デフォルト | 追加 | +-------+-------------+------+------+--------+-------+ | c1 | varchar(10) | はい | MUL | NULL | | | c2 | varchar(10) | はい | | NULL | | +-------+-------------+------+------+--------+-------+ セット内の 2 行 (0.00 秒) c1 に共通インデックスが作成され、c2 に機能インデックスが作成されます。 次に、次に示すように、列 c3 を t3 テーブルに追加して、c2 の機能インデックスをシミュレートします。 mysql> テーブル t3 を変更し、列 c3 varchar(10) を追加します。常に (upper(c1)) として生成されます。 クエリは正常、影響を受けた行は 0 行 (0.03 秒) レコード: 0 重複: 0 警告: 0 列 c3 は計算列です。c3 フィールドの値は常に、c1 フィールドを大文字に変換した結果になります。 次に、t3 テーブルにデータを挿入します。c3 列は計算列です。c3 フィールドの値は常に c1 フィールドを大文字に変換した結果になります。データを挿入するときに、次に示すように c3 列にデータを挿入する必要はありません。 mysql> t3(c1, c2) に値 ('abc', 'def') を挿入します。 クエリは正常、1 行が影響を受けました (0.00 秒) 以下に示すように、t3 テーブル内のデータをクエリします。 mysql> t3 から * を選択します。 +------+------+------+ | c1 | c2 | c3 | +------+------+------+ | abc | def | ABC | +------+------+------+ セット内の 1 行 (0.00 秒) 列 c3 にデータを挿入する必要がないことがわかります。列 c3 のデータは、フィールド c1 の大文字の結果データです。 機能インデックスの効果をシミュレートしたい場合は、次の方法を使用できます。 mysql> t3(c3) にインデックス idx3 を作成します。 クエリは正常、影響を受けた行は 0 行 (0.11 秒) レコード: 0 重複: 0 警告: 0 次に、以下に示すように、c1 フィールドの大文字の値が特定の値と等しいかどうかを再度確認します。 mysql> t3 から select * を実行します。この場合、upper(c1) は 'ABC' です。\G ************************** 1. 行 **************************** id: 1 選択タイプ: シンプル テーブル: t3 パーティション: NULL タイプ: ref 可能なキー: idx3 キー: idx3 キーの長さ: 43 参照: 定数 行数: 1 フィルター: 100.00 追加: NULL セットに 1 行、警告 1 件 (0.00 秒) このとき、idx3 インデックスが使用されます。 これで、MySQL 8 の 3 つの新しいインデックス (非表示、降順、関数) に関するこの記事は終了です。MySQL 8 の非表示、降順、関数インデックスの詳細については、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
<<: JavaScript でイベントのバブリングを防ぐ方法
>>: HTMLコードテキストボックスの制限入力テキストボックスが灰色になり、制限テキストボックスの入力
前回の記事では、Navicat for Mysql 接続エラー 1251 (接続失敗) の問題を解決...
昨日、a:visited を使用して「Guess You Like」の右側にある訪問済みテキストの色...
本日、ローカル開発環境で突然「入力ファイルが指定されていません」というエラーが発生してしまいました。...
WeChat アプレット プロジェクトを書いていたとき、その中に「都市選択」機能がありました。作者は...
成果を達成する html <h2>CSS3 タイムライン</h2> <...
目次1.配列を初期化する2. 配列の合計、最大値、最小値3. エラー値をフィルタリングする4. 論理...
最終的な効果は次のようになります。アニメーションは2つのステップに分かれていますランニング軌道を開発...
この記事では、jQueryタグセレクターアプリケーションの具体的なコードを例として紹介します。具体的...
これらの仕様は、下位互換性のあるドキュメントを Web 上で公開し、できるだけ幅広いユーザーがアクセ...
1. 最新のnginx dockerイメージをダウンロードする $ docker pull ngin...
問題: JDBCを使用してMySQLデータベースに接続すると、中国語の文字を挿入すると文字化けした文...
目次1. 解析する1.1 傍受のルール1.2 傍受プロセス部分1.3 パーサーの概要2. 最適化する...
目次1.スリープ機能2.タイムアウトを設定する3. 約束4. 非同期待機5. 1秒後に出力1、2秒後...
1. インライン参照:ラベルに直接使用されるが、メンテナンスコストが高い スタイル='フォ...
Linuxは特定のプログラムを見つけますwhereis コマンドは主にプログラム ファイルを検索し、...