mysql是否消除了select和having/groupby子句之间的公共子表达式

vaj7vani  于 2021-06-18  发布在  Mysql
关注(0)|答案(2)|浏览(244)

我经常看到人们用这样的查询来回答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优化持悲观态度,所以我喜欢尽我所能地帮助它。

gwo2fgha

gwo2fgha1#

我想这可以用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秒,
所以它意味着表达式对于每个记录只计算一次,而不是两次。

0h4hbjxa

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(*) )会得到同样的答案。此外,在行中进行搜索通常比表达式求值要昂贵得多。所以,除非你有一个好的秒表,否则你不会分辨出区别。

相关问题