我有一个复杂的查询,我必须在一个给我一些性能问题的应用程序中运行。我在这里简化了它。该数据库是CentOS上的MySQL 5.6.35。
SELECT a.`po_num`,
Count(*) AS item_count,
Sum(b.`quantity`) AS total_quantity,
Group_concat(`web_sku` SEPARATOR ' ') AS web_skus
FROM `order` a
INNER JOIN `order_item` b
ON a.`order_id` = b.`order_key`
WHERE `store` LIKE '%foobar%'
LIMIT 200 offset 0;
此查询的关键部分是我已放置" foobar"作为占位符。如果此值类似于big_store,则查询需要更长时间(在此处提供的查询中大约0.4秒,在我实际使用的查询中要长得多),而不是值为small_store(在查询中大约为0.1秒) )。如果没有限制,big_store会返回更多的结果。
但是有一个限制,这让我感到惊讶。两个数据集都超过LIMIT
,只有200.在我看来,MySQL为所有big_store / small_store行执行选择函数COUNT
,SUM
,GROUP_CONCAT
然后追溯应用LIMIT
。我想,当你到达200时,它最好停下来。
在抓取它将使用的200行之后,它是否可以执行选择功能COUNT
,SUM
,GROUP_CONCAT
操作,使我的查询更加快速?这对我来说似乎是可行的,除非在其中一行上有ORDER BY
。
MySQL是否不使用LIMIT
来优化查询选择功能?如果没有,那有充分的理由吗?如果是这样,我上面的想法是否犯了错误?
答案 0 :(得分:1)
由于LIMIT
,它可以停止播放,但这不是一个合理的查询,因为没有ORDER BY
。
如果没有ORDER BY
,它会选择它感觉到的200行并停止。
使用ORDER BY
时,必须扫描包含store
的整个表格(请限定列来自哪个列!)。这是因为前导通配符。只有这样才能修剪到200行。
另一个问题 - 没有GROUP BY
,聚合(SUM
等)会在整个表格中执行(或者至少在过滤后保留的那些表格)。 LIMIT
之前 不适用
也许您所询问的是MariaDB 5.5.21的“LIMIT_ROWS_EXAMINED”。
以这种方式思考...... SELECT
的所有组件都是按语法指定的顺序完成的。由于LIMIT
是最后一个,因此在执行其他内容之后才会适用。
(有几个例外:(1)SELECT col...
必须在FROM ...
之后完成,因为它不知道哪个表;(2)优化器很容易重新排序{{1 JOINed
中的表和子句。)
有关该查询的更多详情。
WHERE ... AND ...
正在WHERE
上过滤(order
是哪里,是吗?),所以它决定从表{{}开始1}}。store
获取与order
匹配的所有行。order
中的行。现在它有一些行(可能超过200)用于聚合。%foobar%
,order_item
,COUNT
。 (实际上这可能会在收集行时进行 - 另一种优化。)SUM
的值不可预测。)GROUP_CONCAT
po_num
部分的0行。 (好吧,另一个无序的东西。)添加OFFSET
(但没有LIMIT
) - 大不了,排序1行。
添加ORDER BY
(但没有GROUP BY
),现在您可能有超过200行,并且可以停止。
添加GROUP BY
和 ORDER BY
和它们是相同的,然后可能必须进行排序分组,但不是为了排序,它可能在200停止。
添加GROUP BY
和 ORDER BY
和他们不相同,然后可能必须对分组进行排序,并且将必须重新排序以进行排序,并且在之后 GROUP BY
之前不能停在200。也就是说,几乎所有的工作都是在所有数据上进行的。
哦,如果你没有最佳指数,所有这一切都会变得更糟。哦,我没有坚持提供ORDER BY
吗?