繁体   English   中英

LEFT OUTER JOIN右表中的ORDER BY列

[英]ORDER BY column from right table of LEFT OUTER JOIN

使用LEFT OUTER JOIN并尝试使用Postgres右表中的列时,我遇到严重的性能问题。 我有一个用户表和一个带有online_users的表,该表列出了我网站上在线的用户ID。 两个表在用户标识中都有索引。 我需要在用户表上运行选择,并首先列出在线的用户,然后列出不在线的用户。 所以我的选择是:

SELECT *
FROM users
LEFT JOIN online_users ON (users.id = online_users.usr_id)
ORDER BY online_users.online_date

我在users.idonline_users.usr_idonline_users.online_date上都有索引,但是由于某些原因,当我在查询上运行ANALYZE时,Postgres不会使用online_users.online_date的索引,并且完整扫描会破坏查询的性能。

有什么方法可以在不更改表结构的情况下优化此查询(这些表已复制,因此更改结构将需要对项目进行重大重构)。

Postgre版本是9.3

以下是解释分析:

                                                          QUERY PLAN                                                             
------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=2589440.94..2595456.84 rows=2406361 width=506) (actual time=18635.686..25775.334 rows=2239030 loops=1)
   Sort Key: usuarios_online.datamessenger
   Sort Method: external merge  Disk: 512424kB
   ->  Hash Left Join  (cost=219.73..130113.66 rows=2406361 width=506) (actual time=0.723..12388.266 rows=2239030 loops=1)
         Hash Cond: (usuarios.id = usuarios_online.id_usr)
         ->  Seq Scan on usuarios  (cost=0.00..108832.61 rows=2406361 width=494) (actual time=0.009..7328.191 rows=2238984 loops=1)
         ->  Hash  (cost=212.66..212.66 rows=566 width=12) (actual time=0.704..0.704 rows=572 loops=1)
               Buckets: 1024  Batches: 1  Memory Usage: 27kB
               ->  Seq Scan on usuarios_online  (cost=0.00..212.66 rows=566 width=12) (actual time=0.079..0.555 rows=572 loops=1)
 Total runtime: 28519.611 ms
(10 rows)

由于您只从online_users订购行,因此可以改用UNION查询:

(
SELECT usr_id, online_date  -- more columns?
FROM   online_users
ORDER  BY online_date
)
UNION ALL
SELECT u.id, NULL  -- more matching columns?
FROM   users u
LEFT   JOIN online_users o ON u.id = o.usr_id
WHERE  o.usr_id IS NULL;

在任何情况下都应该更快。

online_users可以轻松地使用online_date上的索引。
这两个简单的查询计划通常可以更轻松地使用索引。
所有其他用户完全不需要排序。 第二个SELECT只需要排除online_users

在第一个SELECT周围必须加上括号,以允许将ORDER BY放在我的位置。

这可能会进一步优化,具体取决于案例的未声明细节。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM