Dans un environnement de production, le plan d'exécution d'une instruction SQL peut changer fréquemment, entraînant une instabilité de la base de données. Alibaba Cloud utilise des indications pour l'optimiseur et des indications d'index — une méthode appelée « statement outline » — afin de stabiliser les plans d'exécution MySQL. Utilisez des commandes SQL et la boîte à outils DBMS_OUTLN pour appliquer rapidement des plans de requête.
Prérequis
L'instance RDS exécute l'une des versions MySQL suivantes :
MySQL 8.4
MySQL 8.0
MySQL 5.7
Fonctionnement
Le plan de requête prend en charge tous les types d'indications disponibles dans les versions officielles MySQL 8.4, 8,0 et 5,7. Ces indications se répartissent dans les deux catégories suivantes :
-
Indication pour l'optimiseur
Selon leur portée et l'objet cible, les indications pour l'optimiseur incluent des indications au niveau global, au niveau table ou index, ainsi que des indications sur l'ordre de jointure. Pour plus d'informations, consultez la documentation MySQL.
-
Indication d'index
Les indications d'index sont classées par type et par portée. Pour plus d'informations, consultez la documentation MySQL.
Table du plan de requête
AliSQL inclut une table système intégrée nommée outline pour stocker les indications. Cette table est créée automatiquement au démarrage. L'instruction CREATE TABLE suivante est fournie à titre de référence :
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'
Le tableau suivant décrit les colonnes.
Paramètre | Description |
Id | ID du plan de requête. |
Schema_name | Nom de la base de données. |
Digest | Chaîne de hachage de 64 octets calculée à partir de Digest_text. |
Digest_text | Résumé de l'instruction SQL. |
Type |
|
Scope | Requis uniquement pour les indications d'index. Valeurs valides :
Une chaîne vide indique que l'indication d'index s'applique à tous les types. |
State | Indique si le plan de requête est activé. |
Position |
|
Hint |
|
Gestion des plans de requête
AliSQL fournit les six procédures stockées suivantes dans DBMS_OUTLN pour gérer les plans de requête :
-
add_optimizer_outline
Ajoute une indication pour l'optimiseur. Utilisez la commande suivante :
dbms_outln.add_optimizer_outline('<Schema_name>','<Digest>','<query_block>','<hint>','<query>');RemarqueSpécifiez soit Digest, soit Query (l'instruction SQL d'origine). Si vous fournissez Query, DBMS_OUTLN calcule Digest et Digest_text.
Exemple :
mysql> call dbms_outln.add_optimizer_outline("outline_db", '', 1, '/*+ MAX_EXECUTION_TIME(1000) */', "select * from t1 where id = 1"); -
add_index_outline
Ajoute une indication d'index. Utilisez la commande suivante :
dbms_outln.add_index_outline('<Schema_name>','<Digest>',<Position>,'<Type>','<Hint>','<Scope>','<Query>');RemarqueSpécifiez soit Digest, soit Query (l'instruction SQL d'origine). Si vous fournissez Query, DBMS_OUTLN calcule Digest et Digest_text.
Exemple :
mysql> 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
Prévisualise les plans correspondant à une requête. Cette fonction est utile pour la validation manuelle. Utilisez la commande suivante :
dbms_outln.preview_outline('<Schema_name>','<Query>');RemarqueLa valeur du paramètre
max_digest_lengthpeut affecter la précision de la mise en correspondance des plans de requête. Si un plan de requête n'est pas correctement mis en correspondance, augmentez la valeur de ce paramètre.Exemple :
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
Affiche les plans de requête actuellement chargés en mémoire, ainsi que leurs statistiques d'utilisation. Utilisez la commande suivante :
dbms_outln.show_outline();Exemple :
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)Le tableau suivant décrit les colonnes HIT et OVERFLOW.
Paramètre
Description
HIT
Nombre de fois où ce plan de requête a été mis en correspondance.
OVERFLOW
Nombre de fois où ce plan de requête n'a pas trouvé le bloc de requête ou la table correspondante.
-
del_outline
Supprime un plan de requête de la mémoire et de la table
outline. Utilisez la commande suivante :dbms_outln.del_outline(<Id>);Exemple :
mysql> call dbms_outln.del_outline(32);RemarqueSi le plan que vous tentez de supprimer n'existe pas, le système renvoie un avertissement. Exécutez
show warnings;pour afficher les détails.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
Si vous modifiez directement la table
outline, exécutez cette commande pour appliquer les modifications. Utilisez la commande suivante :dbms_outln.flush_outline();Exemple :
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)
Vérification des plans de requête
Utilisez l'une des deux méthodes suivantes pour vérifier qu'un plan de requête est actif :
-
Utilisez
preview_outlinepour vérifier la correspondance.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) -
Utilisez
EXPLAINpour afficher le plan d'exécution.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)