2011-08-25 3 views
0

J'ai une telle requête et j'essaie de l'optimiser. Il faut environ 1 seconde pour effectuer. C'est en quelque sorte le goulot d'étranglement des performances, car il s'exécute quelques fois par seconde.Optimisation de requête PostgreSQL

est ici question:

SELECT "spoleczniak_tablica"."id", "spoleczniak_tablica"."postac_id", 
"spoleczniak_tablica"."hash", "spoleczniak_tablica"."typ", 
"spoleczniak_tablica"."ikona", "spoleczniak_tablica"."opis", 
"spoleczniak_tablica"."cel", "spoleczniak_tablica"."data", "postac_postacie"."id", 
"postac_postacie"."user_id", "postac_postacie"."avatar", "postac_postacie"."ikonka", 
"postac_postacie"."imie", "postac_postacie"."nazwisko", "postac_postacie"."pseudonim", 
"postac_postacie"."plec", "postac_postacie"."wzrost", "postac_postacie"."waga", 
"postac_postacie"."ur_tydz", "postac_postacie"."ur_rok", "postac_postacie"."ur_miasto_id", 
"postac_postacie"."akt_miasto_id", "postac_postacie"."kasa", "postac_postacie"."punkty", 
"postac_postacie"."zmeczenie", "postac_postacie"."zdrowie", "postac_postacie"."kariera" 
FROM "spoleczniak_tablica" INNER JOIN "postac_postacie" ON 
("spoleczniak_tablica"."postac_id" = "postac_postacie"."id") WHERE 
spoleczniak_tablica.postac_id = 1 or spoleczniak_tablica.id in(select wpis_id from 
spoleczniak_oznaczone where etykieta_id in(select tag_id from spoleczniak_subskrypcje where 
postac_id = 1)) or (spoleczniak_tablica.postac_id in(select obserwowany_id from 
spoleczniak_obserwatorium where obserwujacy_id = 1) and hash not in('dyskusja', 'kochanie', 
'szturniecie')) or (spoleczniak_tablica.cel = 1 and spoleczniak_tablica.hash in('dyskusja', 
'kochanie', 'obserwatorium', 'szturchniecie')) or spoleczniak_tablica.hash = 
'administracja-info' or exists(select 1 from spoleczniak_komentarze where kredka_id = 
spoleczniak_tablica.id and postac_id = 1) ORDER BY "spoleczniak_tablica"."id" DESC LIMIT 
21; 

Et voici EXPLIQUEZ ANALYSER:

Limit (cost=52.80..184755.97 rows=21 width=282) (actual time=80.637..229.161 rows=21 loops=1) 
    -> Nested Loop (cost=52.80..27584240184.45 rows=3136216 width=282) (actual time=80.637..229.153 rows=21 loops=1) 
     -> Index Scan Backward using spoleczniak_tablica_pkey on spoleczniak_tablica (cost=52.80..27583220399.44 rows=3136216 width=193) (actual time=80.620..228.767 rows=21 loops=1) 
       Filter: ((postac_id = 1) OR (SubPlan 1) OR ((hashed SubPlan 2) AND ((hash)::text <> ALL ('{dyskusja,kochanie,szturniecie}'::text[]))) OR ((cel = 1) AND ((hash)::text = ANY ('{dyskusja,kochanie,obserwatorium,szturchniecie}'::text[]))) OR ((hash)::text = 'administracja-info'::text) OR (alternatives: SubPlan 3 or hashed SubPlan 4)) 
       SubPlan 1 
       -> Materialize (cost=13.22..11858.79 rows=1255820 width=4) (actual time=0.008..0.044 rows=486 loops=1517) 
         -> Nested Loop (cost=13.22..673.69 rows=1255820 width=4) (actual time=11.818..14.028 rows=486 loops=1) 
          -> HashAggregate (cost=5.89..5.90 rows=1 width=4) (actual time=0.051..0.056 rows=7 loops=1) 
            -> Index Scan using spoleczniak_subskrypcje_postac_id on spoleczniak_subskrypcje (cost=0.00..5.88 rows=2 width=4) (actual time=0.022..0.046 rows=7 loops=1) 
             Index Cond: (postac_id = 1) 
          -> Bitmap Heap Scan on spoleczniak_oznaczone (cost=7.33..662.99 rows=384 width=8) (actual time=1.708..1.978 rows=69 loops=7) 
            Recheck Cond: (etykieta_id = spoleczniak_subskrypcje.tag_id) 
            -> Bitmap Index Scan on spoleczniak_oznaczone_etykieta_id (cost=0.00..7.23 rows=384 width=0) (actual time=1.694..1.694 rows=69 loops=7) 
             Index Cond: (etykieta_id = spoleczniak_subskrypcje.tag_id) 
       SubPlan 2 
       -> Index Scan using spoleczniak_obserwatorium_obserwujacy_id on spoleczniak_obserwatorium (cost=0.00..39.53 rows=21 width=4) (actual time=0.041..0.192 rows=26 loops=1) 
         Index Cond: (obserwujacy_id = 1) 
       SubPlan 3 
       -> Bitmap Heap Scan on spoleczniak_komentarze (cost=18.63..20.64 rows=1 width=0) (never executed) 
         Recheck Cond: ((kredka_id = spoleczniak_tablica.id) AND (postac_id = 1)) 
         -> BitmapAnd (cost=18.63..18.63 rows=1 width=0) (never executed) 
          -> Bitmap Index Scan on spoleczniak_komentarze_kredka_id (cost=0.00..2.98 rows=24 width=0) (never executed) 
            Index Cond: (kredka_id = spoleczniak_tablica.id) 
          -> Bitmap Index Scan on spoleczniak_komentarze_postac_id (cost=0.00..15.40 rows=885 width=0) (never executed) 
            Index Cond: (postac_id = 1) 
       SubPlan 4 
       -> Index Scan using spoleczniak_komentarze_postac_id on spoleczniak_komentarze (cost=0.00..1616.70 rows=885 width=4) (actual time=0.044..54.812 rows=3607 loops=1) 
         Index Cond: (postac_id = 1) 
     -> Index Scan using postac_postacie_pkey on postac_postacie (cost=0.00..0.31 rows=1 width=89) (actual time=0.012..0.014 rows=1 loops=21) 
       Index Cond: (id = spoleczniak_tablica.postac_id) 

Si je supprime ORDER BY, a besoin de requête seulement 2-3 ms. Aucune suggestion?

+2

Vous triez 3082289 lignes. Pas de surprise cela prend terriblement longtemps. Il peut être judicieux d'utiliser des tables temporaires pour réduire la quantité de données sélectionnée. Pourriez-vous s'il vous plait publier la sortie 'ANALYZE' sans commande? – J0HN

+0

Je ne vois pas une sorte. Il me semble qu'il utilise l'index et compte à rebours jusqu'à ce qu'il ait 21 enregistrements acceptés. Nous avons vraiment besoin d'EXPLAIN ANALYZE pour voir à quel point le filtre est sélectif. Cela dit, je pense que j'essaierais de réécrire la clause de filtre qui inclut 'etykieta_id' pour utiliser une jointure à la place des sous-sélections imbriquées. –

+0

J'ai mis à jour la question avec EXPLAIN ANALYZE. – ThomK

Répondre

0

La première chose à faire est de redéfinir cette requête pour la rendre plus lisible. Cela signifie que les sous-objets sont déplacés dans les jointures.

La deuxième chose qui me vient à l'esprit à la lecture de la sortie d'explication est que le planificateur assume beaucoup plus de lignes qu'il n'en obtient réellement. Cela le fait se matérialiser éventuellement inutilement. Une grande chose à faire ici pourrait être d'augmenter les cibles statistiques pour les tables pertinentes et de relancer l'analyse de la base de données. Cela dit, pourquoi prévoit-il autant de lignes alors qu'il sait qu'il n'y en a pas plus de 21? Cela ressemble beaucoup à une limitation de planificateur pour moi et mise à niveau vers une version majeure plus récente de PostgreSQL peut résoudre le problème.