C'è un modo per forzare uno specifico ordine di join in Postgres?Ordine di join tabella in postgres
Ho una query simile a questa. Ho eliminato un sacco di cose che erano nella vera query, ma questa semplificazione dimostra il problema. Ciò che rimane non deve essere troppo criptico: utilizzando un sistema di sicurezza ruolo/compito, sto cercando di determinare se un determinato utente ha i privilegi per eseguire una determinata attività.
select task.taskid
from userlogin
join userrole using (userloginid)
join roletask using (roleid)
join task using (taskid)
where loginname='foobar'
and taskfunction='plugh'
Ma ho capito che il programma conosce già il valore di userlogin, così sembrava la query potrebbe essere reso più efficiente saltando la ricerca sul UserLogin e solo compilando l'userloginid, in questo modo:
select task.taskid
from userrole
join roletask using (roleid)
join task using (taskid)
where userloginid=42
and taskfunction='plugh'
Quando l'ho fatto - eliminando una tabella dalla query e codificando il valore recuperato da quella tabella - il tempo del piano di spiegazione è aumentato! Nella query originale, Postgres legge userlogin quindi userrole quindi roletask quindi task. Ma nella nuova query, ha deciso di leggere prima roletask e quindi di unirsi a userrole, anche se ciò richiedeva una scansione di file completi su roletask.
completa Spiegare i piani sono:
Versione 1:
Hash Join (cost=12.79..140.82 rows=1 width=8)
Hash Cond: (roletask.taskid = task.taskid)
-> Nested Loop (cost=4.51..129.73 rows=748 width=8)
-> Nested Loop (cost=4.51..101.09 rows=12 width=8)
-> Index Scan using idx_userlogin_loginname on userlogin (cost=0.00..8.27 rows=1 width=8)
Index Cond: ((loginname)::text = 'foobar'::text)
-> Bitmap Heap Scan on userrole (cost=4.51..92.41 rows=33 width=16)
Recheck Cond: (userrole.userloginid = userlogin.userloginid)
-> Bitmap Index Scan on idx_userrole_login (cost=0.00..4.50 rows=33 width=0)
Index Cond: (userrole.userloginid = userlogin.userloginid)
-> Index Scan using idx_roletask_role on roletask (cost=0.00..1.50 rows=71 width=16)
Index Cond: (roletask.roleid = userrole.roleid)
-> Hash (cost=8.27..8.27 rows=1 width=8)
-> Index Scan using idx_task_taskfunction on task (cost=0.00..8.27 rows=1 width=8)
Index Cond: ((taskfunction)::text = 'plugh'::text)
Versione 2:
Hash Join (cost=96.58..192.82 rows=4 width=8)
Hash Cond: (roletask.roleid = userrole.roleid)
-> Hash Join (cost=8.28..104.10 rows=9 width=16)
Hash Cond: (roletask.taskid = task.taskid)
-> Seq Scan on roletask (cost=0.00..78.35 rows=4635 width=16)
-> Hash (cost=8.27..8.27 rows=1 width=8)
-> Index Scan using idx_task_taskfunction on task (cost=0.00..8.27 rows=1 width=8)
Index Cond: ((taskfunction)::text = 'plugh'::text)
-> Hash (cost=87.92..87.92 rows=31 width=8)
-> Bitmap Heap Scan on userrole (cost=4.49..87.92 rows=31 width=8)
Recheck Cond: (userloginid = 42)
-> Bitmap Index Scan on idx_userrole_login (cost=0.00..4.49 rows=31 width=0)
Index Cond: (userloginid = 42)
(Sì, lo so che in entrambi i casi i costi sono bassi e la differenza doesn Sembra che sia importante, ma dopo aver eliminato un po 'di lavoro aggiuntivo dalla query per semplificare ciò che devo pubblicare, la query reale non è oltraggiosa, ma sono più interessata a . L principio)
È possibile visualizzare i piani di query (spiega analisi) e le definizioni di tabella? – hgmnz
Ok, hai chiesto, ho sostituito l'ipotetico semplice esempio con la query reale e ho aggiunto i risultati del piano di spiegazione. Oh, sono sicuro che potrei aggiungere alcuni indici aggiuntivi per accelerare la seconda query, ma non è questo il punto. Perché Postgres ha scelto un piano che era meno del meglio che poteva fare, date le domande che aveva? Soprattutto quando ha dimostrato che avrebbe potuto fare meglio se avessi reso la query più complicata? – Jay
stai confrontando i tempi di esecuzione effettivi delle query o semplicemente guardando il costo principale nel piano di spiegazione? i costi? in particolare, hai appena pubblicato spiegare l'output, non spiegare analizzare. anche se ti aspetteresti un costo più alto da equiparare a una più lenta esecuzione della query, potrebbe non funzionare in questo modo. – araqnid