Compatibilidade ao particionamento de tabelas - Amazon Aurora

Compatibilidade ao particionamento de tabelas

O gerenciamento de planos de consulta (QPM) do Aurora PostgreSQL comporta o particionamento de tabelas nas seguintes versões:

  • 15.3 e versões 15 posteriores

  • 14.8 e versões 14 posteriores

  • 13.11 e versões 13 posteriores

Para obter mais informações, consulte Particionamento de tabelas.

Configurar o particionamento de tabelas

Para configurar o particionamento de tabelas no QPM do Aurora PostgreSQL, faça o seguinte:

  1. Defina apg_plan_mgmt.plan_hash_version como 3 ou mais no grupo de parâmetros do cluster de banco de dados.

  2. Navegue até um banco de dados que usa o Gerenciamento de Planos de Consulta e que tem entradas na visualização de apg_plan_mgmt.dba_plans.

  3. Ligue para apg_plan_mgmt.validate_plans('update_plan_hash') a fim de atualizar o valor de plan_hash na tabela de planos.

  4. Repita as etapas 2 e 3 para todos os bancos de dados com o Gerenciamento de Planos de Consulta ativado e que tenham entradas na visualização apg_plan_mgmt.dba_plans.

Para obter mais informações sobre esses parâmetros, consulte Referência de parâmetros do gerenciamento de planos de consultas do Aurora PostgreSQL.

Capturar planos para o particionamento de tabelas

No QPM, planos diferentes são diferenciados pelo valor de plan_hash. Para entender como plan_hash muda, primeiro é necessário conhecer tipos semelhantes de planos.

A combinação de métodos de acesso, nomes de índice sem dígitos e nomes de partição sem dígitos, acumulados no nó de anexação, deve ser constante para que os planos sejam considerados iguais. As partições específicas acessadas nos planos não são significativas. No exemplo a seguir, uma tabela tbl_a é criada com quatro partições.

postgres=>create table tbl_a(i int, j int, k int, l int, m int) partition by range(i); CREATE TABLE postgres=>create table tbl_a1 partition of tbl_a for values from (0) to (1000); CREATE TABLE postgres=>create table tbl_a2 partition of tbl_a for values from (1001) to (2000); CREATE TABLE postgres=>create table tbl_a3 partition of tbl_a for values from (2001) to (3000); CREATE TABLE postgres=>create table tbl_a4 partition of tbl_a for values from (3001) to (4000); CREATE TABLE postgres=>create index t_i on tbl_a using btree (i); CREATE INDEX postgres=>create index t_j on tbl_a using btree (j); CREATE INDEX postgres=>create index t_k on tbl_a using btree (k); CREATE INDEX

Os planos a seguir são considerados iguais porque um único método de varredura está sendo usado para analisar tbl_a, independentemente do número de partições que a consulta procura.

postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 999 and j < 9910 and k > 50; QUERY PLAN ------------------------------------------------------------------- Seq Scan on tbl_a1 tbl_a Filter: ((i >= 990) AND (i <= 999) AND (j < 9910) AND (k > 50)) SQL Hash: 1553185667, Plan Hash: -694232056 (3 rows)
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50; QUERY PLAN ------------------------------------------------------------------- Append -> Seq Scan on tbl_a1 tbl_a_1 Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50)) -> Seq Scan on tbl_a2 tbl_a_2 Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50)) SQL Hash: 1553185667, Plan Hash: -694232056 (6 rows)
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50; QUERY PLAN -------------------------------------------------------------------------- Append -> Seq Scan on tbl_a1 tbl_a_1 Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50)) -> Seq Scan on tbl_a2 tbl_a_2 Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50)) -> Seq Scan on tbl_a3 tbl_a_3 Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50)) SQL Hash: 1553185667, Plan Hash: -694232056 (8 rows)

Os três planos a seguir também são considerados iguais porque, no nível pai, os métodos de acesso, os nomes de índice sem dígitos e os nomes de partição sem dígitos são SeqScan tbl_a, IndexScan (i_idx) tbl_a.

postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50; QUERY PLAN -------------------------------------------------------------------------- Append -> Seq Scan on tbl_a1 tbl_a_1 Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50)) -> Index Scan using tbl_a2_i_idx on tbl_a2 tbl_a_2 Index Cond: ((i >= 990) AND (i <= 1100)) Filter: ((j < 9910) AND (k > 50)) SQL Hash: 1553185667, Plan Hash: -993736942 (7 rows)
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50; QUERY PLAN -------------------------------------------------------------------------- Append -> Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1 Index Cond: ((i >= 990) AND (i <= 2100)) Filter: ((j < 9910) AND (k > 50)) -> Seq Scan on tbl_a2 tbl_a_2 Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50)) -> Index Scan using tbl_a3_i_idx on tbl_a3 tbl_a_3 Index Cond: ((i >= 990) AND (i <= 2100)) Filter: ((j < 9910) AND (k > 50)) SQL Hash: 1553185667, Plan Hash: -993736942 (10 rows)
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 3100 and j < 9910 and k > 50; QUERY PLAN -------------------------------------------------------------------------- Append -> Seq Scan on tbl_a1 tbl_a_1 Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50)) -> Seq Scan on tbl_a2 tbl_a_2 Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50)) -> Seq Scan on tbl_a3 tbl_a_3 Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50)) -> Index Scan using tbl_a4_i_idx on tbl_a4 tbl_a_4 Index Cond: ((i >= 990) AND (i <= 3100)) Filter: ((j < 9910) AND (k > 50)) SQL Hash: 1553185667, Plan Hash: -993736942 (11 rows)

Independentemente da diferença de ordem e número de ocorrências nas partições filho, os métodos de acesso, os nomes de índice sem dígitos e os nomes de partição sem dígitos são constantes no nível pai de cada um dos planos acima.

No entanto, os planos seriam considerados diferentes se alguma das condições a seguir fosse atendida:

  • Algum método de acesso adicional é usado no plano.

    postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50; QUERY PLAN -------------------------------------------------------------------------- Append -> Seq Scan on tbl_a1 tbl_a_1 Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50)) -> Seq Scan on tbl_a2 tbl_a_2 Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50)) -> Bitmap Heap Scan on tbl_a3 tbl_a_3 Recheck Cond: ((i >= 990) AND (i <= 2100)) Filter: ((j < 9910) AND (k > 50)) -> Bitmap Index Scan on tbl_a3_i_idx Index Cond: ((i >= 990) AND (i <= 2100)) SQL Hash: 1553185667, Plan Hash: 1134525070 (11 rows)
  • Um dos métodos de acesso do plano não é mais usado.

    postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50; QUERY PLAN -------------------------------------------------------------------------- Append -> Seq Scan on tbl_a1 tbl_a_1 Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50)) -> Seq Scan on tbl_a2 tbl_a_2 Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50)) SQL Hash: 1553185667, Plan Hash: -694232056 (6 rows)
  • O índice associado a um método de indexação é alterado.

    postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50; QUERY PLAN -------------------------------------------------------------------------- Append -> Seq Scan on tbl_a1 tbl_a_1 Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50)) -> Index Scan using tbl_a2_j_idx on tbl_a2 tbl_a_2 Index Cond: (j < 9910) Filter: ((i >= 990) AND (i <= 1100) AND (k > 50)) SQL Hash: 1553185667, Plan Hash: -993343726 (7 rows)

Aplicar um plano de particionamento de tabelas

Os planos aprovados para tabelas particionadas são aplicados com correspondência posicional. Os planos não são específicos para as partições e podem ser aplicados em partições diferentes dos planos referenciados na consulta original. Os planos também podem ser aplicados para consultas que acessam um número diferente de partições em comparação com o esquema original aprovado.

Por exemplo, se o esquema aprovado for para o seguinte plano:

postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50; QUERY PLAN -------------------------------------------------------------------------- Append -> Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1 Index Cond: ((i >= 990) AND (i <= 2100)) Filter: ((j < 9910) AND (k > 50)) -> Seq Scan on tbl_a2 tbl_a_2 Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50)) -> Index Scan using tbl_a3_i_idx on tbl_a3 tbl_a_3 Index Cond: ((i >= 990) AND (i <= 2100)) Filter: ((j < 9910) AND (k > 50)) SQL Hash: 1553185667, Plan Hash: -993736942 (10 rows)

Depois, esse plano também pode ser aplicado em consultas SQL que fazem referência a duas, quatro ou mais partições. Os planos que poderiam surgir desses cenários para acessar duas e quatro partições são:

postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50; QUERY PLAN ---------------------------------------------------------------------------------- Append -> Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1 Index Cond: ((i >= 990) AND (i <= 1100)) Filter: ((j < 9910) AND (k > 50)) -> Seq Scan on tbl_a2 tbl_a_2 Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50)) Note: An Approved plan was used instead of the minimum cost plan. SQL Hash: 1553185667, Plan Hash: -993736942, Minimum Cost Plan Hash: -1873216041 (8 rows)
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 3100 and j < 9910 and k > 50; QUERY PLAN -------------------------------------------------------------------------- Append -> Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1 Index Cond: ((i >= 990) AND (i <= 3100)) Filter: ((j < 9910) AND (k > 50)) -> Seq Scan on tbl_a2 tbl_a_2 Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50)) -> Index Scan using tbl_a3_i_idx on tbl_a3 tbl_a_3 Index Cond: ((i >= 990) AND (i <= 3100)) Filter: ((j < 9910) AND (k > 50)) -> Seq Scan on tbl_a4 tbl_a_4 Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50)) Note: An Approved plan was used instead of the minimum cost plan. SQL Hash: 1553185667, Plan Hash: -993736942, Minimum Cost Plan Hash: -1873216041 (12 rows)
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 3100 and j < 9910 and k > 50; QUERY PLAN ---------------------------------------------------------------------------------- Append -> Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1 Index Cond: ((i >= 990) AND (i <= 3100)) Filter: ((j < 9910) AND (k > 50)) -> Seq Scan on tbl_a2 tbl_a_2 Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50)) -> Index Scan using tbl_a3_i_idx on tbl_a3 tbl_a_3 Index Cond: ((i >= 990) AND (i <= 3100)) Filter: ((j < 9910) AND (k > 50)) -> Index Scan using tbl_a4_i_idx on tbl_a4 tbl_a_4 Index Cond: ((i >= 990) AND (i <= 3100)) Filter: ((j < 9910) AND (k > 50)) Note: An Approved plan was used instead of the minimum cost plan. SQL Hash: 1553185667, Plan Hash: -993736942, Minimum Cost Plan Hash: -1873216041 (14 rows)

Considere outro plano aprovado com métodos de acesso diferentes para cada partição:

postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50; QUERY PLAN -------------------------------------------------------------------------- Append -> Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1 Index Cond: ((i >= 990) AND (i <= 2100)) Filter: ((j < 9910) AND (k > 50)) -> Seq Scan on tbl_a2 tbl_a_2 Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50)) -> Bitmap Heap Scan on tbl_a3 tbl_a_3 Recheck Cond: ((i >= 990) AND (i <= 2100)) Filter: ((j < 9910) AND (k > 50)) -> Bitmap Index Scan on tbl_a3_i_idx Index Cond: ((i >= 990) AND (i <= 2100)) SQL Hash: 1553185667, Plan Hash: 2032136998 (12 rows)

Nesse caso, qualquer plano que leia de duas partições não seria aplicado. A menos que todas as combinações (método de acesso, nome de índice) do plano aprovado sejam utilizáveis, o plano não pode ser aplicado. Por exemplo, os planos a seguir têm hashes de plano diferentes e o plano aprovado não pode ser aplicado nesses casos:

postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1900 and j < 9910 and k > 50; QUERY PLAN ------------------------------------------------------------------------- Append -> Bitmap Heap Scan on tbl_a1 tbl_a_1 Recheck Cond: ((i >= 990) AND (i <= 1900)) Filter: ((j < 9910) AND (k > 50)) -> Bitmap Index Scan on tbl_a1_i_idx Index Cond: ((i >= 990) AND (i <= 1900)) -> Bitmap Heap Scan on tbl_a2 tbl_a_2 Recheck Cond: ((i >= 990) AND (i <= 1900)) Filter: ((j < 9910) AND (k > 50)) -> Bitmap Index Scan on tbl_a2_i_idx Index Cond: ((i >= 990) AND (i <= 1900)) Note: This is not an Approved plan. No usable Approved plan was found. SQL Hash: 1553185667, Plan Hash: -568647260 (13 rows)
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1900 and j < 9910 and k > 50; QUERY PLAN -------------------------------------------------------------------------- Append -> Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1 Index Cond: ((i >= 990) AND (i <= 1900)) Filter: ((j < 9910) AND (k > 50)) -> Seq Scan on tbl_a2 tbl_a_2 Filter: ((i >= 990) AND (i <= 1900) AND (j < 9910) AND (k > 50)) Note: This is not an Approved plan. No usable Approved plan was found. SQL Hash: 1553185667, Plan Hash: -496793743 (8 rows)

Convenção de nomenclatura

Para que o QPM aplique um plano com tabelas particionadas declarativas, é necessário seguir regras de nomenclatura específicas para tabelas principais, partições de tabelas e índices:

  • Nomes de tabelas principais: esses nomes devem ser diferenciados por caracteres alfabéticos ou especiais, e não apenas por dígitos. Por exemplo, tA, tB e tC são nomes aceitáveis para tabelas pais distintas, enquanto t1, t2 e t3 não são.

  • Nomes de tabelas de partição individuais: partições da mesma tabela principal devem diferir umas das outras somente por dígitos. Por exemplo, nomes de partição aceitáveis para tA podem ser tA1 e tA2, t1A e t2A, ou até mesmo vários dígitos.

    Quaisquer outras diferenças (letras, caracteres especiais) não garantirão a aplicação do plano.

  • Nomes dos índices: na hierarquia das tabelas de partições, todos os índices deverão ter nomes exclusivos. Isso significa que as partes não numéricas dos nomes devem ser diferentes. Por exemplo, se você tiver uma tabela particionada denominada tA com um índice chamado tA_col1_idx1, não poderá ter outro índice denominado tA_col1_idx2. No entanto, é possível ter um índice denominado tA_a_col1_idx2 porque a parte não numérica do nome é exclusiva. Essa regra aplica-se aos índices criados na tabela principal e nas tabelas de partição individuais.

O não cumprimento das convenções de nomenclatura acima pode resultar na falha na aplicação dos planos aprovados. O exemplo a seguir ilustra essa falha de aplicação:

postgres=>create table t1(i int, j int, k int, l int, m int) partition by range(i); CREATE TABLE postgres=>create table t1a partition of t1 for values from (0) to (1000); CREATE TABLE postgres=>create table t1b partition of t1 for values from (1001) to (2000); CREATE TABLE postgres=>SET apg_plan_mgmt.capture_plan_baselines TO 'manual'; SET postgres=>explain (hashes true, costs false) select count(*) from t1 where i > 0; QUERY PLAN -------------------------------------------------------------------------- Aggregate -> Append -> Seq Scan on t1a t1_1 Filter: (i > 0) -> Seq Scan on t1b t1_2 Filter: (i > 0) SQL Hash: -1720232281, Plan Hash: -1010664377 (7 rows)
postgres=>SET apg_plan_mgmt.use_plan_baselines TO 'on'; SET postgres=>explain (hashes true, costs false) select count(*) from t1 where i > 1000; QUERY PLAN ------------------------------------------------------------------------- Aggregate -> Seq Scan on t1b t1 Filter: (i > 1000) Note: This is not an Approved plan. No usable Approved plan was found. SQL Hash: -1720232281, Plan Hash: 335531806 (5 rows)

Embora os dois planos pareçam idênticos, os valores Plan Hash são diferentes devido aos nomes das tabelas secundárias. Os nomes das tabelas variam de acordo com caracteres alfa, em vez de apenas dígitos, o que ocasiona uma falha de imposição.