Comment forcer Postgres à utiliser un index alors qu'il insisterait autrement pour effectuer une analyse séquentielle?
sql
postgresql
indexing
mike
la source
la source
Réponses:
En supposant que vous posiez des questions sur la fonctionnalité commune "d'indexation d'index" trouvée dans de nombreuses bases de données, PostgreSQL ne fournit pas une telle fonctionnalité. C'était une décision consciente prise par l'équipe PostgreSQL. Un bon aperçu de pourquoi et ce que vous pouvez faire à la place se trouve ici . Les raisons en sont essentiellement que c'est un hack de performance qui a tendance à causer plus de problèmes plus tard au fur et à mesure que vos données changent, tandis que l'optimiseur de PostgreSQL peut réévaluer le plan en fonction des statistiques. En d'autres termes, ce qui pourrait être un bon plan de requête aujourd'hui ne sera probablement pas un bon plan de requête pour toujours, et les indices d'index imposent un plan de requête particulier pour toujours.
En tant que marteau très émoussé, utile pour les tests, vous pouvez utiliser les paramètres
enable_seqscan
etenable_indexscan
. Voir:enable_
paramètresCeux-ci ne conviennent pas à une utilisation en production continue . Si vous rencontrez des problèmes avec le choix du plan de requête, vous devriez consulter la documentation pour suivre les problèmes de performances des requêtes . Ne vous contentez pas de définir les
enable_
paramètres et de partir.À moins que vous n'ayez une très bonne raison d'utiliser l'index, Postgres peut faire le bon choix. Pourquoi?
Voir aussi cet ancien message de groupe de discussion .
la source
Probablement la seule raison valable d'utiliser
c'est lorsque vous écrivez des requêtes et que vous souhaitez voir rapidement quel serait le plan de requête s'il y avait de grandes quantités de données dans la ou les tables. Ou bien sûr si vous avez besoin de confirmer rapidement que votre requête n'utilise pas d'index simplement parce que l'ensemble de données est trop petit.
la source
set enable_seqscan=false
, exécutez votre requête, puis exécutez rapidementset enable_seqscan=true
pour ramener postgresql à son bon comportement (et ne faites évidemment pas cela en production, uniquement en développement!)SET SESSION enable_seqscan=false
pour n'affecter que vousParfois, PostgreSQL ne parvient pas à faire le meilleur choix d'index pour une condition particulière. À titre d'exemple, supposons qu'il existe une table de transactions avec plusieurs millions de lignes, dont il y en a plusieurs centaines pour un jour donné, et que la table a quatre index: transaction_id, client_id, date et description. Vous souhaitez exécuter la requête suivante:
PostgreSQL peut choisir d'utiliser l'index transactions_description_idx au lieu de transactions_date_idx, ce qui peut conduire à une requête de plusieurs minutes au lieu de moins d'une seconde. Si tel est le cas, vous pouvez forcer l'utilisation de l'index sur la date en truquant la condition comme ceci:
la source
your_wanted_index
, cela peut être pour que le moteur postgresql effectue simplement un balayage de séquence / clé primaire à la place. Conclusion - il n'y a pas de méthode fiable à 100% pour forcer l'utilisation d'index pour le serveur PostgreSql.where
condition mais deux tables ou jointes et que Postgres ne parvient pas à prendre l'index.Réponse courte
Ce problème se produit généralement lorsque le coût estimé d'une analyse d'index est trop élevé et ne reflète pas correctement la réalité. Vous devrez peut-être réduire le
random_page_cost
paramètre de configuration pour résoudre ce problème. À partir de la documentation Postgres :Vous pouvez vérifier si une valeur inférieure obligera réellement Postgres à utiliser l'index (mais utilisez-la uniquement pour les tests ):
Vous pouvez restaurer la valeur par défaut avec à
SET random_page_cost = DEFAULT;
nouveau.Contexte
Les analyses d'index nécessitent des extractions de page de disque non séquentielles. Postgres utilise
random_page_cost
pour estimer le coût de ces extractions non séquentielles par rapport aux extractions séquentielles. La valeur par défaut est4.0
donc, en supposant un facteur de coût moyen de 4 par rapport aux extractions séquentielles (en tenant compte des effets de mise en cache).Le problème est cependant que cette valeur par défaut ne convient pas dans les scénarios réels importants suivants:
1) disques SSD
Comme l'admet la documentation:
Selon le dernier point de cette diapositive d'un discours à PostgresConf 2018,
random_page_cost
devrait être réglé sur quelque chose entre1.0
et2.0
pour les disques SSD.2) Données mises en cache
Si les données d'index requises sont déjà mises en cache dans la RAM, une analyse d'index sera toujours beaucoup plus rapide qu'une analyse séquentielle. La documentation dit:
Le problème est que vous ne pouvez bien sûr pas savoir facilement si les données pertinentes sont déjà mises en cache. Cependant, si un index spécifique est fréquemment interrogé et si le système dispose de suffisamment de RAM, les données sont susceptibles d'être mises en cache et
random_page_cost
doivent être définies sur une valeur inférieure. Vous devrez expérimenter différentes valeurs et voir ce qui fonctionne pour vous.Vous pouvez également utiliser l' extension pg_prewarm pour la mise en cache explicite des données.
la source
La question en elle-même est tout à fait invalide. Forcer (en faisant enable_seqscan = off par exemple) est une très mauvaise idée. Il peut être utile de vérifier si ce sera plus rapide, mais le code de production ne doit jamais utiliser de telles astuces.
Au lieu de cela, expliquez l'analyse de votre requête, lisez-la et découvrez pourquoi PostgreSQL choisit un mauvais plan (à votre avis).
Il existe des outils sur le Web qui aident à la lecture d'expliquer la sortie d'analyse - l'un d'entre eux est Expliquer.depesz.com - écrit par moi.
Une autre option est de rejoindre le canal #postgresql sur le réseau freenode irc, et de parler aux gars là pour vous aider - car l'optimisation de la requête n'est pas une question de "poser une question, obtenir une réponse, soyez heureux". c'est plutôt une conversation, avec beaucoup de choses à vérifier, beaucoup de choses à apprendre.
la source
Il y a une astuce pour pousser postgres pour préférer un seqscan en ajoutant un
OFFSET 0
dans la sous-requêteC'est pratique pour optimiser les requêtes liant des tables grandes / énormes lorsque tout ce dont vous avez besoin est seulement les n premier / dernier éléments.
Supposons que vous recherchiez les 20 premiers / derniers éléments impliquant plusieurs tables ayant 100k (ou plus) entrées, inutile de créer / relier toutes les requêtes sur toutes les données lorsque ce que vous recherchez est dans les 100 ou 1000 premiers entrées. Dans ce scénario, par exemple, il s'avère plus de 10 fois plus rapide d'effectuer une analyse séquentielle.
voir Comment puis-je empêcher Postgres d'insérer une sous-requête?
la source