2

J'ai des problèmes pour que postgres utilise mes index multi-colonnes pour une recherche complète en utilisant l'extension btree_gin. Ceci est pour une page de recherche d'articles. L'idée derrière l'utilisation de btree_gin est d'être en mesure d'obtenir le « id » champ pour le tri et magazine_id comme un filtre:Postgresql n'utilise pas d'index multi-colonnes (btree_gin)

CREATE INDEX idx_gin_search ON article USING gin(id, magazine_id, search_vector_full) WITH (fastupdate = off); 

Postgres décide d'utiliser un indice de btree le magazine à la place, puis filtre (= lent) :

Executed SQL 
SELECT ••• FROM article WHERE (((article.search_vector) @@  
(plainto_tsquery('pg_catalog.english', 'interesting'))) AND  
article.magazine_id = 7) ORDER BY article.id ASC LIMIT 36 
Time 13.4780406952 ms 

QUERY PLAN 
Limit (cost=2021.87..2021.96 rows=36 width=384) (actual time=9.782..9.787 rows=36 loops=1) 
    -> Sort (cost=2021.87..2027.49 rows=2248 width=384) (actual time=9.781..9.784 rows=36 loops=1) 
    Sort Key: id 
    Sort Method: top-N heapsort Memory: 53kB 
    -> Index Scan using idx_magazine_id on article (cost=0.29..1952.53 rows=2248 width=384) (actual time=0.035..8.924 rows=2249 loops=1) 
      Index Cond: (magazine_id = 7) 
      Filter: (search_vector @@ '''interesting'''::tsquery) 
      Rows Removed by Filter: 11413 
Planning time: 4.600 ms 
Execution time: 9.860 ms 

Alors, ce que je trouve comprendre encore moins, est qu'il refuse aussi d'utiliser ce simple indice de btree sur la page LISTE des articles, où ils sont énumérées ci-dessus x par page dans l'ordre décroissant:

CREATE INDEX idx_btree_listing ON article USING btree(id DESC, magazine_id); 

Encore une fois, il ne pas utiliser l'index multi-colonnes:

Executed SQL 
SELECT ••• FROM article WHERE article.magazine_id = 7 
ORDER BY article.id DESC LIMIT 36 
Time 1.4750957489 ms 

QUERY PLAN 
Limit (cost=0.29..7.48 rows=36 width=384) (actual time=0.034..0.115 rows=36 loops=1) 
-> Index Scan Backward using idx_magazine_id on article (cost=0.29..2729.56 rows=13662 width=384) (actual time=0.031..0.107 rows=36 loops=1) 
    Filter: (magazine_id = 7) 
    Planning time: 1.354 ms 
    Execution time: 0.207 ms 

EDIT: Ce qui précède est une configuration de développement avec moins de dossiers et seulement 1 le magazine, d'où la vitesse rapide. Voici un journal produit par auto_explain sur le serveur de production:

duration: 230.629 ms plan: 
SELECT article.id, article.title, article.date, article.content FROM article WHERE article.magazine_id = 7 ORDER BY article.id DESC LIMIT 36 

Limit (cost=0.42..43.67 rows=36 width=306) (actual time=229.876..229.995 rows=36 loops=1) 
    -> Index Scan Backward using idx_magazine_id on article (cost=0.42..239539.22 rows=199379 width=306) (actual time=229.866..229.968 rows=36 loops=1) 
    Filter: (article.magazine_id = 7) 
    Rows Removed by Filter: 116414 

Je serais reconnaissant quelqu'un pourrait me donner des conseils pour mon plus débogage sur celui-ci.

+1

Pourquoi la deuxième instruction devrait-elle utiliser l'arbre binaire si le résultat peut être complètement récupéré en utilisant l'index 'mmxxx_sitevideo_pkey' - avec une durée d'exécution de 0,2 millisecondes, cela me semble assez rapide. Le temps de planification a pris plus de temps que cela, mais le temps d'exécution total n'est toujours que de 1,5 ** milli ** secondes. Quelle performance attendez-vous? À quelle vitesse avez-vous besoin de cela? Bien que je dois admettre que les délais de planification (en particulier le premier) semblent assez élevés pour de telles déclarations simples. –

+0

Oui ce que vous dites est tout à fait logique, mais je dois préciser que ceux-ci proviennent d'une configuration de développement avec beaucoup moins de données que le serveur de production. Sur le serveur de production, j'ai utilisé le module auto_explain et obtenu le même plan d'exécution. Dans mon développement DB j'ai seulement un magazine_id, sur le vrai serveur je reçois la même requête et puis cela prend plus de temps, désolé j'aurais dû ajouter la requête de production, l'ai maintenant ajouté au message original. (Vous avez également oublié de renommer cet index que vous mentionnez à idx_magazine_id pour "simplification" ;-)) – tdma

+0

Ensuite, merci de poster le plan d'exécution (en utilisant 'explain (analyser, verbose)' depuis la production –

Répondre

1

La première colonne de votre index multi-colonnes est id. Vous ne filtrez pas sur l'identifiant, donc postgres n'utilisera pas cet index. Vous n'avez pas besoin de filtrer toutes les colonnes de l'index, mais les colonnes sur lesquelles vous effectuez le filtrage doivent être les n premières colonnes de l'index. Essayez l'expérimentation avec des variations de l'index que vous avez comme le déplacement de l'id à la fin ou l'id de ommiting à partir de l'index.

+0

Salut, merci pour vos commentaires.J'ai essayé d'inverser l'ordre des champs d'index et aussi sans le champ id comme vous le suggérez, mais le plan d'exécution est le même, et reste bien au-dessus de 100 ms ... Je suppose que l'opération de tri est le problème.Savez-vous si cette question (je me réfère à la deuxième question dans ma question initiale) serait support überhaubt aller tout de l'index? – tdma

+0

OK. Le problème de la question 2 est résolu. Le order_by était déroutant le planificateur. J'ai tout essayé pour le faire fonctionner avec la requête telle qu'elle était, y compris en changeant default_statistics_target et d'autres paramètres du planificateur. Il a continué à faire le mauvais choix (soulève à nouveau la question de savoir si postgres devrait avoir des indices). A la fin, j'ai créé une nouvelle colonne appelée id_sort, avec un contenu identique à id, et un index btree (magazine_id, id_sort desc) qui est très bien utilisé et fonctionne en quelques ms. C'est plutôt absurde cependant. – tdma