1

我正在建立一个博客,但我遇到了问题。应该有一些粘性帖子。我想要的只是首先获得粘性帖子,然后是其余的。

一个有效的查询是

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 行在内存中排序不是很快..

有办法优化吗??

使用两个单独的查询会更好吗?谢谢

4

3 回答 3

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 支持在计算字段上创建索引,这在这里会有所帮助,但有一个限制:

索引定义中使用的所有函数和运算符都必须是“不可变的”,也就是说,它们的结果必须仅取决于它们的参数,而不是任何外部影响(例如另一个表的内容或当前时间)。

所以你不能索引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

但是让轮询过程进行更新不如直接查询有吸引力。这只有在您的查询非常慢或对博客表有大量读取时才有意义。

于 2012-05-30T00:57:05.250 回答
1

我认为你最好运行两个查询,一个用于粘性帖子,一个用于其余的。

SQL 不保证结果的顺序,没有明确的 order by。虽然 UNION ALL 的结果可能看起来正确,但不能保证。这在多线程环境中变得更加明显,您不知道哪个线程将首先完成读取数据并开始返回结果。

最有效的解决方法是将其作为两个不同的查询来完成。

于 2012-05-30T02:34:14.190 回答
0
select * 
from blog
order by 
    coalesce("stickyUntil", '1901-01-01'::date) < current_timestamp, 
    publish DESC 
OFFSET x LIMIT z
于 2012-05-30T11:28:48.443 回答