我经常看到人们用这样的查询来回答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优化持悲观态度,所以我喜欢尽我所能地帮助它。
2条答案
按热度按时间gwo2fgha1#
我想这可以用sleep()函数来测试,
例如,看看这个演示:http://sqlfiddle.com/#!2/0bc1b/1年
两个查询的执行时间约为3000毫秒(3秒)。
表中有3条记录,对于每条记录,查询只休眠1秒,
所以它意味着表达式对于每个记录只计算一次,而不是两次。
0h4hbjxa2#
在咨询了一位mysql工程师之后,我给出了这个冗长的答案。
缓存-查询的任何部分都不会被“记住”以供以后在该(或后续)查询中使用(对比度:查询缓存。)
通用子表达式消除-不。这是一种常见的编译器技术,但mysql不使用它。例子:
(a-b)*(a-b)
我要做两次减法。从循环中删除常量-是的,有限制。这是另一种编译器技术。
各种以sql为中心的黑客——是的;见下文。
重新计算子查询-视情况而定。而且,优化器也在逐渐变得更好。
VIEWs
-视情况而定。仍有案例表明VIEW
注定会表现得比同类产品差SELECT
. 示例:无条件下推到UNION
在一个VIEW
. 事实上,这更多的是一个延迟行动的问题。我认为mariadb的一些较新版本有一个“子查询缓存”。
(警告:我对我的任何答案都没有100%的信心,但我相信大部分答案都是正确的,如mysql 5.7、mariadb 10.1等)
想一想多排
SELECT
作为一个循环。许多,也许所有的“确定性”表达式只计算一次。例如:常量日期表达式,甚至包括函数调用。但是。。。NOW()
在查询开始时专门计算一次。此外,复制时会将值传递给从属服务器。也就是说,当查询存储在从属服务器上时,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的窗口函数对它们可以/不能重用的地方有一些非常严格的限制;我还没有他们的全貌。
一般来说,这些都无关紧要——对表达式的重新评估(
DATE(date)
甚至COUNT(*)
)会得到同样的答案。此外,在行中进行搜索通常比表达式求值要昂贵得多。所以,除非你有一个好的秒表,否则你不会分辨出区别。