请帮助优化我的查询:
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问题。
答案 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更便宜。