COMMANDE lente avec LIMITE


11

J'ai cette requête:

SELECT * 
FROM location 
WHERE to_tsvector('simple',unaccent2("city"))
   @@ to_tsquery('simple',unaccent2('wroclaw')) 
order by displaycount

J'en suis content:

"Sort  (cost=3842.56..3847.12 rows=1826 width=123) (actual time=1.915..2.084 rows=1307 loops=1)"
"  Sort Key: displaycount"
"  Sort Method: quicksort  Memory: 206kB"
"  ->  Bitmap Heap Scan on location  (cost=34.40..3743.64 rows=1826 width=123) (actual time=0.788..1.208 rows=1307 loops=1)"
"        Recheck Cond: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"        ->  Bitmap Index Scan on location_lower_idx  (cost=0.00..33.95 rows=1826 width=0) (actual time=0.760..0.760 rows=1307 loops=1)"
"              Index Cond: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"Total runtime: 2.412 ms"

Mais quand j'ajoute LIMIT, l'exécution prend plus de 2 secondes:

SELECT * 
FROM location 
WHERE to_tsvector('simple',unaccent2("city"))
   @@ to_tsquery('simple',unaccent2('wroclaw')) 
order by displaycount 
limit 20

Explique:

"Limit  (cost=0.00..1167.59 rows=20 width=123) (actual time=2775.452..2775.643 rows=20 loops=1)"
"  ->  Index Scan using location_displaycount_index on location  (cost=0.00..106601.25 rows=1826 width=123) (actual time=2775.448..2775.637 rows=20 loops=1)"
"        Filter: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"Total runtime: 2775.693 ms"

Je pense que c'est un problème avec ORDER BY et LIMIT. Comment puis-je forcer PostgreSQL à utiliser l'index et à faire la commande à la fin?

La sous-requête n'aide pas:

SELECT * 
FROM (
    SELECT * 
    FROM location 
    WHERE to_tsvector('simple',unaccent2("city"))
       @@ to_tsquery('simple',unaccent2('wroclaw')) 
    order by displaycount
) t 
LIMIT 20;

ou:

SELECT * 
FROM (
    SELECT * 
    FROM location 
    WHERE to_tsvector('simple',unaccent2("city"))
       @@ to_tsquery('simple',unaccent2('wroclaw'))
) t 
order by displaycount 
LIMIT 20;

Réponses:


12

Je suppose que cela résoudrait votre requête:

SELECT * 
FROM   location 
WHERE     to_tsvector('simple',unaccent2(city))
       @@ to_tsquery('simple',unaccent2('wroclaw')) 
ORDER  BY to_tsvector('simple',unaccent2(city))
       @@ to_tsquery('simple',unaccent2('wroclaw')) DESC
         ,displaycount 
LIMIT  20;

Je répète la WHEREcondition en tant que premier élément de la ORDER BYclause - qui est logiquement redondante, mais devrait empêcher le planificateur de requêtes de supposer qu'il serait préférable de traiter les lignes en fonction de l'index location_displaycount_index- ce qui s'avère beaucoup plus cher.

Le problème sous-jacent est que le planificateur de requêtes évalue manifestement mal la sélectivité et / ou le coût de votre WHEREcondition. Je ne peux que spéculer pourquoi.

Avez-vous un fonctionnement sous vide automatique - qui devrait également prendre en charge le fonctionnement ANALYZEsur vos tables? Ainsi, vos statistiques de table sont-elles à jour? Tout effet si vous exécutez:

ANALYZE location;

Et essayez à nouveau?

Il se peut également que la sélectivité de l' @@opérateur soit mal évaluée. J'imagine qu'il est très difficile d'estimer pour des raisons logiques.


Si ma requête ne résout pas le problème, et généralement pour vérifier la théorie sous-jacente, effectuez l' une des deux opérations suivantes :

Ce dernier est moins intrusif et n'affecte que la session en cours. Il laisse les méthodes bitmap heap scanet bitmap index scanouvertes, qui sont utilisées par le plan le plus rapide.
Réexécutez ensuite la requête.

BTW: Si la théorie est solide, votre requête (comme vous l'avez maintenant) sera beaucoup plus rapide avec un terme de recherche moins sélectif dans la condition FTS - contrairement à ce que vous pourriez attendre. Essayez-le.


1
La requête fonctionne. La désactivation de l'analyse d'index fonctionne également. ANALYSER ne fonctionne pas. Merci beaucoup pour la réponse complète.
ziri

0

Lorsque vous utilisez un ajustement postgresql LIMIT, il est prévu d'être optimal pour récupérer uniquement le sous-ensemble de lignes. Malheureusement, cela fait en quelque sorte un mauvais choix dans votre cas. Cela peut être dû au fait que les statistiques du tableau sont trop anciennes. Essayez de mettre à jour la statistique en émettant un emplacement ANALYSE DE VIDE;

Forcer l'utilisation d'index se fait normalement en interdisant l'utilisation d'analyses séquentielles (définissez enable_seqscan = false). Cependant, dans votre cas, il ne fait pas d'analyse séquentielle, il passe simplement à un index différent pour la requête avec LIMIT.

Dans le cas où l'analyse ne vous aiderait pas, pourriez-vous dire quelle version de postgresql vous utilisez? Aussi combien de lignes y a-t-il dans le tableau?


L'analyse n'a pas aidé. Le tableau contient environ 36 000 lignes et j'utilise postgresql 9.1.
ziri
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.