postgres中的表连接顺序

Jay*_*Jay 10 sql database postgresql

我有办法强制在Postgres中使用特定的连接顺序吗?

我有一个看起来像这样的查询.我已经删除了一些真实查询中的东西,但这种简化证明了这个问题.剩下的不应该太神秘:使用角色/任务安全系统,我试图确定给定用户是否具有执行给定任务的权限.

select task.taskid
from userlogin
join userrole using (userloginid)
join roletask using (roleid)
join task using (taskid)
where loginname='foobar'
and taskfunction='plugh'
Run Code Online (Sandbox Code Playgroud)

但我意识到该程序已经知道userlogin的价值,所以通过跳过userlogin上的查找并只填写userloginid似乎可以提高查询效率,如下所示:

select task.taskid
from userrole
join roletask using (roleid)
join task using (taskid)
where userloginid=42
and taskfunction='plugh'
Run Code Online (Sandbox Code Playgroud)

当我这样做 - 从查询中删除一个表并对从该表中检索到的值进行硬编码时 - 解释计划时间就会增加!在原始查询中,Postgres读取userlogin然后userrole然后roletask然后task.但是在新查询中,它决定先读取roletask,然后加入userrole,即使这需要对roletask进行全文扫描.

完整的解释计划是:

版本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) 
Run Code Online (Sandbox Code Playgroud)

版本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) 
Run Code Online (Sandbox Code Playgroud)

(是的,我知道在这两种情况下成本都很低,差异看起来并不重要.但这是在我从查询中删除了一堆额外的工作以简化我要发布的内容之后.真正的查询仍然没有离谱,但我对这个原则更感兴趣.)

Bil*_*win 6

文档中的这个页面描述了如何防止PostgreSQL优化器重新排序连接表,允许您自己控制连接的顺序:

http://www.postgresql.org/docs/current/interactive/explicit-joins.html

  • PostgreSQL确实拥有我见过的最好的RDBMS文档. (5认同)