

# Ler os planos EXPLAIN do Aurora DSQL
<a name="reading-dsql-explain-plans"></a>

Entender como ler os planos EXPLAIN é fundamental para otimizar a performance das consultas. Nesta seção, vamos examinar exemplos reais de planos de consulta do Aurora DSQL, mostrar como os diferentes tipos de verificação se comportam, explicar onde os filtros são aplicados e destacar as oportunidades de otimização.

## Tabelas de amostra usadas nesses exemplos
<a name="explain-plan-sample-tables"></a>

Os exemplos abaixo fazem referência a duas tabelas: `transaction` e `account`.

A tabela `transaction` não tem uma chave primária, o que faz com que o Aurora DSQL realize varreduras completas da tabela ao consultá-la.

A tabela `account` tem um índice no `customer_id`. Esse índice inclui `balance` e `status` como colunas de cobertura, o que permite que determinadas consultas sejam atendidas diretamente do índice sem serem lidas na tabela base. No entanto, o índice não inclui `created_at`, portanto, as consultas que fazem referência a essa coluna exigem acesso adicional à tabela.

```
CREATE TABLE transaction (
    account_id uuid,
    transaction_date timestamp,
    description text
);

CREATE TABLE account (
    customer_id uuid,
    balance numeric,
    status varchar,
    created_at timestamp
);

CREATE INDEX ASYNC idx1 ON account (customer_id) INCLUDE (balance, status);
```

## Exemplo de verificação completa
<a name="full-scan-example"></a>

O Aurora DSQL tem tanto verificações sequenciais, que são funcionalmente idênticas ao PostgreSQL, quanto verificações completas. A única diferença entre elas é que as verificações completas podem utilizar filtragem extra no armazenamento. Por isso, quase sempre ela é selecionada em detrimento de verificações sequenciais. Devido à semelhança, abordaremos apenas exemplos das verificações completas mais interessantes.

As verificações completas serão usadas principalmente em tabelas sem chave primária. Como as chaves primárias do Aurora DSQL são, por padrão, índices de cobertura completa, o Aurora DSQL provavelmente usará verificações somente de índice na chave primária em muitas situações em que o PostgreSQL usaria uma verificação sequencial. Como acontece com a maioria dos outros bancos de dados, uma tabela sem índices será mal escalada.

```
EXPLAIN SELECT account_id FROM transaction WHERE transaction_date > '2025-01-01' AND description LIKE '%external%';
```

```
                                                   QUERY PLAN
----------------------------------------------------------------------------------------------------------------
 Full Scan (btree-table) on transaction  (cost=125100.05..177933.38 rows=33333 width=16)
   Filter: (description ~~ '%external%'::text)
   -> Storage Scan on transaction (cost=12510.05..17793.38 rows=66666 width=16)
        Projections: account_id, description
        Filters: (transaction_date > '2025-01-01 00:00:00'::timestamp without time zone)
        -> B-Tree Scan on transaction (cost=12510.05..17793.38 rows=100000 width=30)
```

Esse plano mostra dois filtros aplicados em diferentes estágios. A condição `transaction_date > '2025-01-01'` é aplicada na camada de armazenamento, reduzindo o volume de dados exibidos. A condição `description LIKE '%external%'` é aplicada posteriormente no processador de consultas, após a transferência dos dados, tornando-a menos eficiente. Colocar filtros mais seletivos nas camadas de armazenamento ou índice geralmente melhora a performance.

## Exemplo de verificação somente de índice
<a name="index-only-scan-example"></a>

As verificações somente de índice são os melhores tipos de verificação no Aurora DSQL, pois geram o menor número de idas e vindas até a camada de armazenamento e podem realizar a maior parte da filtragem. Mas só porque você vê “verificação somente de índice” não significa que tenha o melhor plano. Por conta de todos os diferentes níveis de filtragem que podem ocorrer, é essencial ainda prestar atenção aos diferentes locais em que a filtragem pode acontecer.

```
EXPLAIN SELECT balance FROM account 
WHERE customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb' 
AND balance > 100 
AND status = 'pending';
```

```
                                  QUERY PLAN
-------------------------------------------------------------------------------
 Index Only Scan using idx1 on account  (cost=725.05..1025.08 rows=8 width=18)
   Index Cond: (customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb'::uuid)
   Filter: (balance > '100'::numeric)
   -> Storage Scan on idx1 (cost=12510.05..17793.38 rows=9 width=16)
        Projections: balance
        Filters: ((status)::text = 'pending'::text)
        -> B-Tree Scan on idx1 (cost=12510.05..17793.38 rows=10 width=30)
            Index Cond: (customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb'::uuid)
```

Nesse plano, a condição de índice, `customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb'`, é avaliada primeiro durante a verificação do índice, que é o estágio mais eficiente porque limita o volume de dados lidos do armazenamento. O filtro de armazenamento, `status = 'pending'`, é aplicado após a leitura dos dados, mas antes de serem enviados para a camada computacional, reduzindo o volume de dados transferidos. Por fim, o filtro do processador de consultas, `balance > 100`, é executado por último, após a movimentação dos dados, tornando-o o menos eficiente. Dessas, a condição de índice oferece a melhor performance porque controla diretamente o volume de dados verificados.

## Exemplo de verificação de índice
<a name="index-scan-example"></a>

As verificações de índice são semelhantes às verificações somente de índice, exceto que elas têm a etapa extra de exigir o acesso à tabela base. Como o Aurora DSQL pode especificar filtros de armazenamento, ele pode fazer isso tanto na chamada de índice quanto na chamada de pesquisa.

Para deixar isso claro, o Aurora DSQL apresenta o plano como dois nós. Dessa forma, é possível ver claramente o quanto a adição de uma coluna de inclusão ajudará em termos de linhas exibidas do armazenamento.

```
EXPLAIN SELECT balance FROM account 
WHERE customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb'
AND balance > 100 
AND status = 'pending' 
AND created_at > '2025-01-01';
```

```
                                                QUERY PLAN
----------------------------------------------------------------------------------------------------------
 Index Scan using idx1 on account  (cost=728.18..1132.20 rows=3 width=18)
   Filter: (balance > '100'::numeric)
   Index Cond: (customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb'::uuid)
   -> Storage Scan on idx1 (cost=12510.05..17793.38 rows=8 width=16)
        Projections: balance
        Filters: ((status)::text = 'pending'::text)
        -> B-Tree Scan on account (cost=12510.05..17793.38 rows=10 width=30)
            Index Cond: (customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb'::uuid)
   -> Storage Lookup on account (cost=12510.05..17793.38 rows=4 width=16)
        Filters: (created_at > '2025-01-01 00:00:00'::timestamp without time zone)
        -> B-Tree Lookup on transaction (cost=12510.05..17793.38 rows=8 width=30)
```

 Esse plano mostra como a filtragem ocorre em vários estágios: 
+  A condição de índice em `customer_id ` filtra os dados com antecedência. 
+ O filtro de armazenamento em `status` restringe ainda mais os resultados antes que eles sejam enviados para computação. 
+ O filtro do processador de consultas em `balance` é aplicado posteriormente, após a transferência.
+ O filtro de pesquisa em `created_at` é avaliado ao buscar colunas adicionais da tabela base. 

Adicionar colunas usadas com frequência como campos `INCLUDE` geralmente pode eliminar essa pesquisa e melhorar a performance. 

## Práticas recomendadas
<a name="best-practices"></a>
+ **Alinhe os filtros com as colunas indexadas** para enviar a filtragem mais cedo.
+ **Use as colunas INCLUDE** para permitir verificações somente de índice e evitar pesquisas.
+ **Valide as estimativas de linha** ao investigar problemas de desempenho. O Aurora DSQL gerencia estatísticas automaticamente executando `ANALYZE` em segundo plano com base nas taxas de alteração de dados. Se as estimativas parecerem imprecisas, você pode executar `ANALYZE` manualmente para atualizar as estatísticas imediatamente.
+ **Evite consultas não indexadas** em tabelas grandes para evitar verificações completas dispendiosas.