【问题标题】:ORDER BY column from right table of LEFT OUTER JOINLEFT OUTER JOIN 右表的 ORDER BY 列
【发布时间】:2015-07-23 21:43:57
【问题描述】:

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

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)

【问题讨论】:

  • 请发布您的EXPLAIN ANALYZE 的完整输出(点击edit 并将其添加到问题中)。
  • (these tables are replicated, so changing the structure will require a major refactoring of our project). 数据模型设计问题也是真正的问题。如果它是错误的:改变它。现在。或者更好:昨天。
  • 请参考[postgresql-performance]标签信息中的性能查询说明。
  • @IMSoP - 我添加了 EXPLAIN ANALYZE 输出。谢谢

标签: sql postgresql join sql-order-by postgresql-performance


【解决方案1】:

由于您只对来自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 所必需的。

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

【讨论】:

  • 您好,感谢您的回复。我尝试使用联合声明,但在性能方面结果是相同的。我为问题中的查询添加了解释分析结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多