根据当前时间的条件订购的正确方法是什么?

时间:2015-11-25 06:12:35

标签: mysql sql explain

我需要订购记录并将“热门”(推广)记录放在首位。如果记录的hot_expires_at列不为空且未来,则该记录为“热门”。目前我有这个简单明了的解决方案:

ORDER BY
  IF( hot_expires_at IS NOT NULL AND hot_expires_at > NOW(),
      hot_expires_at, from_unixtime(0)) DESC, 
  created_at DESC

然而,这需要一个文件分区,并且随着时间的推移变得非常慢,因为我有数十万条记录。 (如果有帮助的话,其中只有一小部分是“热门”。)

我知道我可以运行一个额外的工作,每隔几分钟计算一次rank字段 - 这将足够接近实时。但这似乎是一种蛮力的解决方案。

我还可以将查询拆分为两个(“hot”和“not”),并添加组合结果的外部逻辑,但这也很粗糙且容易出错。

我正在寻找在MySQL中使用MySQL设施的正确方法。

2 个答案:

答案 0 :(得分:0)

我会以与现在略有不同的方式解决此问题。首先,我会废除时间戳字段hot_expires_at的概念,对于旧记录而言NULL,而对于#34; hot"而不是NULL。记录。相反,我会将名称更改为expires_at,我会确保每个记录都有这样的字段。关于这种设计的清洁之处在于,它使您不必存储记录是否热的状态。相反,时间戳本身包含确定标签所需的所有信息。

出于报告的目的,您可以SELECT确定给定记录是否为热点"只需检查它是否会在将来的某个时间点到期。因此,以下类型的查询应该完成这项工作:

SELECT *, CASE WHEN expires_at > NOW() THEN "hot" ELSE "not" END AS is_hot
FROM your_table
ORDER BY expires_at DESC, created_at DESC

答案 1 :(得分:0)

当您使用函数NOW()时,它每次都会返回一个值来评估每条记录。正如您所提到的,您拥有数十万条记录,因此他们的评估需要花费很多时间。我认为你必须修改用于IF语句的值,例如在查询开始之前使用由NOW()初始化的变量或者使用SYSDATE()函数。

“另外,SET TIMESTAMP语句会影响NOW()而不是SYSDATE()返回的值。这意味着二进制日志中的时间戳设置对SYSDATE()的调用没有影响。将时间戳设置为a非零值会导致NOW()的每次后续调用返回该值。将timestamp设置为零会取消此效果,以便NOW()再次返回当前日期和时间。“