我正在建立博客,但我遇到了问题。应该有一些粘性帖子。我想要的只是获得粘贴帖子,然后是其余的。
一个有效的查询是
select * from
(
(select *,true as st from blog where "stickyUntil" > current_timestamp)
UNION all
(SELECT *,false as st from blog where "stickyUntil" < current_timestamp or "stickyUntil" is null )
) q
order by st desc, "stickyUntil" DESC ,publish DESC OFFEST x LIMIT z
另一个更简单的查询是workz
select * from blog order by case when "stickyUntil" > current_timestamp then "stickyUntil" end desc nulls last, publish desc;
但这会迫使200,000行在内存中排序不是很快..
有没有办法优化它?
使用两个单独的查询会更好吗? 感谢
答案 0 :(得分:3)
我会使用CASE语句来避免表格的两次传递:
select *,
CASE
WHEN "stickyUntil" > current_timestamp THEN true
ELSE false
END as st
FROM blog
ORDER BY st DESC ,publish DESC OFFEST x LIMIT z
Postgres支持在计算字段上创建INDEX,这对此有帮助,但存在限制:
索引定义中使用的所有函数和运算符必须是&#34; immutable&#34;, 也就是说,他们的结果必须仅依赖于他们的论点,而不是任何依据 外部影响(例如另一张桌子的内容或当前时间)。
因此您无法索引 st 计算。如果 st 的计算不需要太精确,则另一个选项是将 st 字段添加到表中:
ALTER TABLE blog
ADD COLUMN st boolean default true
INDEX st 作为常规列:
CREATE INDEX sti ON blog(st)
并定期运行:
UPDATE blog
SET st = false
WHERE st = true
AND "stickyUntil" < current_timestamp
但是进行更新的轮询过程远比直接查询更具吸引力。这只有在您的查询非常慢或者博客表的大量读取时才有意义。
答案 1 :(得分:1)
我认为你最好不要运行两个查询,一个用于粘贴帖子,另一个用于其他查询。
SQL不保证结果的排序,没有明确的顺序。尽管UNION ALL的结果似乎正确,但您无法保证。这在多线程环境中变得更加明显,在这种环境中,您不知道哪个线程将首先完成读取数据并开始返回结果。
最有效的解决方法是将其作为两个不同的查询。
答案 2 :(得分:0)
select *
from blog
order by
coalesce("stickyUntil", '1901-01-01'::date) < current_timestamp,
publish DESC
OFFSET x LIMIT z