2011-10-25 9 views
5

Ho una query che esegue molto più lentamente (~ 5 minuti) quando la eseguo con il default enable_nestloop = true e enable_nestloop = false (~ 10 secondi).Postgresql - Query eseguita molto più velocemente con enable_nestloop = false. Perché il pianificatore non sta facendo la cosa giusta?

Spiegate risultato analizzare per entrambi i casi:

macchina A nestloop = true - http://explain.depesz.com/s/nkj0 (~ 5 minuti) macchina A nestloop = false - http://explain.depesz.com/s/wBM (~ 10 secondi)

in diversi macchina leggermente più lento , copiando il database e lasciando il default enable_nestloop = true ci vogliono ~ 20 sec.

macchina B nestloop = true - (~ 20secs)

Per tutti i casi di cui sopra ho assicurato che ho fatto un ANALYZE prima di eseguire le query. Non c'erano altre query in esecuzione in parallelo.

Entrambe le macchine utilizzano Postgres 8.4. La macchina A esegue Ubuntu 10.04 a 32 bit mentre la macchina B esegue Ubuntu 8.04 a 32 bit.

La query effettiva è disponibile qui. Si tratta di una query di reporting con molti join poiché il database viene utilizzato principalmente per l'elaborazione delle transazioni.

  1. Senza ricorrere a mettere in qualcosa di simile viste materializzate cosa posso fare per rendere il pianificatore fare ciò che ho raggiunto impostando enable_nestloop = false?

  2. Dalla ricerca che ho fatto sembra che il motivo per cui il pianificatore sta scegliendo la query apparentemente non ottimale è a causa dell'enorme differenza tra le righe stimate e quelle effettive. Come posso avvicinare questa figura?

  3. Se dovessi riscrivere la query, cosa dovrei cambiare?

  4. Perché il pianificatore sembra fare la cosa giusta per la Macchina B. Che cosa dovrei confrontare in entrambe le macchine?

+0

Collegamenti dalla domanda precedente che è stato necessario rimuovere - query - http://pastie.org/2754424 – Mohan

+0

Spiegare l'analisi per la macchina B - http://explain.depesz.com/s/dYO – Mohan

risposta

2

Risulta riscrivere la query era la soluzione migliore. La query è stata scritta in un modo che si basava molto sui join di sinistra e aveva molti join. L'ho appiattito e ridotto i join di sinistra utilizzando la mia conoscenza della natura di join dei dati nelle tabelle a cui si stava aggiungendo la query. Immagino che la regola generale sia che se il pianificatore sta uscendo con stime davvero scadenti, potrebbe esserci un modo migliore di scrivere la query.

2

Se il pianificatore di query sceglie piani di query non ottimali, allora è probabile che si dispone di informazioni incomplete o fuorvianti con cui lavorare.

Vedere questo PostgreSQL Wiki page sull'ottimizzazione del server. Prestare particolare attenzione ai capitoli su random_page_cost e default_statistics_target.
Leggere anche i capitoli corrispondenti nel manuale su Statistics Used by the Planner e Planner Cost Constants.

Più precisamente, si potrebbe contribuire ad aumentare la statistics target per le seguenti colonne:

ALTER TABLE postgres.products ALTER COLUMN id SET STATISTICS 1000; 
ALTER TABLE postgres.sales_orders ALTER COLUMN retailer_id SET STATISTICS 1000; 
ALTER TABLE postgres.sales_orders ALTER COLUMN company_id SET STATISTICS 1000; 

ALTER TABLE goods_return_notes ALTER COLUMN retailer_id SET STATISTICS 1000; 
ALTER TABLE goods_return_notes ALTER COLUMN company_id SET STATISTICS 1000; 

ALTER TABLE retailer_category_leaf_nodes ALTER COLUMN tree_left SET STATISTICS 1000; 
ALTER TABLE channels ALTER COLUMN principal_id SET STATISTICS 1000; 

Questi sono coinvolti nei filtri con conseguente l'enorme differenza

tra le righe previste e quelle effettive.

Ci sono altro. Controlla ogni colonna in cui la piallatrice si discosta molto dalla stima. Il valore predefinito è solo 100. Ha senso solo per le tabelle con >> 1000 righe. Sperimenta con l'impostazione. Eseguire ANALYZE nelle tabelle in seguito affinché le modifiche abbiano effetto.

Potrebbe anche contribuire a creare un indice parziale su postgres(sales_orders.retailer_id) WHERE retailer_id IS NOT NULL (a seconda di come valori NULL sono comuni).


Un'altra cosa che può aiutare è quello di aggiornamento alla versione più recente 9.1. Ci sono stati numerosi miglioramenti sostanziali in questo settore.

+0

Apprezzo il fatto che il la configurazione può fare la differenza. Tuttavia la configurazione tra la macchina A e la macchina B sono identiche. Conoscete i parametri specifici del tipo pg_stats che dovrei guardare? – Mohan

+0

@Mohan: ho modificato la mia risposta con suggerimenti più specifici. –

+0

Grazie Erwin. Abbiamo provato ad aggiornare a 9.1 e ad impostare random_page_cost su un valore più basso, senza alcun risultato. Proverò i tuoi altri suggerimenti. – Mohan

0

Di solito c'è una sola ragione per piani diversi per gli stessi dati e le stesse query su due server con lo stesso PostgreSQL. Questa è una configurazione diversa, principalmente valore di work_mem. L'hash join è in genere più veloce, ma richiede molta memoria disponibile.

2

Questa lettura potrebbe essere utile: PostgreSQL tutorial about explicit JOINs.

Il pianificatore di query tenta di analizzare l'ordine JOIN per trovare l'ordine migliore per JOINing.

Ho visto La tua query ha avuto almeno 15 JOIN. Il numero di possibili ordini JOIN sale come fattoriale (n!). Quindi non è ragionevole che il pianificatore di query cerchi di trovare il miglior ordine JOIN se ci sono 15 JOIN - dovrebbe guardare 15! = 1307674368000 piani diversi.

Quindi utilizza Genetic Query Optimizer. Vedi Query Planning: Genetic Query Optimizer parameters. Il parametro "geqo_threshold" determina quanti JOIN devono essere presenti per il pianificatore di query per utilizzare Genetic Query Optimizer.

In questo modo il planner PostgreSQL analizza solo una piccola parte delle possibili varianti e cerca di trovare il migliore (a caso). Quindi ogni volta che esegui ANALYZE, potrebbe venire con un piano migliore.

Penso che in generale, se hai così tante tabelle da JOIN, stai meglio facendo come hai fatto tu: riscrivendo la query in ordine JOIN ottimale.

Problemi correlati