Todos os produtos
Search
Central de documentação

PolarDB:Statement Outline

Última atualização: Jun 28, 2026

Quando os planos de execução mudam inesperadamente — devido ao crescimento de dados, desvio de estatísticas ou atualizações de versão — geralmente é necessário adicionar hints do otimizador diretamente no SQL. Se não for possível modificar o código da aplicação, o Statement Outline permite injetar esses hints sem alterar o SQL. Ele fixa o plano de execução para uma instrução específica ao corresponder a um digest SQL normalizado e reescrever a consulta com o hint configurado antes que o otimizador a processe.

O PolarDB fornece o pacote DBMS_OUTLN com stored procedures para adicionar, visualizar, inspecionar e excluir outlines.

Após adicionar um outline, verifique se ele funciona imediatamente. Execute CALL dbms_outln.preview_outline('<schema>', '<query>') — um resultado não vazio confirma que o outline correspondeu. Alternativamente, execute EXPLAIN na consulta alvo e verifique se a coluna Extra exibe Using outline <ID> .

Pré-requisitos

Antes de começar, certifique-se de ter:

  • Um cluster PolarDB for MySQL executando uma das seguintes versões:

    • PolarDB for MySQL 5.6 com versão secundária 5.6.1.0.36 ou posterior

    • PolarDB for MySQL 5.7 com versão secundária 5.7.1.0.2 ou posterior

    • PolarDB for MySQL 8.0.1 com versão secundária 8.0.1.1.1 ou posterior

    • PolarDB for MySQL 8.0.2

Para verificar a versão do seu cluster, consulte Visualizar o número da versão.

O PolarDB for MySQL 5.6 não suporta optimizer hints. Use add_index_outline (um index hint) para clusters da versão 5.6.

Como funciona

O Statement Outline intercepta uma instrução SQL correspondente e a reescreve com o hint configurado antes que o otimizador a processe. A correspondência baseia-se em um digest normalizado do texto SQL, opcionalmente restrito a um banco de dados específico:

  • Se Schema_name estiver definido, tanto o nome do banco de dados quanto o digest SQL devem corresponder à regra do outline.

  • Se Schema_name estiver em branco, apenas o digest SQL precisa corresponder.

Todos os hints são persistidos na tabela de sistema mysql.outline e carregados na memória durante a inicialização.

Escolha um tipo de outline

Outline de optimizer hint

Outline de index hint

Mecanismo

Injeta hints /*+ ... */ dentro da consulta

Anexa USE INDEX, FORCE INDEX ou IGNORE INDEX a uma referência de tabela

Controles

Ordem de junção, algoritmo de junção, comportamento do bloco de consulta, variáveis de sessão

Índice usado pelo otimizador para uma tabela específica

Suporte ao MySQL 5.6

Não

Sim

Procedimento

add_optimizer_outline

add_index_outline

Início rápido

Os exemplos a seguir mostram as operações de outline mais comuns. Todos usam a sintaxe CALL dbms_outln.<procedure>().

Fixar uma consulta com um optimizer hint

Force um índice específico usando um 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
);

Verifique se o outline correspondeu:

CALL dbms_outln.preview_outline('test', 'SELECT test.t1.a AS a FROM test.t1');

Fixar uma consulta com um index hint

Use add_index_outline para aplicar um hint USE INDEX. Esta abordagem funciona em clusters 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
);

Fixar a ordem de junção

Force it1 e it2 a se unirem primeiro, deixando o otimizador lidar com as tabelas 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'
);

Definir uma variável de sessão para uma única instrução

Aplique hints SET_VAR para substituir uma variável de sessão durante a execução de uma única instrução:

CALL dbms_outln.add_optimizer_outline(
  'test',
  '/*+ SET_VAR(max_execution_time=1) */',
  'SELECT * FROM t1'
);

Roteamento para nós somente leitura row-store ou columnstore

Em clusters com nós somente leitura In-Memory Columnar Index (IMCI), force o roteamento de instruções com 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');

Gerencie outlines

Adicionar um outline de optimizer hint

CALL dbms_outln.add_optimizer_outline('<Schema_name>', '<Hint>', '<Query>');

Parâmetro

Descrição

Schema_name

Nome do banco de dados. Deixe em branco para corresponder apenas pelo digest.

Hint

String completa do optimizer hint, como /*+ MAX_EXECUTION_TIME(1000) */.

Query

Instrução SQL original a ser fixada.

Quando Query contiver strings entre aspas duplas, envolva toda a Query em aspas duplas e use aspas simples internamente, ou vice-versa. Um outline criado com aspas simples em Query corresponde ao SQL independentemente do uso de aspas simples ou duplas na execução.

Exemplo: Fixar um limite de tempo de execução em uma consulta:

SQL original:

SELECT * FROM t1 WHERE name = "Tom";

Normalize as aspas para o outline:

SELECT * FROM t1 WHERE name = 'Tom';

Adicione o outline:

CALL dbms_outln.add_optimizer_outline("", "/*+ max_execution_time(1000) */", "SELECT * FROM t1 WHERE name='Tom'");

Adicionar um outline de index hint

CALL dbms_outln.add_index_outline('<Schema_name>', '<Digest>', <Position>, '<Type>', '<Hint>', '<Scope>', '<Query>');

Parâmetro

Descrição

Schema_name

Nome do banco de dados.

Digest

String de hash de 64 bytes obtida pelo hash de Digest_text. Deixe em branco para permitir que o sistema calcule a partir de Query. Consulte STATEMENT_DIGEST().

Position

Posição baseada em 1 da tabela à qual o hint se aplica. Para a N-ésima tabela no texto SQL, defina Position como N.

Type

Tipo de index hint: USE INDEX, FORCE INDEX ou IGNORE INDEX.

Hint

Lista separada por vírgulas de nomes de índices, como ind_1,ind_2.

Scope

Restringe o hint a um tipo de consulta: FOR JOIN, FOR ORDER BY ou FOR GROUP BY. Deixe em branco para aplicar a todos os tipos de consulta.

Query

Instrução SQL original a ser fixada.

Exemplo:

CALL dbms_outln.add_index_outline(
  'outline_db', '', 1, 'USE INDEX', 'ind_1', '',
  "SELECT * FROM t1 WHERE t1.col1 = 1 AND t1.col2 = 'xpchild'"
);

Visualize um outline

preview_outline mostra quais outlines correspondem a uma determinada consulta sem executá-la. Use este recurso para validar um outline antes de usá-lo em produção.

CALL dbms_outln.preview_outline('<Schema_name>', '<Query>');

Exemplo:

CALL dbms_outln.preview_outline('outline_db', "SELECT * FROM t1 WHERE t1.col1 = 1 AND t1.col2 = 'xpchild'");

Saída:

+------------+------------------------------------------------------------------+------------+------------+-------+---------------------+
| 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)

Visualize outlines ativos

show_outline lista todos os outlines atualmente carregados na memória, juntamente com as contagens de acertos e estouro.

CALL dbms_outln.show_outline();

Saída:

+------+------------+------------------------------------------------------------------+-----------+-------+------+-------------------------------------------------------+------+----------+-------------------------------------------------------------------------------------+
| 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: quantidade de vezes que este outline foi correspondido e aplicado.

  • OVERFLOW: número de vezes em que o outline não encontrou o bloco de consulta ou a tabela alvo na instrução.

Exclua um outline

CALL dbms_outln.del_outline(<Id>);

Informe o ID obtido em show_outline. O outline é removido imediatamente tanto da memória quanto da tabela de sistema mysql.outline.

Exemplo:

CALL dbms_outln.del_outline(32);

Se o ID não existir, o sistema registra um aviso em vez de um erro:

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 |
+---------+------+----------------------------------------------+

Verifique se um outline foi aplicado

Após adicionar um outline, confirme seu funcionamento com um destes 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'");

Um conjunto de resultados não vazio indica que o outline correspondeu.

Método 2: EXPLAIN

Execute EXPLAIN na consulta alvo. Se o outline foi aplicado, a coluna Extra inclui 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 |
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+------------------------------+
O texto Using outline <ID> em Extra aparece apenas nas versões:
PolarDB for MySQL 8.0.1 com versão secundária 8.0.1.0.34 ou posterior
PolarDB for MySQL 8.0.2 com versão secundária 8.0.2.2.27 ou posterior

Para ver o SQL reescrito, execute SHOW WARNINGS após o EXPLAIN:

SHOW WARNINGS;
+-------+------+----------------------------------------------------------+
| Level | Code | Message                                                  |
+-------+------+----------------------------------------------------------+
| Note  | 1003 | /* select#1 */ SELECT `outline_db`.`t1`.`id` AS `id`,... USE INDEX (`ind_1`) WHERE ... |
+-------+------+----------------------------------------------------------+

Sharding Outline

Em cenários de sharding de tabelas, as tabelas físicas seguem um padrão de sufixo numérico — t_001, t_002, ..., t_999. Um Statement Outline padrão corresponde apenas ao nome exato da tabela, exigindo uma regra separada por tabela. Em uma configuração grande de sharding, isso se torna inviável.

O Sharding Outline resolve esse problema tratando os números finais como um padrão curinga. Ele reconhece t_1, t_2 e t_100 como o único padrão t_?, permitindo que uma única regra cubra todas as tabelas correspondentes.

Outline Padrão

Sharding Outline

Correspondência de nome de tabela

Correspondência exata, ex.: t_1

Padrão curinga, ex.: t_?

Escopo

Uma tabela específica

Todas as tabelas fragmentadas com um padrão de nomenclatura consistente

Regras necessárias

Uma por tabela fragmentada

Uma regra para todas as tabelas correspondentes

Manutenção

Alta: criação, atualização e exclusão em lote

Baixa: uma única regra gerencia todas as tabelas correspondidas

Versões suportadas:

  • PolarDB for MySQL 8.0.1 com versão secundária 8.0.1.1.54 ou posterior

  • PolarDB for MySQL 8.0.2 com versão secundária 8.0.2.2.33 ou posterior

Ative o Sharding Outline

  1. No console do PolarDB, acesse Parameter Settings e defina loose_outline_templated_digest_for_sharding_table como ON. Para detalhes, consulte Definir parâmetros.

  2. Chame add_optimizer_outline_sharding usando qualquer nome de tabela fragmentada como Query. O procedimento transforma automaticamente os números finais no padrão t_?.

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
);

Após a execução, a regra se aplica a todas as tabelas que correspondem a t_? — incluindo t_1, t_2 e t_100.

Parâmetros

Configure o comportamento do Statement Outline no console do PolarDB em Parameter Settings. Consulte Definir parâmetros.

Parâmetro

Escopo

Descrição

loose_opt_outline_enabled

Global

Ativa ou desativa o Statement Outline. ON (padrão) ou OFF.

loose_outline_templated_digest_for_sharding_table

Sessão

Ativa ou desativa o Sharding Outline. ON (padrão) ou OFF. Requer PolarDB for MySQL 8.0.1 versão secundária 8.0.1.1.54 ou posterior, ou 8.0.2 versão secundária 8.0.2.2.33 ou posterior.

Apêndice: Tabela de sistema do Statement Outline

O PolarDB armazena todas as regras de outline em mysql.outline. A tabela é criada automaticamente na inicialização.

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

Descrição

Id

ID exclusivo do outline.

Schema_name

Nome do banco de dados. Vazio significa correspondência apenas por digest.

Digest

String de hash de 64 bytes obtida pelo hash de Digest_text. Consulte STATEMENT_DIGEST().

Digest_text

Forma normalizada da instrução SQL usada para cálculo do digest.

Type

OPTIMIZER para optimizer hints. USE INDEX, FORCE INDEX ou IGNORE INDEX para index hints.

Scope

Escopo do index hint: FOR JOIN, FOR ORDER BY ou FOR GROUP BY. String vazia aplica-se a todos os tipos de consulta. Usado apenas para index hints.

State

Indica se a regra está ativa. Y (padrão) ou N.

Position

Para optimizer hints: posição baseada em 1 do bloco de consulta alvo do hint. Para index hints: posição baseada em 1 da tabela no texto SQL.

Hint

Para optimizer hints: string completa do hint, ex.: /*+ MAX_EXECUTION_TIME(1000) */. Para index hints: lista separada por vírgulas de nomes de índices, ex.: ind_1,ind_2.