如何使用左连接优化查询

时间:2016-10-12 13:24:46

标签: sql postgresql left-join

请帮助优化我的查询:

select id, paid_till, rating, paid 
from lots
left join (select 1 paid) paid on current_timestamp <= lots.paid_till 
order by paid asc, rating desc, updated_at desc;

查询计划:

Sort  (cost=1948.17..1948.18 rows=4 width=28) (actual time=0.703..0.704 rows=4 loops=1)
  Sort Key: (1), lots.rating DESC, lots.updated_at DESC
  Sort Method: quicksort  Memory: 25kB
  ->  Nested Loop Left Join  (cost=0.00..1948.13 rows=4 width=28) (actual time=0.014..0.682 rows=4 loops=1)
     Join Filter: (now() <= lots.paid_till)
     Rows Removed by Join Filter: 2
     ->  Seq Scan on lots  (cost=0.00..1948.04 rows=4 width=24) (actual time=0.008..0.675 rows=4 loops=1)
     ->  Materialize  (cost=0.00..0.03 rows=1 width=4) (actual time=0.001..0.001 rows=1 loops=4)
           ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.000..0.000 rows=1 loops=1)

Planning time: 0.210 ms
Execution time: 0.724 ms

我应该添加哪些指数?我如何修复&#34;嵌套循环左连接&#34;?

P.S。我不能在select中使用虚拟列进行排序,导致Rails问题。

2 个答案:

答案 0 :(得分:2)

获得paid值的奇怪方法。改为使用CASE表达式:

select 
  id, 
  paid_till, 
  rating, 
  case when current_timestamp <= paid_till then 1 else 0 end as paid 
from lots
order by paid asc, rating desc, updated_at desc;

但是,这可能会加快查询速度。没有WHERE子句,因此必须读取完整的表。我认为加快速度的唯一方法是覆盖索引:

create index idx_quick on lots
(
  case when current_timestamp <= paid_till then 1 else 0 end,
  rating,
  updated_at desc,
  paid_till,
  id)
;

但为此查询制作索引裁剪似乎有点过分。

答案 1 :(得分:1)

要摆脱左连接使用:

select id, paid_till, rating, paid_till is null as paid
from lots
where current_timestamp <= lots.paid_till 
   or paid_till is null
order by 4 asc, rating desc, updated_at desc;

不确定你的意思“我不能在select中使用虚拟列进行排序,导致Rails问题”但如果你的混淆层无法对表达式进行排序,你可以这样做:

select *
from (
    select id, paid_till, rating, paid_till is null as paid
    from lots
    where current_timestamp <= lots.paid_till 
       or paid_till is null
) t    
order by paid asc, rating desc, updated_at desc;

或者简单地在末尾对所有未付费的行进行排序,而根本不使用paid表达式:

select id, paid_till, rating
from lots
where current_timestamp <= lots.paid_till 
   or paid_till is null
order by paid_till asc nulls last, rating desc, updated_at desc;

以上所有内容都将摆脱“嵌套循环左连接”步骤。但我真的怀疑这是你的问题 - 即使是在制作上。大表的“Seq Scan on lots”将产生更大的影响。

如果条件current_timestamp <= lots.paid_till仅返回该表的一小部分,则在paid_till列上放置索引可能会有所帮助。如果你能摆脱or paid_till is null条件,它会更有帮助。这可以通过为那些尚未支付的行存储'infinity'而不是null来实现。如果该列中没有null值,则条件可以减少到where current_timestamp <= lots.paid_till使用索引,如果它比Seq Scan更便宜。

要了解优化程序何时使用索引,您可能希望阅读thisthis

相关问题