¿Hay alguna manera de forzar una orden de unión específica en Postgres?Orden de unión de tabla en postgres
Tengo una consulta que se parece a esto. Eliminé un montón de cosas que estaban en la consulta real, pero esta simplificación demuestra el problema. Lo que queda no debe ser demasiado críptico: al usar un sistema de seguridad de roles/tareas, estoy tratando de determinar si un usuario dado tiene privilegios para realizar una tarea determinada.
select task.taskid
from userlogin
join userrole using (userloginid)
join roletask using (roleid)
join task using (taskid)
where loginname='foobar'
and taskfunction='plugh'
pero me di cuenta que el programa ya conoce el valor de userlogin, por lo que parecía la consulta podría ser más eficiente por saltarse la búsqueda en userlogin y simplemente rellenando el userloginid, así:
select task.taskid
from userrole
join roletask using (roleid)
join task using (taskid)
where userloginid=42
and taskfunction='plugh'
Cuando lo hice, eliminando una tabla de la consulta y codificando el valor recuperado de esa tabla en su lugar, ¡el tiempo del plan de explicación se incrementó! En la consulta original, Postgres leyó userlogin luego userrole luego roletask then task. Pero en la nueva consulta, decidió leer roletask primero y luego unirse a userrole, aunque esto requería hacer un escaneo de archivo completo en roletask.
completa explicar los planes son:
Versión 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)
Versión 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í, ya sé que en ambos casos los costos son bajos y la diferencia doesn Parece que no importaría, pero esto es después de que eliminé un montón de trabajo adicional de la consulta para simplificar lo que tengo que publicar. La consulta real aún no es escandalosa, pero estoy más interesado en t . El principio)
¿Puede mostrar los planes de consulta (explicar el análisis) y las definiciones de tabla? – hgmnz
Bien, preguntaste, reemplacé el ejemplo simple hipotético con la consulta real y agregué los resultados del plan de explicación. Oh, estoy seguro de que podría agregar algunos índices adicionales para acelerar la segunda consulta, pero ese no es el punto. ¿Por qué Postgres eligió un plan que era menos que lo mejor que podía hacer, dadas las consultas que tenía? ¿Especialmente cuando demostró que podría mejorar si hiciera la consulta más complicada? – Jay
¿está comparando los tiempos de ejecución reales de las consultas o simplemente mirando el costo del título en el plan de explicación? ¿los costos? en particular, acaba de publicar la salida de explicación, no explicar analizar. aunque podría esperar un costo mayor para igualar a una ejecución de consulta más lenta, podría no funcionar de esa manera. – araqnid