SQL ステートメントの実行計画は更新され続けるため、データベースが不安定になる場合があります。 Alibaba Cloud では、オプティマイザとインデックスヒントを使用して安定した実行計画を作成する、ステートメント アウトライン機能を提供します。 ステートメント アウトライン機能を使用するには、DBMS_OUTLN パッケージをインストールします。
前提条件
インスタンスのバージョンが、ApsaraDB RDS for MySQL 8.0 であることが前提です。
機能設計
ステートメント アウトライン機能は、MySQL 8.0 の次のタイプのヒントをサポートします。
- オプティマイザヒント
オプティマイザヒントはスコープとオブジェクトによって分類され、グローバルレベルのヒント、テーブルレベルのヒント、インデックスレベルのヒント、JOIN_ORDER ヒントなど、さまざまなタイプに分類されます。 詳細については、「Optimizer Hints」をご参照ください。
- インデックスヒント
インデックスヒントは、スコープとタイプによって分類されます。 詳細については、「Index Hints」をご参照ください。
アウトラインテーブルの概要
AliSQLは、outline という名前のシステムテーブルを使用してヒントを保存します。 このテーブルは、インスタンスシステムによってシステムの起動時に自動的に作成されます。 次のステートメントで outline テーブルを作成します。
CREATE TABLE `mysql`.`outline` (
`Id` bigint(20) NOT NULL AUTO_INCREMENT,
`Schema_name` varchar(64) COLLATE utf8_bin DEFAULT NULL,
`Digest` varchar(64) COLLATE utf8_bin NOT NULL,
`Digest_text` longtext COLLATE utf8_bin,
`Type` enum('IGNORE INDEX','USE INDEX','FORCE INDEX','OPTIMIZER') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`Scope` enum('','FOR JOIN','FOR ORDER BY','FOR GROUP BY') CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
`State` enum('N','Y') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'Y',
`Position` bigint(20) NOT NULL,
`Hint` text COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`Id`)
) /*! 50100 TABLESPACE `mysql` */ ENGINE=InnoDB
DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0 COMMENT='Statement outline'
下表に各パラメーターを説明します。
パラメーター | 説明 |
Id | outline テーブルの ID を設定します。 |
Schema_name | データベースの名前を設定します。 |
Digest | ハッシュ計算中に Digest_text から算出した 64 バイトのハッシュ文字列を設定します。 |
Digest_text | SQL ステートメントのダイジェストを設定します。 |
Type |
|
Scope | このパラメーターは、インデックスヒントに対してのみ設定します。 設定可能な値は次のとおりです。
空の文字列は、すべてのタイプのインデックスヒントを示します。 |
State | ステートメント アウトラインを有効にするかどうかを設定します。 |
Position |
|
Hint |
|
ステートメント アウトラインの管理
AliSQL は、DBMS_OUTLN パッケージに 6 つの管理インターフェイスを備えています。 詳細については以下のとおりです。
- add_optimizer_outline
オプティマイザヒントを追加します。 コマンドは次のとおりです。
dbms_outln.add_optimizer_outline('<Schema_name>','<Digest>','<query_block>','<hint>','<query>');
説明 Digest または Query SQL ステートメントを入力できます。 Query ステートメントを入力すると、DBMS_OUTLN はDigest および Digest_textを計算します。例:
CALL DBMS_OUTLN.add_optimizer_outline("outline_db", '', 1, '/*+ MAX_EXECUTION_TIME(1000) */', "select * from t1 where id = 1");
- add_index_outline
インデックスヒントを追加します。 コマンドは次のとおりです。
dbms_outln.add_index_outline('<Schema_name>','<Digest>',<Position>,'<Type>','<Hint>','<Scope>','<Query>');
説明 Digest または Query SQL ステートメントを入力できます。 Query ステートメントを入力すると、DBMS_OUTLN はDigest および Digest_textを計算します。例:
call dbms_outln.add_index_outline('outline_db', '', 1, 'USE INDEX', 'ind_1', '', "select * from t1 where t1.col1 =1 and t1.col2 ='xpchild'");
- preview_outline
ステートメント アウトラインと一致する SQL ステートメントのステータスを照会します。手作業での検証に使用されます。 ステートメントは次のとおりです。
dbms_outln.preview_outline('<Schema_name>','<Query>');
例:
mysql> call dbms_outln.preview_outline('outline_db', "select * from t1 where t1.col1 =1 and t1.col2 ='xpchild'"); +------------+------------------------------------------------------------------+------------+------------+-------+---------------------+ | SCHEMA | DIGEST | BLOCK_TYPE | BLOCK_NAME | BLOCK | HINT | +------------+------------------------------------------------------------------+------------+------------+-------+---------------------+ | outline_db | b4369611be7ab2d27c85897632576a04bc08f50b928a1d735b62d0a140628c4c | TABLE | t1 | 1 | USE INDEX (`ind_1`) | +------------+------------------------------------------------------------------+------------+------------+-------+---------------------+ 1 row in set (0.00 sec)
- show_outline
メモリ内のステートメント アウトラインを表示します。 ステートメントは次のとおりです。
dbms_outln.show_outline();
例:
mysql> call dbms_outln.show_outline(); +------+------------+------------------------------------------------------------------+-----------+-------+------+-------------------------------------------------------+------+----------+-------------------------------------------------------------------------------------+ | ID | SCHEMA | DIGEST | TYPE | SCOPE | POS | HINT | HIT | OVERFLOW | DIGEST_TEXT | +------+------------+------------------------------------------------------------------+-----------+-------+------+-------------------------------------------------------+------+----------+-------------------------------------------------------------------------------------+ | 33 | outline_db | 36bebc61fce7e32b93926aec3fdd790dad5d895107e2d8d3848d1c60b74bcde6 | OPTIMIZER | | 1 | /*+ SET_VAR(foreign_key_checks=OFF) */ | 1 | 0 | SELECT * FROM `t1` WHERE `id` = ? | | 32 | outline_db | 36bebc61fce7e32b93926aec3fdd790dad5d895107e2d8d3848d1c60b74bcde6 | OPTIMIZER | | 1 | /*+ MAX_EXECUTION_TIME(1000) */ | 2 | 0 | SELECT * FROM `t1` WHERE `id` = ? | | 34 | outline_db | d4dcef634a4a664518e5fb8a21c6ce9b79fccb44b773e86431eb67840975b649 | OPTIMIZER | | 1 | /*+ BNL(t1,t2) */ | 1 | 0 | SELECT `t1` . `id` , `t2` . `id` FROM `t1` , `t2` | | 35 | outline_db | 5a726a609b6fbfb76bb8f9d2a24af913a2b9d07f015f2ee1f6f2d12dfad72e6f | OPTIMIZER | | 2 | /*+ QB_NAME(subq1) */ | 2 | 0 | SELECT * FROM `t1` WHERE `t1` . `col1` IN ( SELECT `col1` FROM `t2` ) | | 36 | outline_db | 5a726a609b6fbfb76bb8f9d2a24af913a2b9d07f015f2ee1f6f2d12dfad72e6f | OPTIMIZER | | 1 | /*+ SEMIJOIN(@subq1 MATERIALIZATION, DUPSWEEDOUT) */ | 2 | 0 | SELECT * FROM `t1` WHERE `t1` . `col1` IN ( SELECT `col1` FROM `t2` ) | | 30 | outline_db | b4369611be7ab2d27c85897632576a04bc08f50b928a1d735b62d0a140628c4c | USE INDEX | | 1 | ind_1 | 3 | 0 | SELECT * FROM `t1` WHERE `t1` . `col1` = ? AND `t1` . `col2` = ? | | 31 | outline_db | 33c71541754093f78a1f2108795cfb45f8b15ec5d6bff76884f4461fb7f33419 | USE INDEX | | 2 | ind_2 | 1 | 0 | SELECT * FROM `t1` , `t2` WHERE `t1` . `col1` = `t2` . `col1` AND `t2` . `col2` = ? | +------+------------+------------------------------------------------------------------+-----------+-------+------+-------------------------------------------------------+------+----------+-------------------------------------------------------------------------------------+ 7 rows in set (0.00 sec)
下表に、HIT および OVERFLOW パラメーターを説明します。
パラメーター 説明 HIT ステートメント アウトラインが目的のクエリブロックまたはテーブルを検出した回数を示します。 OVERFLOW ステートメント アウトラインが目的の宛先クエリブロックまたはテーブルを検出できなかった回数を示します。 - del_outline
メモリとテーブルからステートメント アウトラインを削除します。 コマンドは次のとおりです。
dbms_outln.del_outline(<Id>);
例:
mysql> call dbms_outln.del_outline(32);
説明 削除するステートメント アウトラインが存在しなかった場合、対応するエラーが表示されます。 エラーメッセージを表示するには、SHOW WARNINGS;
ステートメントを実行します。mysql> call dbms_outln.del_outline(1000); Query OK, 0 rows affected, 2 warnings (0.00 sec) mysql> show warnings; +---------+------+----------------------------------------------+ | Level | Code | Message | +---------+------+----------------------------------------------+ | Warning | 7521 | Statement outline 1000 is not found in table | | Warning | 7521 | Statement outline 1000 is not found in cache | +---------+------+----------------------------------------------+ 2 rows in set (0.00 sec)
- flush_outline
アウトラインテーブルのステートメントアウトラインを変更した場合は、次のステートメントを実行してステートメント アウトラインを再度有効化する必要があります。 ステートメントは次のとおりです。
dbms_outln.flush_outline();
例:
mysql> update mysql.outline set Position = 1 where Id = 18; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> call dbms_outln.flush_outline(); Query OK, 0 rows affected (0.01 sec)
機能テスト
ステートメント アウトラインが有効かどうかを確認するには、2 つの方法があります。
- preview_outline インターフェースを使用する方法。
mysql> call dbms_outln.preview_outline('outline_db', "select * from t1 where t1.col1 =1 and t1.col2 ='xpchild'"); +------------+------------------------------------------------------------------+------------+------------+-------+---------------------+ | SCHEMA | DIGEST | BLOCK_TYPE | BLOCK_NAME | BLOCK | HINT | +------------+------------------------------------------------------------------+------------+------------+-------+---------------------+ | outline_db | b4369611be7ab2d27c85897632576a04bc08f50b928a1d735b62d0a140628c4c | TABLE | t1 | 1 | USE INDEX (`ind_1`) | +------------+------------------------------------------------------------------+------------+------------+-------+---------------------+ 1 row in set (0.01 sec)
- EXPLAIN ステートメントを実行する方法。
mysql> explain select * from t1 where t1.col1 =1 and t1.col2 ='xpchild'; +----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------------+ | 1 | SIMPLE | t1 | NULL | ref | ind_1 | ind_1 | 5 | const | 1 | 100.00 | Using where | +----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) mysql> show warnings; +-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Note | 1003 | /* select#1 */ select `outline_db`.`t1`.`id` AS `id`,`outline_db`.`t1`.`col1` AS `col1`,`outline_db`.`t1`.`col2` AS `col2` from `outline_db`.`t1` USE INDEX (`ind_1`) where ((`outline_db`.`t1`.`col1` = 1) and (`outline_db`.`t1`.`col2` = 'xpchild')) | +-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)