Otimizar consultas
Use as técnicas de otimização de consulta descritas nesta seção para fazer com que as consultas sejam executadas mais rapidamente ou como soluções alternativas para consultas que excedam os limites de recursos no Athena.
Otimizar junções
Há muitas estratégias diferentes para executar junções em um mecanismo de consulta distribuído. Duas das mais comuns são as junções hash distribuídas e as consultas com condições de junção complexas.
Em uma junção de hash distribuída, coloque tabelas grandes à esquerda e tabelas pequenas à direita
O tipo mais comum de junção usa uma comparação de igualdade como condição de junção. O Athena executa esse tipo de junção como uma junção hash distribuída.
Em uma junção hash distribuída, o mecanismo cria uma tabela de pesquisa (tabela hash) com base em um dos lados da junção. Esse lado é chamado de lado da compilação. Os registros do lado da compilação são distribuídos entre os nós. Cada nó cria uma tabela de pesquisa para o respectivo subconjunto. O outro lado da junção, denominado lado de teste, é então transmitido pelos nós. Os registros do lado de teste são distribuídos pelos nós da mesma forma que no lado da compilação. Isso permite que cada nó realize a junção pesquisando os registros correspondentes em sua própria tabela de pesquisa.
Quando as tabelas de pesquisa criadas do lado da compilação da junção não cabem na memória, as consultas podem falhar. Mesmo que o tamanho total do lado da compilação seja menor que a memória disponível, as consultas poderão falhar se a distribuição dos registros tiver uma distorção significativa. Em um caso extremo, todos os registros poderiam ter o mesmo valor para a condição de junção e caber na memória em um único nó. Mesmo uma consulta com menos distorção poderá falhar se um conjunto de valores for enviado ao mesmo nó e a soma dos valores ultrapassar a memória disponível. Os nós têm a capacidade de vazar registros para o disco, mas o vazamento retarda a execução da consulta e pode ser insuficiente para evitar que a consulta falhe.
O Athena tenta reordenar as junções para usar a relação maior como lado de teste e a relação menor como o lado da compilação. No entanto, por não gerenciar os dados em tabelas, o Athena tem informações limitadas e muitas vezes deve presumir que a primeira tabela é a maior e a segunda tabela é a menor.
Ao gravar junções com condições de junção baseadas em igualdade, suponha que a tabela à esquerda da palavra-chave JOIN
seja o lado de teste e que a tabela à direita seja o lado da compilação. Verifique se a tabela direita, o lado da compilação, é a menor das tabelas. Se não for possível diminuir o lado da compilação da junção o suficiente para caber na memória, considere executar várias consultas que unam subconjuntos da tabela de compilação.
Usar EXPLAIN para analisar consultas com junções complexas
Consultas com condições de junção complexas (por exemplo, consultas que usam LIKE
, >
ou outros operadores) geralmente demandam muito computacionalmente. Na pior das hipóteses, cada registro de um lado da junção deve ser comparado a todos os registros do outro lado da junção. Como o tempo de execução aumenta com o quadrado do número de registros, as consultas correm o risco de exceder o tempo máximo de execução.
Para descobrir como o Athena executará sua consulta com antecedência, você pode usar a instrução EXPLAIN
. Para ter mais informações, consulte Usar EXPLAIN e EXPLAIN ANALYZE no Athena e Noções básicas dos resultados da instrução EXPLAIN do Athena.
Reduzir o escopo das funções da janela ou removê-las
Por serem operações que fazem uso intensivo de recursos, as funções de janela podem fazer com que as consultas sejam executadas lentamente ou até mesmo falhem com a mensagem Query exhausted resources at this scale factor
. As funções de janela mantêm todos os registros em que operam na memória para calcular o resultado. Quando a janela é muito grande, a função de janela pode ficar sem memória.
Para garantir que suas consultas sejam executadas dentro dos limites de memória disponíveis, reduza o tamanho das janelas em que suas funções de janela operam. Para fazer isso, adicione uma cláusula PARTITIONED BY
ou restrinja o escopo das cláusulas de particionamento existentes.
Usar de funções que não são de janela
Às vezes, consultas com funções de janela podem ser gravadas sem funções de janela. Por exemplo, em vez de usar row_number
para encontrar os principais registros N
, você pode usar ORDER BY
e LIMIT
. Em vez de usar row_number
ou rank
para desduplicar registros, você pode usar funções agregadas como max_by
Por exemplo, digamos que você tenha um conjunto de dados com atualizações de um sensor. O sensor informa periodicamente o status da bateria e inclui alguns metadados, como localização. Para saber o último status da bateria de cada sensor e sua localização, você pode usar esta consulta:
SELECT sensor_id, arbitrary(location) AS location, max_by(battery_status, updated_at) AS battery_status FROM sensor_readings GROUP BY sensor_id
Os metadados, como a localização, são os mesmos para cada registro, então você pode usar a função arbitrary
para escolher qualquer valor do grupo.
Para obter o último status da bateria, você pode usar a função max_by
. A função max_by
escolhe o valor de uma coluna do registro em que o valor máximo de outra coluna foi encontrado. Nesse caso, ela retorna o status da bateria do registro com a hora da última atualização dentro do grupo. Essa consulta é executada mais rapidamente e usa menos memória do que uma consulta equivalente com função de janela.
Otimizar agregações
Ao realizar uma agregação, o Athena distribui os registros entre os nós de processamento usando as colunas na cláusula GROUP BY
. Para tornar a tarefa de combinar registros com grupos o mais eficiente possível, os nós tentam manter os registros na memória, mas os vazam para o disco, se necessário.
Também é uma boa ideia evitar incluir colunas redundantes nas cláusulas GROUP
BY
. Como menos colunas exigem menos memória, uma consulta que usa menos colunas para descrever um grupo é mais eficiente. As colunas numéricas também usam menos memória do que as strings. Por exemplo, ao agregar um conjunto de dados que tenha um ID numérico de categoria e um nome de categoria, use somente a coluna ID da categoria na cláusula GROUP BY
.
Às vezes, as consultas incluem colunas na cláusula GROUP BY
para contornar o fato de que uma coluna deve ser parte da cláusula GROUP BY
ou ser uma expressão agregada. Se essa regra não for seguida, você poderá receber uma mensagem de erro como esta:
EXPRESSION_NOT_AGGREGATE: line 1:8: 'category' must be an aggregate expression or appear in GROUP BY clause
Para evitar a necessidade de adicionar colunas redundantes à cláusula GROUP BY
, use a função arbitrary
SELECT country_id, arbitrary(country_name) AS country_name, COUNT(*) AS city_count FROM world_cities GROUP BY country_id
A função ARBITRARY
retorna um valor de arbitrary do grupo. A função é útil quando você sabe que todos os registros do grupo têm o mesmo valor para uma coluna, mas o valor não identifica o grupo.
Otimizar as principais N consultas
A cláusula ORDER BY
retorna os resultados de uma consulta em ordem de classificação. O Athena usa a classificação distribuída para executar a operação de classificação paralelamente em vários nós.
Se você não precisar estritamente que seu resultado seja classificado, evite adicionar uma cláusula ORDER
BY
. Além disso, evite adicionar ORDER BY
a consultas internas se não for estritamente necessário. Em muitos casos, o planejador de consultas poderá remover a classificação redundante, mas isso não é garantido. Uma exceção a essa regra é se uma consulta interna estiver realizando uma operação principal N
, como encontrar o N
mais recente ou os valores de N
mais comuns.
Quando o Athena vê ORDER BY
junto com LIMIT
, ele entende que você está executando uma consulta principal N
e usa as operações dedicadas adequadamente.
nota
Embora o Athena muitas vezes também possa detectar funções de janela como row_number
que usa N
principal, recomendamos a versão mais simples que usa ORDER BY
e LIMIT
. Para ter mais informações, consulte Reduzir o escopo das funções da janela ou removê-las.
Incluir somente as colunas obrigatórias
Caso não precise estritamente de uma coluna, não a inclua na consulta. Quanto menos dados a consulta precisar processar, mais rápido ela será executada. Isso reduz a quantidade de memória necessária e a quantidade de dados que devem ser enviados entre os nós. Se você estiver usando um formato de arquivo colunar, reduzir o número de colunas também reduzirá a quantidade de dados lidos do Amazon S3.
O Athena não tem limite específico para o número de colunas de um resultado, mas a forma como as consultas são executadas limita o possível tamanho combinado das colunas. O tamanho combinado das colunas inclui os nomes e tipos.
Por exemplo, o seguinte erro é causado por uma relação que excede o limite de tamanho de um descritor de relação:
GENERIC_INTERNAL_ERROR: io.airlift.bytecode.CompilationException
Para resolver esse problema, reduza o número de colunas na consulta ou crie subconsultas e use JOIN
para recuperar uma quantidade menor de dados. Se você tiver consultas que executam SELECT *
na consulta mais externa, altere *
para uma lista com somente as colunas necessárias.
Otimizar consultas com o uso de aproximações
O Athena tem suporte para funções agregadas de aproximação
Diferentemente das operações COUNT(DISTINCT col)
, o approx_distinct
Otimizar LIKE
É possível usar LIKE
para encontrar strings correspondentes, mas com strings longas, demanda uso intensivo de computação. Na maioria dos casos, a função regexp_like
Muitas vezes, é possível otimizar uma pesquisa ancorando a substring que você está procurando. Por exemplo, se você estiver procurando por um prefixo, é muito melhor usar “substr
%” em vez de “substr
%”. Ou, se você estiver usando regexp_like
, “^substr
”.
Usar UNION ALL em vez de UNION
UNION ALL
e UNION
são duas maneiras de combinar os resultados de duas consultas em um único resultado. UNION ALL
concatena os registros da primeira consulta com a segunda e UNION
faz o mesmo, mas também remove as duplicatas. UNION
precisa processar todos os registros e encontrar as duplicatas, o que requer uso intensivo de memória e computação, mas UNION ALL
é uma operação relativamente rápida. A menos que você precise desduplicar registros, use UNION
ALL
para obter a melhor performance.
Usar UNLOAD para grandes conjuntos de resultados
Quando se espera que os resultados da consulta sejam grandes (por exemplo, dezenas de milhares de linhas ou mais), use UNLOAD para exportar os resultados. Na maioria dos casos, isso é mais rápido do que executar uma consulta normal, e usar UNLOAD
também oferece mais controle sobre a saída.
Quando a consulta acaba de ser executada, o Athena armazena o resultado como um único arquivo CSV não compactado no Amazon S3. Isso leva mais tempo que usar UNLOAD
, não apenas porque o resultado não está compactado, mas também porque a operação não pode ser paralelizada. Por sua vez, UNLOAD
grava os resultados diretamente dos nós de trabalho e faz uso total do paralelismo do cluster de computação. Além disso, é possível configurar UNLOAD
para gravar os resultados em formato compactado e em outros formatos de arquivo, como JSON e Parquet.
Para ter mais informações, consulte UNLOAD.
Use CTAS ou o Glue ETL para materializar agregações usadas com frequência
“Materializar” uma consulta é uma forma de acelerar a performance da consulta armazenando resultados de consultas complexas pré-computados (por exemplo, agregações e junções) para reutilização em consultas subsequentes.
Se muitas de suas consultas incluírem as mesmas junções e agregações, você poderá materializar a subconsulta comum como uma nova tabela e executar consultas nessa tabela. É possível criar a nova tabela com Criar uma tabela com base em resultados de consultas (CTAS) ou com uma ferramenta ETL dedicada, como o Glue ETL
Por exemplo, digamos que você tenha um painel com widgets que exibem diferentes aspectos de um conjunto de dados de pedidos. Cada widget tem sua própria consulta, mas todas as consultas compartilham as mesmas junções e filtros. Uma tabela de pedidos é unida a uma tabela de itens de linha, e há um filtro para exibir somente os últimos três meses. Se você identificar os atributos comuns dessas consultas, poderá criar uma nova tabela que os widgets possam usar. Isso reduz a duplicação e melhora a performance. A desvantagem é que você deverá manter a nova tabela atualizada.
Reutilizar resultados da consulta
É comum que a mesma consulta seja executada várias vezes em pouco tempo. Por exemplo, isso pode ocorrer quando várias pessoas abrem o mesmo painel de dados. Ao executar uma consulta, você pode pedir para o Athena reutilizar os resultados calculados anteriormente. Especifique a idade máxima dos resultados a serem reutilizados. Se a mesma consulta for executada anteriormente dentro desse período, o Athena retornará esses resultados em vez de executar a consulta novamente. Para obter mais informações, consulte Reutilização de resultados da consulta no Athena aqui no Guia do usuário do Amazon Athena e Reduce cost and improve query performance with Amazon Athena Query Result Reuse