

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Optimisation des requêtes


Utilisez les techniques d'optimisation des requêtes décrites dans cette section pour accélérer l'exécution des requêtes ou pour contourner les requêtes qui dépassent les limites de ressources dans Athena.

## Optimisation des jointures


Il existe de nombreuses stratégies différentes pour exécuter des jointures dans un moteur de requête distribué. Les deux plus courantes sont les jointures par hachage distribuées et les requêtes comportant des conditions de jointure complexes.

### Positionnement des grandes tables à gauche et des petites tables à droite dans une jointure de hachage distribuée


Le type de jointure le plus courant utilise une comparaison d'égalité comme condition de jointure. Athena exécute ce type de jointure en tant que jointure par hachage distribuée.

Dans une jointure par hachage distribuée, le moteur crée une table de recherche (table de hachage) à partir de l'un des côtés de la jointure. Ce côté est appelé *côté build*. Les enregistrements du côté build sont répartis entre les nœuds. Chaque nœud crée une table de recherche pour son sous-ensemble. L'autre côté de la jointure, appelé *côté sonde*, est ensuite diffusé via les nœuds. Les enregistrements du côté sonde sont répartis sur les nœuds de la même manière que du côté build. Cela permet à chaque nœud d'effectuer la jointure en recherchant les enregistrements correspondants dans sa propre table de recherche.

Lorsque les tables de recherche créées à partir du côté build de la jointure ne rentrent pas dans la mémoire, les requêtes peuvent échouer. Même si la taille totale du côté build est inférieure à la mémoire disponible, les requêtes peuvent échouer si la répartition des enregistrements présente une asymétrie importante. Dans un cas extrême, tous les enregistrements peuvent avoir la même valeur pour la condition de jointure et doivent être conservés en mémoire sur un seul nœud. Même une requête moins asymétrique peut échouer si un ensemble de valeurs est envoyé au même nœud et que le total des valeurs dépasse la mémoire disponible. Les nœuds ont la capacité de répartir des enregistrements sur le disque, mais le déversement ralentit l'exécution des requêtes et peut s'avérer insuffisant pour empêcher l'échec de la requête.

Athena tente de réorganiser les jointures pour utiliser la relation la plus grande comme côté sonde, et la plus petite relation comme côté build. Cependant, comme Athena ne gère pas les données contenues dans les tables, il dispose de peu d'informations et doit souvent partir du principe que la première table est la plus grande et la seconde la plus petite.

Lorsque vous écrivez des jointures avec des conditions de jointure basées sur l'égalité, supposez que la table située à gauche du mot-clé `JOIN` correspond au côté sonde et que la table de droite correspond au côté build. Assurez-vous que la bonne table, le côté build, est la plus petite des tables. S'il n'est pas possible de réduire le côté build de la jointure suffisamment pour tenir en mémoire, envisagez d'exécuter plusieurs requêtes qui joignent des sous-ensembles de la table de build.

### Analyse des requêtes contenant des jointures complexes à l’aide d’EXPLAIN


Les requêtes comportant des conditions de jointure complexes (par exemple, les requêtes qui utilisent des opérateurs `LIKE`, `>` ou autres) sont souvent exigeantes en termes de calcul. Dans le pire des cas, chaque enregistrement d'un côté de la jointure doit être comparé à tous les enregistrements de l'autre côté de la jointure. Comme la durée d'exécution augmente avec le carré du nombre d'enregistrements, ces requêtes risquent de dépasser la durée d'exécution maximale.

Pour savoir à l'avance comment Athena exécutera votre requête, vous pouvez utiliser l'instruction `EXPLAIN`. Pour plus d’informations, consultez [Utilisation de EXPLAIN et EXPLAIN ANALYZE sur Athena](athena-explain-statement.md) et [Présentation des résultats de l’instruction EXPLAIN d’Athena](athena-explain-statement-understanding.md).

## Réduction de la portée des fonctions de fenêtrage ou suppression de ces fonctions


Les fonctions de fenêtrage étant des opérations gourmandes en ressources, elles peuvent ralentir ou même faire échouer les requêtes avec le message La requête a épuisé les ressources à ce facteur d'échelle. Les fonctions de fenêtrage conservent en mémoire tous les enregistrements sur lesquels elles opèrent afin de calculer leur résultat. Lorsque la fenêtre est très grande, la fonction de fenêtrage peut manquer de mémoire.

Pour vous assurer que vos requêtes s'exécutent dans les limites de mémoire disponibles, réduisez la taille des fenêtres sur lesquelles vos fonctions de fenêtrage opèrent. Pour ce faire, vous pouvez ajouter une clause `PARTITIONED BY` ou réduire la portée des clauses de partitionnement existantes.

### Utilisation de fonctions autres que les fonctions de fenêtrage


Parfois, les requêtes comportant des fonctions de fenêtrage peuvent être réécrites sans fonctions de fenêtrage. Par exemple, au lieu d'utiliser `row_number` pour rechercher les meilleurs enregistrements `N`, vous pouvez utiliser `ORDER BY` et `LIMIT`. Au lieu d'utiliser `row_number` ou `rank` pour dédupliquer des enregistrements, vous pouvez utiliser des fonctions d'agrégation telles que [max\$1by](https://trino.io/docs/current/functions/aggregate.html#max_by), [min\$1by](https://trino.io/docs/current/functions/aggregate.html#min_by) et [arbitrary](https://trino.io/docs/current/functions/aggregate.html#arbitrary).

Supposons, par exemple, que vous disposiez d'un jeu de données actualisé par un capteur. Le capteur indique régulièrement l'état de la batterie et inclut certaines métadonnées, telles que l'emplacement. Si vous souhaitez connaître le dernier état de la batterie de chaque capteur et son emplacement, vous pouvez utiliser cette requête :

```
SELECT sensor_id,
       arbitrary(location) AS location,
       max_by(battery_status, updated_at) AS battery_status
FROM sensor_readings
GROUP BY sensor_id
```

Les métadonnées telles que l'emplacement étant les mêmes pour chaque enregistrement, vous pouvez utiliser la fonction `arbitrary` pour sélectionner n'importe quelle valeur dans le groupe. 

Pour connaître le dernier état de la batterie, vous pouvez utiliser la fonction `max_by`. La fonction `max_by` sélectionne la valeur d'une colonne dans l'enregistrement où la valeur maximale d'une autre colonne a été trouvée. Dans ce cas, il renvoie l'état de la batterie de l'enregistrement avec l'heure de la dernière mise à jour au sein du groupe. Cette requête s'exécute plus rapidement et utilise moins de mémoire qu'une requête équivalente dotée d'une fonction de fenêtrage. 

## Optimisation des agrégations


Lorsqu'Athena effectue une agrégation, il répartit les enregistrements entre les composants master en utilisant les colonnes de la clause `GROUP BY`. Pour que la tâche de mise en correspondance des enregistrements avec des groupes soit aussi efficace que possible, les nœuds tentent de conserver les enregistrements en mémoire mais les déversent sur le disque si nécessaire.

Il est également conseillé d'éviter d'inclure des colonnes redondantes dans les clauses `GROUP BY`. Le nombre réduit de colonnes nécessitant moins de mémoire, une requête décrivant un groupe utilisant moins de colonnes est plus efficace. Les colonnes numériques utilisent également moins de mémoire que les chaînes. Par exemple, lorsque vous agrégez un jeu de données qui possède à la fois un ID de catégorie numérique et un nom de catégorie, utilisez uniquement la colonne ID de catégorie dans la clause `GROUP BY`.

Parfois, les requêtes incluent des colonnes dans la clause `GROUP BY` pour contourner le fait qu'une colonne doit faire partie de la clause `GROUP BY` ou d'une expression agrégée. Si cette règle n'est pas respectée, vous pouvez recevoir un message d'erreur du type suivant :

 EXPRESSION\$1NOT\$1AGGREGATE : ligne 1:8 : « catégorie » doit être une expression agrégée ou apparaître dans la clause GROUP BY 

Pour éviter d'avoir à ajouter des colonnes redondantes à la clause `GROUP BY`, vous pouvez utiliser la fonction [ARBITRARY](https://trino.io/docs/current/functions/aggregate.html#arbitrary), comme dans l'exemple suivant.

```
SELECT country_id,
       arbitrary(country_name) AS country_name,
       COUNT(*) AS city_count
FROM world_cities
GROUP BY country_id
```

La fonction `ARBITRARY` renvoie une valeur arbitraire à partir du groupe. La fonction est utile lorsque vous savez que tous les enregistrements du groupe ont la même valeur pour une colonne, mais que cette valeur n'identifie pas le groupe.

## Optimisation des N requêtes principales


La clause `ORDER BY` renvoie les résultats d'une requête dans un ordre trié. Athena utilise le tri distribué pour exécuter l'opération de tri en parallèle sur plusieurs nœuds.

Si vous n'avez pas strictement besoin que votre résultat soit trié, évitez d'ajouter une clause `ORDER BY`. Évitez également d'ajouter des clauses `ORDER BY` à des requêtes internes si elles ne sont pas strictement nécessaires. Dans de nombreux cas, le planificateur de requêtes peut supprimer le tri redondant, mais cela n'est pas garanti. Il existe une exception à cette règle si une requête interne effectue une opération Top `N`, telle que la recherche des valeurs `N` les plus récentes ou `N` les plus courantes.

Quand Athena voit `ORDER BY` en même temps que `LIMIT`, il comprend que vous exécutez une requête Top `N` et utilise des opérations dédiées en conséquence.

**Note**  
Bien qu'Athena puisse également souvent détecter des fonctions de fenêtrage telles `row_number` qui utilisent `N` principal, nous recommandons la version plus simple qui utilise `ORDER BY` et `LIMIT`. Pour de plus amples informations, veuillez consulter [Réduction de la portée des fonctions de fenêtrage ou suppression de ces fonctions](#performance-tuning-optimizing-window-functions).

## Inclure uniquement les colonnes obligatoires


Si vous n'avez pas strictement besoin d'une colonne, ne l'incluez pas dans votre requête. Moins une requête doit traiter de données, plus elle sera exécutée rapidement. Cela réduit à la fois la quantité de mémoire requise et la quantité de données à envoyer entre les nœuds. Si vous utilisez un format de fichier en colonnes, la réduction du nombre de colonnes réduit également la quantité de données lues à partir d'Amazon S3.

Athena n'impose aucune limite spécifique quant au nombre de colonnes dans un résultat, mais la manière dont les requêtes sont exécutées limite la taille combinée possible des colonnes. La taille combinée des colonnes inclut leur nom et leur type.

Par exemple, l'erreur suivante est due à une relation qui dépasse la limite de taille d'un descripteur de relation :

 ERREUR INTERNE GÉNÉRIQUE : io.airlift.bytecode. CompilationException 

Pour contourner ce problème, réduisez le nombre de colonnes dans la requête ou créez des sous-requêtes et utilisez une commande `JOIN` qui récupère une plus petite quantité de données. Si vous avez des requêtes effectuant `SELECT *` dans la requête la plus externe, vous devez remplacer l'`*` par une liste contenant uniquement les colonnes dont vous avez besoin.

## Optimisation des requêtes à l’aide d’approximations


Athena prend en charge les [fonctions d'agrégation d'approximations](https://trino.io/docs/current/functions/aggregate.html#appro) pour compter les valeurs distinctes, les valeurs les plus fréquentes, les percentiles (y compris les médianes approximatives) et créer des histogrammes. Utilisez ces fonctions chaque fois que des valeurs exactes ne sont pas nécessaires.

Contrairement aux opérations `COUNT(DISTINCT col)`, [approx\$1distinct](https://trino.io/docs/current/functions/aggregate.html#approx_distinct) utilise beaucoup moins de mémoire et s'exécute plus rapidement. De même, l'utilisation de [numeric\$1histogram](https://trino.io/docs/current/functions/aggregate.html#numeric_histogram) au lieu de [histogram](https://trino.io/docs/current/functions/aggregate.html#histogram) utilise des méthodes approximatives et donc moins de mémoire.

## Optimisation de LIKE


Vous pouvez utiliser `LIKE` pour trouver des chaînes correspondantes, mais avec de longues chaînes, cela demande beaucoup de calcul. La fonction [regexp\$1like](https://trino.io/docs/current/functions/regexp.html#regexp_like) est dans la plupart des cas une alternative plus rapide et offre également plus de flexibilité.

Vous pouvez souvent optimiser une recherche en ancrant la sous-chaîne que vous recherchez. Par exemple, si vous recherchez un préfixe, il est préférable d'utiliser « *substr* % » au lieu de « *substr* % % ». Ou, si vous utilisez `regexp_like` « ^ *substr* ».

## Utiliser UNION ALL au lieu de UNION


 `UNION ALL` et `UNION` sont deux manières de combiner les résultats de deux requêtes en un seul résultat. `UNION ALL` concatène les enregistrements de la première requête avec la seconde, et `UNION` fait de même, mais supprime également les doublons. `UNION` doit traiter tous les enregistrements et trouver les doublons, ce qui demande beaucoup de mémoire et de calcul, mais `UNION ALL` est une opération relativement rapide. À moins que vous n'ayez besoin de dédupliquer des enregistrements, utilisez `UNION ALL` pour de meilleures performances.

## Utiliser UNLOAD pour les grands ensembles de résultats


Lorsque les résultats d'une requête sont censés être volumineux (par exemple, des dizaines de milliers de lignes ou plus), utilisez UNLOAD pour exporter les résultats. Dans la plupart des cas, cela est plus rapide que l'exécution d'une requête normale, et l'utilisation de `UNLOAD` vous permet également de mieux contrôler le résultat.

Lorsque l'exécution d'une requête est terminée, Athena stocke le résultat sous la forme d'un seul fichier CSV non compressé sur Amazon S3. Cela prend plus de temps que `UNLOAD`, non seulement parce que le résultat n'est pas compressé, mais également parce que l'opération ne peut pas être parallélisée. En revanche, `UNLOAD` écrit les résultats directement à partir des composants master et utilise pleinement le parallélisme du cluster de calcul. En outre, vous pouvez configurer `UNLOAD` pour écrire les résultats au format compressé et dans d'autres formats de fichier tels que JSON et Parquet.

Pour de plus amples informations, veuillez consulter [UNLOAD](unload.md). 

## Utiliser CTAS ou ETL Glue pour matérialiser les agrégations fréquemment utilisées


La « matérialisation » d'une requête est un moyen d'accélérer les performances des requêtes en stockant des résultats de requêtes complexes précalculés (par exemple, des agrégations et des jointures) pour les réutiliser dans les requêtes suivantes.

Si bon nombre de vos requêtes incluent les mêmes jointures et agrégations, vous pouvez matérialiser la sous-requête commune sous la forme d'une nouvelle table, puis exécuter des requêtes sur cette table. Vous pouvez créer la nouvelle table avec [Création d’une table à partir des résultats des requêtes (CTAS)](ctas.md) ou un outil ETL dédié tel que [ETL Glue](https://aws.amazon.com/glue).

Supposons, par exemple, que vous disposiez d'un tableau de bord comprenant des widgets qui présentent différents aspects d'un jeu de données de commandes. Chaque widget possède sa propre requête, mais les requêtes partagent toutes les mêmes jointures et filtres. Une table des commandes est jointe à une table des articles, et un filtre permet de n'afficher que les trois derniers mois. Si vous identifiez les caractéristiques communes de ces requêtes, vous pouvez créer une nouvelle table que les widgets pourront utiliser. Cela réduit les doublons et améliore les performances. L'inconvénient est que vous devez maintenir la nouvelle table à jour.

## Réutiliser les résultats des requêtes


Il est courant qu'une même requête soit exécutée plusieurs fois dans un court laps de temps. Cela peut se produire, par exemple, lorsque plusieurs personnes ouvrent le même tableau de bord de données. Lorsque vous exécutez une requête, vous pouvez demander à Athena de réutiliser les résultats précédemment calculés. Vous spécifiez l'âge maximal des résultats à réutiliser. Si la même requête a déjà été exécutée pendant cette période, Athena renvoie ces résultats au lieu de réexécuter la requête. Pour plus d'informations, consultez [Réutilisation des résultats des requêtes dans Athena](reusing-query-results.md) ici dans le *Guide de l'utilisateur Amazon Athena* et [Réduction des coûts et amélioration des performances des requêtes grâce à la réutilisation des résultats des requêtes Amazon Athena](https://aws.amazon.com/blogs/big-data/reduce-cost-and-improve-query-performance-with-amazon-athena-query-result-reuse/) sur le *blog AWS Big Data*.