J'ai une requête relativement simple sur une table avec 1,5 M de lignes:
SELECT mtid FROM publication
WHERE mtid IN (9762715) OR last_modifier=21321
LIMIT 5000;
EXPLAIN ANALYZE
production:
Limit (cost=8.84..12.86 rows=1 width=8) (actual time=0.985..0.986 rows=1 loops=1) -> Bitmap Heap Scan on publication (cost=8.84..12.86 rows=1 width=8) (actual time=0.984..0.985 rows=1 loops=1) Recheck Cond: ((mtid = 9762715) OR (last_modifier = 21321)) -> BitmapOr (cost=8.84..8.84 rows=1 width=0) (actual time=0.971..0.971 rows=0 loops=1) -> Bitmap Index Scan on publication_pkey (cost=0.00..4.42 rows=1 width=0) (actual time=0.295..0.295 rows=1 loops=1) Index Cond: (mtid = 9762715) -> Bitmap Index Scan on publication_last_modifier_btree (cost=0.00..4.42 rows=1 width=0) (actual time=0.674..0.674 rows=0 loops=1) Index Cond: (last_modifier = 21321) Total runtime: 1.027 ms
Jusqu'ici tout va bien, rapide et utilise les index disponibles.
Maintenant, si je modifie un peu une requête, le résultat sera:
SELECT mtid FROM publication
WHERE mtid IN (SELECT 9762715) OR last_modifier=21321
LIMIT 5000;
La EXPLAIN ANALYZE
sortie est:
Limit (cost=0.01..2347.74 rows=5000 width=8) (actual time=2735.891..2841.398 rows=1 loops=1) -> Seq Scan on publication (cost=0.01..349652.84 rows=744661 width=8) (actual time=2735.888..2841.393 rows=1 loops=1) Filter: ((hashed SubPlan 1) OR (last_modifier = 21321)) SubPlan 1 -> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.001 rows=1 loops=1) Total runtime: 2841.442 ms
Pas si rapide, et en utilisant seq scan ...
Bien sûr, la requête d'origine exécutée par l'application est un peu plus complexe, et même plus lente, et bien sûr l'original généré en hibernation ne l'est pas (SELECT 9762715)
, mais la lenteur est là même pour ça (SELECT 9762715)
! La requête est générée par hibernate, il est donc très difficile de les modifier, et certaines fonctionnalités ne sont pas disponibles (par exemple, UNION
ne sont pas disponibles, ce qui serait rapide).
Questions
- Pourquoi l'index ne peut-il pas être utilisé dans le deuxième cas? Comment pourraient-ils être utilisés?
- Puis-je améliorer les performances des requêtes d'une autre manière?
Réflexions supplémentaires
Il semble que nous pourrions utiliser le premier cas en effectuant manuellement un SELECT, puis en plaçant la liste résultante dans la requête. Même avec 5000 numéros dans la liste IN (), c'est quatre fois plus rapide que la deuxième solution. Cependant, cela semble juste FAUX (aussi, cela pourrait être 100 fois plus rapide :)). Il est totalement incompréhensible que le planificateur de requêtes utilise une méthode complètement différente pour ces deux requêtes, donc je voudrais trouver une meilleure solution à ce problème.
(SELECT 9762715)
.
(SELECT 9762715)
. À la question d'hibernation: cela pourrait être fait, mais nécessite une réécriture sérieuse du code, car nous avons des requêtes de critères d'hibernation définies par l'utilisateur qui sont traduites à la volée. Donc, essentiellement, nous modifierions Hibernate, ce qui est une énorme entreprise avec beaucoup d'effets secondaires possibles.
JOIN
au lieu duIN ()
? En outre, apublication
été analysé récemment?