我有一个很大的查询,它本身运行得很好。它有很多join
个语句。所以,它的结构如下:
SELECT ... FROM mytable t
LEFT OUTER JOIN mytable2 t2 ON t2.attr = t.attr1
LEFT OUTER JOIN mytable3 t3 ON t3.attr = t.attr3
...
LEFT OUTER JOIN mytableN tN ON tN.attr = t.attrN
它只运行一毫秒。但是如果我添加LIKE语句:
SELECT ... FROM mytable t
LEFT OUTER JOIN mytable2 t2 ON t2.attr = t.attr1
LEFT OUTER JOIN mytable3 t3 ON t3.attr = t.attr3
...
LEFT OUTER JOIN mytableN tN ON tN.attr = t.attrN
WHERE tK.attrP LIKE '%Something%'
然后它几乎永远不会结束。我不能等到最后,不得不手动停止。但与此同时,如果我像这样重写查询
SELECT ... FROM mytable t
LEFT OUTER JOIN mytablek tK ON tK.attr = t.attr1
WHERE tK.attrP LIKE '%Something%'
然后它再次开始像闪光灯一样运行。这是为什么?我认为,没有逻辑,所有那些与此字段attrP
无关的额外连接都会对查询的速度产生一些影响。我想,我知道如何优化这个查询,但我认为,我使用MySQL
越多,我就越不喜欢它。数百次我在没有合理解释的事情上挣扎。
修改
好吧,我认为我知道如何优化它 - 以这种方式使用内连接:
SELECT ... FROM mytable t
... bunch of joins
INNER JOIN mytablek tK ON tK.attr = t.attr1 AND tK.attrP LIKE '%Something%'
... bunch of joins
但这没有效果。
修改
好吧,我找到了一个解决方案 - 使用match against
。但不幸的是,这种解决方案并不普遍。实际上,当您尝试搜索子查询返回的字段时,匹配会引发错误。可怜的mysql
答案 0 :(得分:1)
运行查询时,SQL引擎有很多选项。该语言的优势之一是优化器选择最好的"运行给定查询的方法。当然,当发动机最好的东西不一定是最好的。
第二点是您的条件是将left join
转为inner join
s。所以,你也可以用这种方式编写查询(为了清楚起见)。
在此背景下,您的问题有两种可能的答案。第一个是当您运行其他查询时,您注意到结果首次出现时。这是"时间到第一行"测量。但是,与更复杂的查询匹配的行位于输入的末尾。 MySQL需要处理所有不匹配的行以找到匹配的行。如果某些中间结果为第一个表中的给定行创建笛卡尔积,则尤其如此。
另一种可能性是执行计划发生变化。因为left join
实际上是内部联接,所以MySQL在重写它们时有很大的灵活性。
我的下一个建议是将联接放到表mytablek
作为第一个表,而不是最后一个表。也许这将有助于MySQL找到最佳的优化。
第二种方法是使用子查询:
(select t.*
from mytablek tk
where tK.attrP LIKE '%Something%'
) tk
这可能会迫使引擎快速减少行,并将优化器指向更好的方向。
来自
答案 1 :(得分:1)
添加WHERE tK.attrP LIKE '%Something%'
可能会从结果集中删除记录。但我们不知道有多少。也许是1%,也许是99%。
我们甚至不知道我们是否只使用mytableK加入了mytable并使用了该子句,会影响多少百分比的记录。是否值得首先加入这些表,并留下所谓的少量记录,使用循环来进行其他连接以获取其他表的记录?或者我们是否应该首先在表格上使用优秀的连接算法更好地加入所有内容,并且最后只使用LIKE进行过滤?
我们不知道,dbms也不知道。
但是你注意到dbms在纯连接上运行速度很快,但在应用LIKE子句时速度很慢。所以提示dbms先做一件事,然后再做另一件事:
SELECT *
FROM
(
SELECT ... FROM mytable t
LEFT OUTER JOIN mytable2 t2 ON t2.attr = t.attr1
LEFT OUTER JOIN mytable3 t3 ON t3.attr = t.attr3
...
LEFT OUTER JOIN mytableN tN ON tN.attr = t.attrN
)
WHERE tK_attrP LIKE '%Something%';