mi viene data questa query per ottimizzare su PostgreSQL 9.2:ottimizzazione delle query PostgreSQL No interno/esterno join permesso
SELECT C.name, COUNT(DISTINCT I.id) AS NumItems, COUNT(B.id)
FROM Categories C INNER JOIN Items I ON(C.id = I.category)
INNER JOIN Bids B ON (I.id = B.item_id)
GROUP BY C.name
Come parte del mio incarico scuola.
ho creato questi indici su rispettivi tavolo: items(category)
-> 2ndary b + tree, bids(item_id)
-> 2ndary albero B +, e categories(id)
-> indice primario qui,
La parte strana è, PostgreSQL sta facendo una scansione sequenziale sulla mia tabella Articoli, Categorie e Offerte e quando imposto lo enable_seqscan=off
, la ricerca dell'indice risulta essere più orrenda del risultato sottostante.
Quando corro spiegare in PostgreSQL questo è il risultato: PER FAVORE NON RIMUOVERE LE INDICAZIONI IN QUANTO SONO IMPORTANTI!
GroupAggregate (cost=119575.55..125576.11 rows=20 width=23) (actual time=6912.523..9459.431 rows=20 loops=1)
Buffers: shared hit=30 read=12306, temp read=6600 written=6598
-> Sort (cost=119575.55..121075.64 rows=600036 width=23) (actual time=6817.015..8031.285 rows=600036 loops=1)
Sort Key: c.name
Sort Method: external merge Disk: 20160kB
Buffers: shared hit=30 read=12306, temp read=6274 written=6272
-> Hash Join (cost=9416.95..37376.03 rows=600036 width=23) (actual time=407.974..3322.253 rows=600036 loops=1)
Hash Cond: (b.item_id = i.id)
Buffers: shared hit=30 read=12306, temp read=994 written=992
-> Seq Scan on bids b (cost=0.00..11001.36 rows=600036 width=8) (actual time=0.009..870.898 rows=600036 loops=1)
Buffers: shared hit=2 read=4999
-> Hash (cost=8522.95..8522.95 rows=50000 width=19) (actual time=407.784..407.784 rows=50000 loops=1)
Buckets: 4096 Batches: 2 Memory Usage: 989kB
Buffers: shared hit=28 read=7307, temp written=111
-> Hash Join (cost=1.45..8522.95 rows=50000 width=19) (actual time=0.082..313.211 rows=50000 loops=1)
Hash Cond: (i.category = c.id)
Buffers: shared hit=28 read=7307
-> Seq Scan on items i (cost=0.00..7834.00 rows=50000 width=8) (actual time=0.004..144.554 rows=50000 loops=1)
Buffers: shared hit=27 read=7307
-> Hash (cost=1.20..1.20 rows=20 width=19) (actual time=0.062..0.062 rows=20 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 1kB
Buffers: shared hit=1
-> Seq Scan on categories c (cost=0.00..1.20 rows=20 width=19) (actual time=0.004..0.028 rows=20 loops=1)
Buffers: shared hit=1
Total runtime: 9473.257 ms
Vedere this plan on explain.depesz.com.
Voglio solo sapere perché questo accade, ad esempio perché gli indici rendono la query orrendamente lenta rispetto alla scansione sequenziale.
Modifica: Penso di essere riuscito a scoprire un paio di cose passando attraverso la documentazione postgresql. Postgresql ha deciso di eseguire la scansione seq su alcune tabelle come offerte e articoli in quanto prevedeva che doveva recuperare ogni singola riga nella tabella (confrontare il numero di righe nella parentesi prima del tempo effettivo e il numero di righe nel tempo effettivo parte). La scansione sequenziale è migliore nel recupero di tutte le righe. Beh, nulla può essere fatto in quella parte.
Ho creato un indice aggiuntivo per categories(name)
e il risultato di seguito è quello che ho. In qualche modo è migliorato, ma ora l'hash join viene sostituito con il ciclo annidato. Qualche indizio sul perché?
GroupAggregate (cost=0.00..119552.02 rows=20 width=23) (actual time=617.330..7725.314 rows=20 loops=1)
Buffers: shared hit=178582 read=37473 written=14, temp read=2435 written=436
-> Nested Loop (cost=0.00..115051.55 rows=600036 width=23) (actual time=0.120..6186.496 rows=600036 loops=1)
Buffers: shared hit=178582 read=37473 written=14, temp read=2109 written=110
-> Nested Loop (cost=0.00..26891.55 rows=50000 width=19) (actual time=0.066..2827.955 rows=50000 loops=1)
Join Filter: (c.id = i.category)
Rows Removed by Join Filter: 950000
Buffers: shared hit=2 read=7334 written=1, temp read=2109 written=110
-> Index Scan using categories_name_idx on categories c (cost=0.00..12.55 rows=20 width=19) (actual time=0.039..0.146 rows=20 loops=1)
Buffers: shared hit=1 read=1
-> Materialize (cost=0.00..8280.00 rows=50000 width=8) (actual time=0.014..76.908 rows=50000 loops=20)
Buffers: shared hit=1 read=7333 written=1, temp read=2109 written=110
-> Seq Scan on items i (cost=0.00..7834.00 rows=50000 width=8) (actual time=0.007..170.464 rows=50000 loops=1)
Buffers: shared hit=1 read=7333 written=1
-> Index Scan using bid_itemid_idx on bids b (cost=0.00..1.60 rows=16 width=8) (actual time=0.016..0.036 rows=12 loops=50000)
Index Cond: (item_id = i.id)
Buffers: shared hit=178580 read=30139 written=13
Total runtime: 7726.392 ms
Date un'occhiata sul piano here se è meglio.
Sono riuscito a ridurlo a 114062.92 creando indice su categoria (id) e items(category)
. Postgresql ha utilizzato entrambi gli indici per ottenere il costo di 114062,92. Tuttavia, ora postgresql sta giocando con me non usando l'indice! perché è così buggy?
Per raggruppare per nome, è necessario ordinare per nome, anche se se metti un indice su categories.name potrebbe funzionare meglio. Metterei anche un indice su items.id per cercare di accelerare il distinto (i.id) e il join su b.item_id. –
Inoltre, tieni presente che Postgres "spiega il piano" potrebbe non darti buoni risultati fino a dopo aver fatto un "analisi del vuoto". –
grazie per la risposta @PaulTomblin. Yeap mi sono assicurato di aver usato l'analisi del vuoto prima di spiegare il piano per ottenere un risultato accurato. articoli.id è la chiave primaria per la tabella degli articoli, quindi conterrà l'indice cluster. – ImNoob