クエリの実行中、列ストアインデックスのプルーナー機能は、アクセスする必要のないデータブロックをフィルタリングすることで、SQL クエリのパフォーマンスを向上させます。このトピックでは、プルーナーのシナリオ、考慮事項、構文、および関連パラメーターについて説明します。
概要
列ストアインデックスのデータは、単一列のデータブロックに格納され、デフォルトの粒度はブロックあたり 64,000 行です。データブロックの数は、テーブルの総行数 / 64000 という数式で見積もることができます。ある行セットのすべての列パックは、行グループを形成します。データスキャンでは、指定された列のすべてのデータブロックを走査して、フィルター条件を満たすレコードを取得する必要があります。大規模なテーブルをクエリする場合、スキャンのオーバーヘッドは高くなります。テーブルデータが完全にメモリに収まらない場合、オーバーヘッドはさらに増加します。実際には、統計情報と特定のフィルター条件を使用して、不要なデータブロックをスキップし、クエリを高速化できます。 PolarDB の列ストアインデックスでは、このメソッドはプルーナーと呼ばれます。現在、次の 4 種類のプルーナーがサポートされています。
ブルームフィルター
ビット配列を使用してセットを表し、要素がそのセットに属するかどうかを判断します。
プレフィックスブルームフィルター:文字列のプレフィックスに基づいてブルームフィルターを構築し、長い文字列によるパフォーマンスとストレージのオーバーヘッドを削減します。サポートされているバージョンは次のとおりです。
MySQL 8.0.1、リビジョンバージョン 8.0.1.1.42 以降。
MySQL 8.0.2、リビジョンバージョン 8.0.2.2.25 以降。
Min-Max インデックス
各データブロックの最小値と最大値を格納します。フィルター条件をこれらの値と比較して、ブロックをスキャンするかどうかを決定します。
トークンブルームフィルター
英数字以外の文字で文字列を分割してフィルタリングします。たとえば、「I am IMCI」は
I |am|IMCIとなります。これは LIKE あいまいクエリに適しています。N-gram ブルームフィルター
指定された長さの部分文字列に文字列を分割してフィルタリングします。たとえば、N-gram サイズが 3 の文字列「storage」は
sto|tor|ora|rag|ageとなります。これは LIKE あいまいクエリに適しています。
シナリオ
ブルームフィルター:等価条件および IN 条件に最適です。文字列 ID でフィルタリングする場合など、等価条件の選択性が高い場合に強力なフィルタリングを提供します。
Min-Max インデックス:列データの局所性が高い場合に効果的で、特に日付やソートされたフィールドを含む WHERE 句などの範囲フィルターや等価フィルターに適しています。
トークンブルームフィルターと N-gram ブルームフィルターは、LIKE あいまいクエリで一致しないデータブロックを迅速に除外します。
ストレージのオーバーヘッド
文字列型の列に対してプルーナーを有効にすると、ストレージとメモリのオーバーヘッドが増加します。シナリオに応じて、ブルームフィルター、Min-Max インデックス、トークンブルームフィルター、N-gram ブルームフィルターなど、構築するプルーナーの種類を選択できます。メモリ使用量の数式は次のとおりです。
ブルームフィルター、トークンブルームフィルター、または N-gram ブルームフィルター
デフォルトの 64,000 行のブロックサイズで、個別値の数が総行数の 3% を超える場合:
メモリ使用量 = 1.2 × ブルームフィルターを持つ列数 × テーブルの総行数 (バイト)
デフォルトの 64,000 行のブロックサイズで、個別値の数が総行数の 3% 以下の場合:
メモリ使用量 = 1.2 × ブルームフィルターを持つ列数 × 個別値の数 (バイト)
この場合、ブルームフィルターの有効性はデータの局所性に依存します。データが均一に分散している場合、パフォーマンスは低下します。
Min-Max インデックス
メモリ使用量の数式は次のとおりです。
メモリ使用量 = 2 × Min-Max インデックスを持つ列数 × (テーブルの総行数 / ブロックサイズ) × プレフィックス長 × 文字コード長
たとえば、20 億行のテーブルで、10 列に Min-Max インデックスがあり、プレフィックス長が 20、ブロックサイズが 64,000、文字コードが utf8mb4 (1 文字あたり 4 バイト) の場合、約 46 MB のメモリを使用します。
注意事項
PolarDB for MySQL バージョン 8.0.1.1.32 以前、または 8.0.2.2.13 以前を実行するクラスターでは、NULL 値を含むデータブロックに対してプルーナーは構築されません。
IS NULLまたはIS NOT NULLでのフィルタリングはサポートされていません。PolarDB for MySQL バージョン 8.0.1.1.35 以降、または 8.0.2.2.16 以降を実行するクラスターでは、列ストアインデックスを作成する際に、文字列型の列に対してプルーナーが自動的に構築されます。ブルームフィルターは、メモリ管理に Least Recently Used (LRU) キャッシュを使用します。古いバージョンからアップグレードする場合、文字列型の列に対してプルーナーを有効にするには、列ストアインデックスを再構築する必要があります。
PolarDB for MySQL バージョン 8.0.1.1.34 以前、または 8.0.2.2.15 以前を実行するクラスターでは、プルーナーは永続的にメモリに残ります。列ストアインデックスの作成中に、文字列型の列に対してプルーナーは自動的に構築されません。
文字列型の列に対してプルーナーを構築するには、文字列に「\0」が含まれていないことを確認する必要があります (例:「polar\0db」)。
システムは、INT、DECIMAL、DATETIME などの数値型に対して自動的に Min-Max インデックスを構築します。
Min-Max インデックスは、JSON または GEOMETRY フィールドではサポートされていません。
ブルームフィルターは、INT、DECIMAL、DATETIME などの数値型、または JSON、BLOB、TEXT フィールドではサポートされていません。
構文リファレンス
テーブルの作成時にプルーナーを構築したり、既存のテーブルに追加または削除したりできます。既存のテーブルのプルーナーを変更するには、まず列ストアインデックスを削除してから再作成する必要があります。構文は次のとおりです。
データ定義言語 (DDL) 文を使用して、テーブルスキーマの COMMENT 属性を変更し、文字列型の列にプルーナーを追加または削除できます。
列レベルの COMMENT 属性は、テーブルレベルの COMMENT 属性よりも優先されます。
新しいバージョンでは、より多くのプルーナータイプがサポートされ、文字列に対する Min-Max インデックスやブルームフィルターなど、一般的なものがデフォルトで有効になっています。新しいプルーナーを追加する前に、各列の既存のプルーナータイプを確認してください。詳細については、「テーブル列にプルーナーが構築されているかどうかの確認」をご参照ください。
テーブル作成時のプルーナーの構築
プルーナー (ブルームフィルター) の構築
説明PolarDB for MySQL 8.0、リビジョン 8.0.1.1.32 以降、または 8.0.2.2.13 以降を実行するクラスターは、
PRUNER_BLOOM属性をサポートしています。サポートされているすべての列にブルームフィルターを構築します。例:
CREATE TABLE t1 ( id INT PRIMARY KEY, str_col1 char(10), str_col2 varchar(10) ) ENGINE InnoDB COMMENT "COLUMNAR=1 PRUNER_BLOOM=1"; /* コメント内の pruner_bloom 属性 */特定の列にブルームフィルターを構築します。例:
CREATE TABLE t1 ( id INT PRIMARY KEY, str_col1 char(10) "PRUNER_BLOOM=1", /* コメント内の pruner_bloom 属性 */ str_col2 varchar(10) ) ENGINE InnoDB COMMENT "COLUMNAR=1";
プルーナー (minmax インデックス) の構築
長い文字列の列の場合、システムは文字列のプレフィックスを最小値と最大値と比較して、メモリ使用量を削減します。デフォルトのプレフィックス長は 20 文字で、最大は 255 です。`PRUNER_MINMAX` を使用して文字列の Min-Max インデックスを有効にし、`PREFIX_LEN` を使用してプレフィックス長を設定できます。
説明文字数は、エンコーディングの長さではなく、文字数に基づいています。たとえば、「Alibaba Cloud PolarDB」の最初の 2 文字は「Al」、最初の 5 文字は「Aliba」です。
PolarDB for MySQL 8.0、リビジョン 8.0.1.1.32 以降、または 8.0.2.2.13 以降を実行するクラスターは、
PRUNER_MINMAXおよびPREFIX_LEN属性をサポートしています。
すべての文字列の列に Min-Max インデックスを構築します。例:
CREATE TABLE t1 ( id INT PRIMARY KEY, str_col1 char(10), str_col2 varchar(10) ) ENGINE InnoDB COMMENT "COLUMNAR=1 PRUNER_MINMAX=1 PREFIX_LEN=30"; /* 30 文字のプレフィックスを持つ pruner_minmax 属性 */特定の列に Min-Max インデックスを構築します。例:
CREATE TABLE t1 ( id INT PRIMARY KEY, str_col1 char(10) "PRUNER_MINMAX=1 PREFIX_LEN=30", /* 30 文字のプレフィックスを持つ pruner_minmax */ str_col2 varchar(10) "PRUNER_MINMAX=1 PREFIX_LEN=10" /* 10 文字のプレフィックスを持つ pruner_minmax */ ) ENGINE InnoDB COMMENT "COLUMNAR=1";
プレフィックスブルームフィルターの構築
説明PolarDB for MySQL 8.0、リビジョン 8.0.1.1.42 以降、または 8.0.2.2.25 以降を実行するクラスターは、
PRUNER_PREFIX_BLOOM属性をサポートしています。サポートされているすべての列にプレフィックスブルームフィルターを構築します。例:
CREATE TABLE t1 ( id INT PRIMARY KEY, str_col1 char(10), str_col2 varchar(10) ) ENGINE InnoDB COMMENT "COLUMNAR=1 PRUNER_PREFIX_BLOOM=1"; /* テーブルコメント内の PRUNER_PREFIX_BLOOM */特定の列にプレフィックスブルームフィルターを構築します。例:CREATE TABLE t1 ( id INT PRIMARY KEY, str_col1 char(10) "PRUNER_PREFIX_BLOOM=1", /* 列コメント内の PRUNER_PREFIX_BLOOM */ str_col2 varchar(10) ) ENGINE InnoDB COMMENT "COLUMNAR=1";
CREATE TABLE t1 ( id INT PRIMARY KEY, str_col1 char(10) "PRUNER_PREFIX_BLOOM=1", /* 列コメント内の PRUNER_PREFIX_BLOOM */ str_col2 varchar(10) ) ENGINE InnoDB COMMENT "COLUMNAR=1";
トークンブルームフィルターの構築
説明PRUNER_TOKEN_BLOOM属性は、次のバージョンでサポートされています。PolarDB for MySQL 8.0.1、リビジョン 8.0.1.1.39 以降。
PolarDB for MySQL 8.0.2、リビジョン 8.0.2.2.20 以降。
サポートされているすべての列にトークンブルームフィルターを構築できます。例:
CREATE TABLE t1 ( id INT PRIMARY KEY, str_col1 char(10), str_col2 varchar(10) ) ENGINE InnoDB COMMENT "COLUMNAR=1 PRUNER_TOKEN_BLOOM=1";特定の列にトークンブルームフィルターを構築できます。例:
CREATE TABLE t1 ( id INT PRIMARY KEY, str_col1 char(10) "PRUNER_TOKEN_BLOOM=1", str_col2 varchar(10) ) ENGINE InnoDB COMMENT "COLUMNAR=1";
N-gram ブルームフィルターの構築
説明PRUNER_TOKEN_BLOOMプロパティは、次の条件を満たすクラスターバージョンでサポートされています。PolarDB for MySQL 8.0.1、リビジョン 8.0.1.1.39 以降。
PolarDB for MySQL 8.0.2、リビジョン 8.0.2.2.20 以降。
PRUNER_NGRAM_BLOOM=N:N は 2 以上でなければならず、部分文字列の長さを設定します。N はLIKE "%string%"の文字列の長さ以下の値に設定することを推奨します。LIKE "%string%"の文字列が N より短い場合、N-gram ブルームフィルターは使用できません。
サポートされているすべての列に N-gram ブルームフィルターを構築します。例:
CREATE TABLE t1 ( id INT PRIMARY KEY, str_col1 char(10), str_col2 varchar(10) ) ENGINE InnoDB COMMENT "COLUMNAR=1 PRUNER_NGRAM_BLOOM=2";特定の列に N-gram ブルームフィルターを構築します。例:
CREATE TABLE t1 ( id INT PRIMARY KEY, str_col1 char(10) "PRUNER_NGRAM_BLOOM=3", str_col2 varchar(10) ) ENGINE InnoDB COMMENT "COLUMNAR=1";
既存のテーブルでのプルーナーの構築または削除
既存のテーブルにプルーナーを追加または削除するには、まず列ストアインデックスを削除してから再作成して、インデックスを再構築する必要があります。インデックスを再構築する前に、COMMENT のプルーナー属性を更新または削除します。次のセクションでは、PRUNER_MINMAX を例として使用します。
プルーナーを構築する
元のテーブル構造が次のようになっていると仮定します。
Table: t1 Create Table: CREATE TABLE `t1` ( `id` int(11) NOT NULL, `str_col1` char(10) DEFAULT NULL, `str_col2` varchar(10) DEFAULT NULL, PRIMARY KEY (`id`), COLUMNAR INDEX (`id`,`str_col1`,`str_col2`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='COLUMNAR=1'テーブル
t1のすべての文字列の列に Min-Max プルーナーを構築します。テーブル
t1の列ストアインデックスを削除します。ALTER TABLE t1 COMMENT = "COLUMNAR=0";テーブル
t1のすべての文字列の列に対して Min-Max プルーナーを有効にします。ALTER TABLE t1 COMMENT = "COLUMNAR=1 PRUNER_MINMAX=1";(任意) 更新されたテーブル構造を表示します。
SHOW CREATE TABLE t1 FULL \G結果:
*************************** 1. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `id` int(11) NOT NULL, `str_col1` char(10) DEFAULT NULL, `str_col2` varchar(10) DEFAULT NULL, PRIMARY KEY (`id`), COLUMNAR INDEX (`id`,`str_col1`,`str_col2`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='COLUMNAR=1 PRUNER_MINMAX=1't1テーブルにPRUNER_MINMAX属性が含まれるようになりました。
テーブル
t1のstr_col1列に Min-Max プルーナーを構築します。str_col1列にプルーナーを追加します。ALTER TABLE t1 MODIFY COLUMN str_col1 char(10) COMMENT 'PRUNER_MINMAX=1';次のコマンドを順に実行して、テーブル
t1の列ストアインデックスを再構築します。ALTER TABLE t1 COMMENT = "COLUMNAR=0"; ALTER TABLE t1 COMMENT = "COLUMNAR=1";(任意) 更新されたテーブル構造を表示します。
SHOW CREATE TABLE t1 FULL \G結果:
*************************** 1. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `id` int(11) NOT NULL, `str_col1` char(10) DEFAULT NULL COMMENT 'PRUNER_MINMAX=1', `str_col2` varchar(10) DEFAULT NULL, PRIMARY KEY (`id`), COLUMNAR INDEX (`id`,`str_col1`,`str_col2`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='COLUMNAR=1'str_col1列にPRUNER_MINMAX属性が追加されました。
プルーナーの削除
テーブルから
PRUNER_MINMAX属性を削除します。テーブル
t1が次の構造を持っていると仮定します。SHOW CREATE TABLE t1 full \G *************************** 1. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `id` int(11) NOT NULL, `str_col1` char(10) DEFAULT NULL, `str_col2` varchar(10) DEFAULT NULL, PRIMARY KEY (`id`), COLUMNAR INDEX (`id`,`str_col1`,`str_col2`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='COLUMNAR=1 PRUNER_MINMAX=1'テーブル
t1からPRUNER_MINMAX属性を削除するには:次のコマンドを実行して、テーブル
t1の列ストアインデックスを削除します。ALTER TABLE t1 COMMENT = "COLUMNAR=0";PRUNER_MINMAXを 0 に設定し、インデックスを再構築します。ALTER TABLE t1 COMMENT = "COLUMNAR=1 PRUNER_MINMAX=0";(任意) 更新されたテーブル構造を表示します。
SHOW CREATE TABLE t1 FULL \G結果:
*************************** 1. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `id` int(11) NOT NULL, `str_col1` char(10) DEFAULT NULL, `str_col2` varchar(10) DEFAULT NULL, PRIMARY KEY (`id`), COLUMNAR INDEX (`id`,`str_col1`,`str_col2`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='COLUMNAR=1't1テーブルにはPRUNER_MINMAX属性がなくなりました。
列から
PRUNER属性を削除します。テーブル
t1のstr_col1列にPRUNER_MINMAX属性があると仮定します。テーブル構造は次のとおりです。Table: t1 Create Table: CREATE TABLE `t1` ( `id` int(11) NOT NULL, `str_col1` char(10) DEFAULT NULL COMMENT 'PRUNER_MINMAX=1', `str_col2` varchar(10) DEFAULT NULL, PRIMARY KEY (`id`), COLUMNAR INDEX (`id`,`str_col1`,`str_col2`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='COLUMNAR=1'str_col1列からPRUNER_MINMAX属性を削除するには:str_col1列からPRUNER_MINMAX属性を削除します。ALTER TABLE t1 MODIFY COLUMN str_col1 char(10) COMMENT 'PRUNER_MINMAX=0';列ストアインデックスを再構築します。
ALTER TABLE t1 COMMENT = "COLUMNAR=0"; ALTER TABLE t1 COMMENT = "COLUMNAR=1";(任意) 更新されたテーブル構造を表示します。
SHOW CREATE TABLE t1 FULL \G結果:
*************************** 1. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `id` int(11) NOT NULL, `str_col1` char(10) DEFAULT NULL, `str_col2` varchar(10) DEFAULT NULL, PRIMARY KEY (`id`), COLUMNAR INDEX (`id`,`str_col1`,`str_col2`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='COLUMNAR=1'str_col1列にはPRUNER_MINMAX属性がなくなりました。
テーブル列にプルーナーが構築されているかどうかの確認
プルーナーの有効性の検証
SHOW STATUS を使用した確認
クエリを実行する前後に、SHOW STATUS LIKE 'imci_pruner%' を使用してデータブロックのフィルタリングを検査し、プルーナーの効果を確認できます。これらの値は、現在のセッションの累積プルーナーメトリックです。複数テーブルのクエリの場合、結果はすべてのテーブルで合計されます。ステータス値は次のように説明されます。
imci_pruner_accepted:フィルター条件を完全に満たすデータブロックの数。imci_pruner_rejected:フィルター条件を満たさないデータブロックの数。
スキップされたブロックの合計数は、受け入れられたブロックと拒否されたブロックの合計です。
受け入れられたブロックはレコードごとのフィルタリングをスキップしますが、マテリアライズにはアクセスが必要な場合があります。拒否されたブロックはスキャンプロセス全体をスキップし、I/O は発生しません。
例
テーブル t1 を例として、検索文に対してプルーナーが有効かどうかを判断します。テーブル t1 のテーブルスキーマは次のとおりです。
Table: t1
Create Table: CREATE TABLE `t1` (
`id` int(11) NOT NULL,
`str_col1` char(10) DEFAULT NULL,
`str_col2` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`),
COLUMNAR INDEX (`id`,`str_col1`,`str_col2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='COLUMNAR=1 PRUNER=1'テーブルに 10 個のデータブロックが含まれており、条件 str_col1='polardb' を満たすレコードが単一のデータブロックに集中していると仮定します。次の手順を実行して、SELECT COUNT(1) FROM t1 WHERE str_col1='polardb' 検索文でプルーナーが有効になるかどうかを確認できます。
現在のプルーナーのステータスを確認します。
SHOW STATUS LIKE 'imci_pruner%';結果:
+----------------------+-------+ | Variable_name | Value | +----------------------+-------+ | imci_pruner_accepted | 0 | | imci_pruner_rejected | 0 | +----------------------+-------+ 2 rows in set (0.00 sec)次のコマンドを実行して、条件
str_col1='polardb'を満たす行数をクエリします。SELECT COUNT(1) FROM t1 WHERE str_col1='polardb';結果:
+----------+ | count(1) | +----------+ | 1 | +----------+ 1 row in set (0.01 sec)プルーナーのステータスを再度確認します。
SHOW STATUS LIKE 'imci_pruner%';結果:
+----------------------+-------+ | Variable_name | Value | +----------------------+-------+ | imci_pruner_accepted | 0 | | imci_pruner_rejected | 9 | +----------------------+-------+ 2 rows in set (0.00 sec)imci_pruner_acceptedの値は 0、imci_pruner_rejectedの値は 9 です。クエリは 9 つのブロックをスキップしたため、プルーナーの有効性が確認されます。
imci_sql_profiling を使用した確認
この機能は、PolarDB for MySQL 8.0、リビジョン 8.0.1.1.5 以降、または 8.0.2.2.29 以降でのみサポートされています。
information_schema.imci_sql_profiling をクエリして、実行計画で Table Scan オペレーターがプルーナーを使用してフィルタリングしたデータパケットの数を確認できます。SHOW STATUS での確認とは異なり、このメソッドはクエリに直接関連付けられたテーブルレベルのフィルタリングを示します。SHOW STATUS コマンドはセッションスコープであり、手動での差分計算が必要です。したがって、このメソッドの方が直感的です。
列ストアインデックスのクエリプロファイリングを有効にします。
SET imci_analyze_query=ON;クエリを実行します。例:
SELECT count(*) from t1 WHERE v1 > 100; +--------------+ | count(*) | +--------------+ | 600 | +--------------+imci_sql_profilingテーブルを確認します。SELECT `Operator`, `Extra Info` from INFORMATION_SCHEMA.IMCI_SQL_PROFILING;+----+------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+ | ID | Operator | Extra Info | +----+------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+ | 1 | Select Statement | IMCI Execution Plan (max_dop = 32, real_dop = 32, max_query_mem = unlimited, real_query_mem = unlimited) | | 2 | └─Aggregation | | | 3 | └─Table Scan Cond: (v1 > 100), Pruner Counter: [AC: 8, RE: 1, PA: 2] | | +----+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+AC: 8は 8 つのパケットが受け入れられたことを示します。RE: 1は 1 つのパケットが拒否されたことを示します。PA: 2は 2 つのパケットが部分的に一致し、さらなるフィルタリングが必要であったことを示します。
Performance Testing
このセクションでは、2 コア、4 GB のクラスターで、約 1,800 のデータブロックに相当する 1 億 2,000 万行のテーブルでのテストについて説明します。文字列の列 col には 8,000 万の個別値があります。このテストでは、次のステートメントを使用して、ブルームフィルターの有無によるクエリパフォーマンスを比較します。
SELECT COUNT(1) FROM t1 WHERE col='xxx'クエリ時間は次のとおりです。
ブルームフィルターの構築 | ブルームフィルターなし |
0.15 秒 | 18.6 秒 |
条件 col='xxx' とブルームフィルターを組み合わせることで、ほとんどのデータブロックが除外されました。スキャンされたのはごく少数のブロックのみで、パフォーマンスが大幅に向上しました。