Cuando los planes de ejecución cambian de forma inesperada —por el crecimiento de los datos, la desviación de las estadísticas o las actualizaciones de versión—, normalmente es necesario agregar optimizer hints directamente en el SQL. Si no puede modificar el código de la aplicación, Statement Outline le permite inyectar esos hints sin tocar el SQL. Esta función fija el plan de ejecución de una instrucción específica: compara un digest de SQL normalizado y reescribe la consulta con el hint configurado antes de que el optimizador la procese.
PolarDB proporciona el paquete DBMS_OUTLN, que incluye procedimientos almacenados para agregar, previsualizar, inspeccionar y eliminar outlines.
Después de agregar un outline, compruebe de inmediato que funciona correctamente. EjecuteCALL dbms_outln.preview_outline('<schema>', '<query>'); si el resultado no está vacío, se confirma que el outline coincidió. También puede ejecutarEXPLAINsobre la consulta objetivo y revisar si la columnaExtramuestraUsing outline <ID>.
Requisitos previos
Antes de empezar, asegúrese de contar con lo siguiente:
-
Un clúster de PolarDB for MySQL que ejecute una de estas versiones:
PolarDB for MySQL 5.6 con la versión menor 5.6.1.0.36 o posterior
PolarDB for MySQL 5.7 con la versión menor 5.7.1.0.2 o posterior
PolarDB for MySQL 8.0.1 con la versión menor 8.0.1.1.1 o posterior
PolarDB for MySQL 8.0.2
Para consultar la versión de su clúster, consulte View the version number.
PolarDB for MySQL 5.6 no admite optimizer hints. En los clústeres con la versión 5.6, utilice add_index_outline (un index hint).
Cómo funciona
Statement Outline intercepta una instrucción SQL coincidente y la reescribe con el hint configurado antes de que el optimizador la procese. La coincidencia se basa en un digest normalizado del texto SQL, que de manera opcional se limita a una base de datos específica:
Si
Schema_nametiene un valor asignado, tanto el nombre de la base de datos como el digest de SQL deben coincidir con la regla del outline.Si
Schema_nameestá vacío, solo debe coincidir el digest de SQL.
Todos los hints se almacenan de forma persistente en la tabla del sistema mysql.outline y se cargan en memoria durante el inicio.
Elija un tipo de outline
|
Outline de optimizer hint |
Outline de index hint |
|
|
Mecanismo |
Inyecta hints |
Agrega |
|
Controla |
El orden de unión, el algoritmo de unión, el comportamiento del bloque de consulta y las variables de sesión |
El índice que utiliza el optimizador para una tabla específica |
|
Compatibilidad con MySQL 5.6 |
No |
Sí |
|
Procedimiento |
|
|
Inicio rápido
A continuación se muestran las operaciones de outline más comunes. Todos los ejemplos utilizan la sintaxis CALL dbms_outln.<procedure>().
Fije una consulta con un optimizer hint
Fuerce un índice específico mediante un optimizer hint:
CALL dbms_outln.add_optimizer_outline(
'test', -- Schema_name
'/*+ INDEX(t1 i_a) */', -- Hint string
'SELECT test.t1.a AS a FROM test.t1' -- Original SQL
);
Compruebe que el outline coincidió:
CALL dbms_outln.preview_outline('test', 'SELECT test.t1.a AS a FROM test.t1');
Fije una consulta con un index hint
Utilice add_index_outline para aplicar un hint USE INDEX. Este método es compatible con los clústeres de MySQL 5.6:
CALL dbms_outln.add_index_outline(
'outline_db', -- Schema_name
'', -- Digest (leave blank; the system calculates it from Query)
1, -- Position: the 1st table in the SQL
'USE INDEX', -- Type
'ind_1', -- Index name(s)
'', -- Scope (blank = all query types)
"SELECT * FROM t1 WHERE t1.col1 = 1 AND t1.col2 = 'xpchild'" -- Original SQL
);
Fije el orden de unión
Obligue a que it1 e it2 se unan primero. El optimizador se encarga de las tablas restantes:
CALL dbms_outln.add_optimizer_outline(
'outline_db',
'/*+ JOIN_PREFIX(it1, it2) */',
'SELECT it3.id3, it2.i2, it1.id2
FROM t3 it3, t1 it1, t2 it2
WHERE it3.i3 = it1.id1
AND it2.id2 = it1.id2
GROUP BY it3.id3, it1.id2'
);
Establezca una variable de sesión para una sola instrucción
Aplique hints SET_VAR para anular una variable de sesión durante la ejecución de una única instrucción:
CALL dbms_outln.add_optimizer_outline(
'test',
'/*+ SET_VAR(max_execution_time=1) */',
'SELECT * FROM t1'
);
Dirija el tráfico a nodos de solo lectura de almacenamiento por filas o columnstore
En los clústeres con nodos de solo lectura de In-Memory Columnar Index (IMCI), fuerce el enrutamiento de instrucciones con SET_VAR:
-- Force execution on columnstore (IMCI) read-only nodes
CALL dbms_outln.add_optimizer_outline('test', '/*+ SET_VAR(cost_threshold_for_imci=0) */', 'SELECT test.t1.a AS a FROM test.t1');
-- Force execution on row-store read-only nodes
CALL dbms_outln.add_optimizer_outline('test', '/*+ SET_VAR(use_imci_engine=OFF) */', 'SELECT test.t1.a AS a FROM test.t1');
Gestione los outlines
Agregue un outline de optimizer hint
CALL dbms_outln.add_optimizer_outline('<Schema_name>', '<Hint>', '<Query>');
|
Parámetro |
Descripción |
|
|
El nombre de la base de datos. Déjelo vacío para que la coincidencia se base únicamente en el digest. |
|
|
La cadena completa del optimizer hint, por ejemplo, |
|
|
La instrucción SQL original que desea fijar. |
CuandoQuerycontiene cadenas entre comillas dobles, encierre todo el valor deQueryentre comillas dobles y use comillas simples en el interior, o viceversa. Un outline creado con comillas simples enQuerycoincide con el SQL sin importar si lo ejecuta con comillas simples o dobles.
Ejemplo: fije un límite de tiempo de ejecución en una consulta:
SQL original:
SELECT * FROM t1 WHERE name = "Tom";
Normalice las comillas para el outline:
SELECT * FROM t1 WHERE name = 'Tom';
Agregue el outline:
CALL dbms_outln.add_optimizer_outline("", "/*+ max_execution_time(1000) */", "SELECT * FROM t1 WHERE name='Tom'");
Agregue un outline de index hint
CALL dbms_outln.add_index_outline('<Schema_name>', '<Digest>', <Position>, '<Type>', '<Hint>', '<Scope>', '<Query>');
|
Parámetro |
Descripción |
|
|
El nombre de la base de datos. |
|
|
Una cadena hash de 64 bytes que se obtiene al calcular el hash de |
|
|
La posición de la tabla a la que aplica el hint, con base 1. Para la N-ésima tabla del texto SQL, establezca |
|
|
El tipo de index hint: |
|
|
Una lista de nombres de índices separados por comas, por ejemplo, |
|
|
Restringe el hint a un tipo de consulta: |
|
|
La instrucción SQL original que desea fijar. |
Ejemplo:
CALL dbms_outln.add_index_outline(
'outline_db', '', 1, 'USE INDEX', 'ind_1', '',
"SELECT * FROM t1 WHERE t1.col1 = 1 AND t1.col2 = 'xpchild'"
);
Previsualice un outline
preview_outline muestra qué outlines coinciden con una consulta determinada sin ejecutarla. Utilícelo para validar un outline antes de implementarlo en producción.
CALL dbms_outln.preview_outline('<Schema_name>', '<Query>');
Ejemplo:
CALL dbms_outln.preview_outline('outline_db', "SELECT * FROM t1 WHERE t1.col1 = 1 AND t1.col2 = 'xpchild'");
Salida:
+------------+------------------------------------------------------------------+------------+------------+-------+---------------------+
| 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)
Consulte los outlines activos
show_outline enumera todos los outlines cargados actualmente en memoria, junto con los conteos de aciertos y desbordamientos.
CALL dbms_outln.show_outline();
Salida:
+------+------------+------------------------------------------------------------------+-----------+-------+------+-------------------------------------------------------+------+----------+-------------------------------------------------------------------------------------+
| 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` = ? |
+------+------------+------------------------------------------------------------------+-----------+-------+------+-------------------------------------------------------+------+----------+-------------------------------------------------------------------------------------+
HIT: el número de veces que este outline coincidió y se aplicó.OVERFLOW: el número de veces que el outline no encontró el bloque de consulta o la tabla objetivo en la instrucción.
Elimine un outline
CALL dbms_outln.del_outline(<Id>);
Pase el valor de ID obtenido en show_outline. El outline se elimina de inmediato tanto de la memoria como de la tabla del sistema mysql.outline.
Ejemplo:
CALL dbms_outln.del_outline(32);
Si el ID no existe, el sistema registra una advertencia en lugar de un error:
CALL dbms_outln.del_outline(1000);
-- Query OK, 0 rows affected, 2 warnings (0.00 sec)
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 |
+---------+------+----------------------------------------------+
Compruebe que se aplicó un outline
Después de agregar un outline, confirme que funciona correctamente con cualquiera de estos métodos.
Método 1: preview_outline (recomendado)
CALL dbms_outln.preview_outline('outline_db', "SELECT * FROM t1 WHERE t1.col1 = 1 AND t1.col2 = 'xpchild'");
Un conjunto de resultados no vacío indica que el outline coincidió.
Método 2: EXPLAIN
Ejecute EXPLAIN sobre la consulta objetivo. Si se aplicó el outline, la columna Extra incluye Using outline <ID>.
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; Using outline 1 |
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+------------------------------+
El textoUsing outline <ID>en la columnaExtraaparece únicamente en:
PolarDB for MySQL 8.0.1 con la versión menor 8.0.1.0.34 o posterior
PolarDB for MySQL 8.0.2 con la versión menor 8.0.2.2.27 o posterior
Para ver el SQL reescrito, ejecute SHOW WARNINGS después de EXPLAIN:
SHOW WARNINGS;
+-------+------+----------------------------------------------------------+
| Level | Code | Message |
+-------+------+----------------------------------------------------------+
| Note | 1003 | /* select#1 */ SELECT `outline_db`.`t1`.`id` AS `id`,... USE INDEX (`ind_1`) WHERE ... |
+-------+------+----------------------------------------------------------+
Sharding Outline
En escenarios de fragmentación de tablas, las tablas físicas siguen un patrón de sufijo numérico: t_001, t_002, ..., t_999. Un Statement Outline estándar coincide solo con el nombre exacto de la tabla, por lo que requiere una regla independiente por cada tabla. En una configuración de fragmentación grande, esto resulta difícil de gestionar.
Sharding Outline resuelve este problema al tratar los números finales como un patrón comodín. Reconoce t_1, t_2 y t_100 como el único patrón t_?, de modo que una sola regla cubre todas las tablas coincidentes.
|
Outline estándar |
Sharding Outline |
|
|
Coincidencia de nombre de tabla |
Coincidencia exacta, por ejemplo, |
Patrón comodín, por ejemplo, |
|
Alcance |
Una tabla específica |
Todas las tablas fragmentadas con un patrón de nomenclatura consistente |
|
Reglas necesarias |
Una por cada tabla fragmentada |
Una regla para todas las tablas coincidentes |
|
Mantenimiento |
Alto: creación, actualización y eliminación por lotes |
Bajo: una sola regla gestiona todas las tablas coincidentes |
Versiones compatibles:
PolarDB for MySQL 8.0.1 con la versión menor 8.0.1.1.54 o posterior
PolarDB for MySQL 8.0.2 con la versión menor 8.0.2.2.33 o posterior
Habilite Sharding Outline
En la consola de PolarDB, vaya a Parameter Settings y establezca
loose_outline_templated_digest_for_sharding_tableenON. Para obtener más información, consulte Set parameters.Llame a
add_optimizer_outline_shardingy pase cualquier nombre de tabla fragmentada comoQuery. El procedimiento convierte automáticamente los números finales en el patrónt_?.
CALL dbms_outln.add_optimizer_outline_sharding(
'test', -- Schema_name
'', -- Digest (leave blank)
1, -- Position
'/*+ MAX_EXECUTION_TIME(1000) */', -- Hint string
"SELECT t_1.c_1 FROM t_1" -- Any sharded table name works: t_1, t_2, t_100
);
Tras la ejecución, la regla se aplica a todas las tablas que coinciden con t_?, incluidas t_1, t_2 y t_100.
Parámetros
Configure el comportamiento de Statement Outline en la consola de PolarDB, dentro de Parameter Settings. Consulte Set parameters.
|
Parámetro |
Alcance |
Descripción |
|
|
Global |
Habilita o deshabilita Statement Outline. |
|
|
Session |
Habilita o deshabilita Sharding Outline. |
Apéndice: tabla del sistema de Statement Outline
PolarDB almacena todas las reglas de outline en mysql.outline. Esta tabla se crea automáticamente durante el inicio.
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`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Statement outline'
|
Campo |
Descripción |
|
|
El ID único del outline. |
|
|
El nombre de la base de datos. Si está vacío, la coincidencia se basa únicamente en el digest. |
|
|
Cadena hash de 64 bytes que se obtiene al calcular el hash de |
|
|
La forma normalizada de la instrucción SQL que se usa para calcular el digest. |
|
|
|
|
|
El alcance del index hint: |
|
|
Indica si la regla está activa. |
|
|
Para optimizer hints: la posición del bloque de consulta al que apunta el hint, con base 1. Para index hints: la posición de la tabla en el texto SQL, con base 1. |
|
|
Para optimizer hints: la cadena completa del hint, por ejemplo, |