我经常看到人们通过这样的查询回答MySQL问题:
SELECT DAY(date), other columns
FROM table
GROUP BY DAY(date);
SELECT somecolumn, COUNT(*)
FROM table
HAVING COUNT(*) > 1;
我总是希望为列添加别名,并参考GROUP BY
或HAVING
子句中的别名,例如
SELECT DAY(date) AS day, other columns
FROM table
GROUP BY day;
SELECT somecolumn, COUNT(*) AS c
FROM table
HAVING c > 1;
MySQL是否足够聪明,注意到后面的子句中的表达式与SELECT
中的表达式相同,只执行一次?我不确定如何测试这一点 - EXPLAIN
并没有显示出任何差异,但它似乎并没有显示它是如何进行分组或过滤的第一名;它似乎主要用于优化连接和WHERE
子句。
我倾向于对MySQL优化感到悲观,所以我想尽我所能给予它。
答案 0 :(得分:5)
我认为这可以使用sleep()函数测试,
例如,看一下这个演示:http://sqlfiddle.com/#!2/0bc1b/1
Select * FROM t;
| X |
|---|
| 1 |
| 2 |
| 2 |
SELECT x+sleep(1)
FROM t
GROUP BY x+sleep(1);
SELECT x+sleep(1) As name
FROM t
GROUP BY name;
两个查询的执行时间约为3000毫秒(3秒)
表中有3条记录,对于每条记录,查询仅休眠1秒,
所以这意味着表达式只针对每条记录评估一次,而不是两次。
答案 1 :(得分:1)
在咨询了一位MySQL工程师之后,我提出了这个冗长的答案。
(a-b)*(a-b)
将执行两次减法。VIEWs
- 这取决于。仍然存在VIEW
注定比同等SELECT
更差的情况。示例:无条件下推到UNION
中的VIEW
。实际上,这更多是延迟行动的问题。(警告:我对我的任何答案都没有100%的信心,但我相信大部分都是正确的,如MySQL 5.7,MariaDB 10.1等)
将多行SELECT
视为循环。许多,也许全部,"确定性"表达式被评估一次。示例:常量日期表达式,甚至涉及函数调用。但...
NOW()
在查询开始时专门评估一次。此外,复制时该值将传递给Slaves。也就是说,当查询存储在从属服务器上时,NOW()
可能已过期。 (SYSDATE()
是另一种动物。)
特别是only_full_group_by
的出现,GROUP BY
需要知道它是否与SELECT
表达式匹配。所以,这会查找类似的代码。
HAVING
和ORDER BY
可以使用SELECT
列表中的别名(与WHERE
和GROUP BY
不同)。因此,SELECT expr AS x ... HAVING expr
似乎会重新评估expr
,但SELECT expr AS x ... HAVING x
似乎已达到已评估的expr
。
MariaDB 10.2的Windowing功能对它们可以/不能重用的位置有一些非常严格的限制;我还没有完整的图片。
一般来说,这一切都不重要 - 对表达式(DATE(date)
甚至COUNT(*)
)的重新评估会得到相同的答案。此外,通过行的翻找通常比表达评估昂贵得多。所以,除非你有一个好的秒表,否则你不会说出差异。