TL;博士
所选答案中的查询“应该有效”;用平凡的集合表现很好。但对于大型集,这将是地狱般的表现。
为了获得最佳性能,我们希望使用在范围条件中引用裸列的查询。像这样的东西:
SELECT from_unixtime( `lastlogin` ) AS `last`
FROM `players`
WHERE `lastlogin` > 0
AND `lastlogin` < UNIX_TIMESTAMP('2012-10-01 00:00:00')
原始答案
列别名last
(在您的查询中)不能在 WHERE 子句(您的查询)中引用。这是一条 MySQL 语法规则。(基本上,该规则的原因是该别名引用的表达式在处理 WHERE 子句中的谓词时不可用。)
HAVING
但是可以在子句的谓词中引用该列别名。该HAVING
子句几乎在执行计划结束时得到处理。这可行,但从性能的角度来看是有问题的:
SELECT from_unixtime( `lastlogin` ) AS `last`
FROM `players` WHERE `lastlogin` <> 0
HAVING `last` < '2012-10-01 00:00:00';
其执行计划几乎等同于使用内联视图(创建派生表)并针对派生表运行 SELECT(从性能角度来看这也是有问题的):
SELECT d.*
FROM (
SELECT from_unixtime( `lastlogin` ) AS `last`
FROM `players` WHERE `lastlogin` <> 0
) d
WHERE `last` < '2012-10-01 00:00:00';
列别名last
可以在这里引用,因为内部查询(别名为 d 的内联视图)首先运行,结果集存储为 MyISAM 表。然后外部查询针对 MyISAM 表运行。在这个查询中,last
它引用了表中的列名,因此可以在 WHERE 子句中引用它。
重要的提示:
所以那种回答你问的问题。但,
你真的不想那样做!
这种方法对于大型集合会表现出问题的性能,因为此查询本质上是创建表的副本,然后在副本上运行查询。将对表中的每一行执行 from_unixtime 函数(除了 lastlogin 为 NULL 或等于 0 的行。)
从性能的角度来看,使用单个查询(无内联视图)并在 WHERE 子句中的裸列上使用谓词要好得多。
理想情况下,lastlogin
将存储为 DATETIME 或 TIMESTAMP 数据类型。但是,如果该列是整数,那么将谓词中的文字常量转换为整数,然后将其与裸列进行比较会更好(性能方面)。这将允许 MySQL 至少考虑对具有lastlogin
作为前导列的索引进行范围扫描,而不是from_unixtime
对每一行执行函数,以与文字进行比较。
MySQL 提供了一个方便的UNIX_TIMESTAMP()
函数来将 DATETIME 转换为整数值(它基本上是函数的逆FROM_UNIXTIME()
函数,但有一些注意事项。
为了获得最佳性能,我们需要以下形式的查询:
SELECT from_unixtime( `lastlogin` ) AS `last`
FROM `players`
WHERE `lastlogin` <> 0
AND `lastlogin` < UNIX_TIMESTAMP('2012-10-01 00:00:00')