MySQLでは、
今回は、
オプティマイザーヒント構文
オプティマイザーのヒントは/*+ ... */をステートメント内に記述します。SELECT、UPDATEやDELETEなどのDMLのキーワードの後にヒントを記述します。ヒントの内容をパーサーが認識して処理します。以下のように記載します。
mysql> SELECT /*+ hint */ ... mysql> UPDATE /*+ hint */ ...
指定したヒントが有効か確認するには、EXPLAIN後にSHOW WARNINGS実施します。たとえば、NO_ヒントを追加して実施した結果です。このヒントは指定したテーブルおよびインデックスを使用したレンジスキャンで解決しないようにオプティマイザーを制御します。ヒントが有効であれば、SHOW WARNINGSにて使用されたヒントが表示されます。
mysql> EXPLAIN SELECT /*+ NO_RANGE_OPTIMIZATION(t PRIMARY) */ * FROM t WHERE id BETWEEN 1 AND 10; +----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+ | 1 | SIMPLE | t | NULL | ALL | PRIMARY | NULL | NULL | NULL | 39528 | 11.11 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+ mysql> SHOW WARNINGS; +-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Note | 1003 | /* select#1 */ select /*+ NO_RANGE_OPTIMIZATION(`t`@`select#1` `PRIMARY`) */ `d`.`t`.`id` AS `id`,`d`.`t`.`k` AS `k`,`d`.`t`.`c` AS `c`,`d`.`t`.`pad` AS `pad` from `d`.`t` where (`d`.`t`.`id` between 1 and 10) | +-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
無効なヒントを指定した場合は、
mysql> EXPLAIN SELECT /*+ NO_RANGE_OPTIMIZATION(t idx_t) */ * FROM t WHERE id BETWEEN 1 AND 10; +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ | 1 | SIMPLE | t | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 10 | 100.00 | Using where | +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ mysql> SHOW WARNINGS; +---------+------+------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +---------+------+------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Warning | 3128 | Unresolved name `t`@`select#1` `idx_t` for NO_RANGE_OPTIMIZATION hint | | Note | 1003 | /* select#1 */ select `d`.`t`.`id` AS `id`,`d`.`t`.`k` AS `k`,`d`.`t`.`c` AS `c`,`d`.`t`.`pad` AS `pad` from `d`.`t` where (`d`.`t`.`id` between 1 and 10) | +---------+------+------------------------------------------------------------------------------------------------------------------------------------------------------------+
このようにして、
MySQL 8.0のオプティマイザーヒント
ここからは、
JOINヒント
JOINヒントを使用して、
SET_VARヒント
SET_SET_というように記述します。
このヒントの使用例を紹介します。
従来であれば、range_や、optimizer_などのシステム変数を特定のステートメントに値を変更したいときには、
SET SESSIONを使用して値を変更- ステートメント実行
SET SESSIONを使用して値を戻す
mysql> SET SESSION optimizer_switch='condition_fanout_filter=off'; mysql> SELECT....; mysql> SET SESSION optimizer_switch='condition_fanout_filter=on';
セッション値の変更はステートメント間やトランザクション間ではなく、
以下のようにヒントを使用すると、
mysql> SELECT /*+ SET_VAR(optimizer_switch='condition_fanout_filter=off') */ ...
INDEX_MERGE・NO_INDEX_MERGEヒント
指定されたテーブル、
MERGE・NO_MERGEヒント
指定されたテーブル、
- SHOW WARNINGSにエラー情報はでなくても、
ヒントの効果がないとオプティマイザーが判断すると無視されることもあります。 - optimizer_
switchシステム変数のderived_ mergeフラグよりもヒントが優先されます。 - ビューの場合は、
ヒントよりもビュー定義の ALGORITHM = {MERGE | TEMPTABLE}句が優先されます。
SKIP_SCAN・NO_SKIP_SCANヒント
MySQL 8.
HASH_JOIN・NO_HASH_JOINヒント
MySQL 8.
mysql> EXPLAIN FORMAT=tree SELECT /*+ NO_HASH_JOIN(t,t2) */ * FROM t JOIN t2 USING(c);
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Inner hash join (t.c = t2.c) (cost=4105.41 rows=3953)
-> Table scan on t (cost=547.54 rows=39528)
-> Hash
-> Table scan on t2 (cost=0.35 rows=1)
|
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> EXPLAIN FORMAT=tree SELECT /*+ NO_BNL(t,t2) */ * FROM t JOIN t2 USING(c);
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Nested loop inner join (cost=4105.40 rows=3953)
-> Table scan on t2 (cost=0.35 rows=1)
-> Filter: (t.c = t2.c) (cost=547.53 rows=3953)
-> Table scan on t (cost=547.53 rows=39528)
|
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
RESOURCE_GROUPヒント
MySQL 8.
まとめ
今回紹介した内容は、