在MySQL中,WHERE子句中列的顺序会影响查询性能吗?


38

我在某些具有较大可能结果集的数据库查询中遇到性能问题。

有问题的查询,我AND在WHERE子句中有三个

条款的顺序重要吗?

与之类似,如果我将ASI_EVENT_TIME子句放在第一位(因为这样会从所有子句中删除大部分结果。

这会改善查询的运行时间吗?

查询:

SELECT DISTINCT  activity_seismo_info.* 
FROM `activity_seismo_info` 
WHERE 
    activity_seismo_info.ASI_ACTIVITY_ID IS NOT NULL  AND 
    activity_seismo_info.ASI_SEISMO_ID IN (43,44,...,259) AND 
    (
        activity_seismo_info.ASI_EVENT_TIME>='2011-03-10 00:00:00' AND 
        activity_seismo_info.ASI_EVENT_TIME<='2011-03-17 23:59:59'
    ) 

ORDER BY activity_seismo_info.ASI_EVENT_TIME DESC

查询说明:

+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
| id | select_type | table   | type  | possible_keys             | key          | key_len | ref  | rows  | Extra                       |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
|  1 | SIMPLE      | act...o | range | act...o_FI_1,act...o_FI_2 | act...o_FI_1 | 5       | NULL | 65412 | Using where; Using filesort |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+

使用:

PHP 5.2

MySQL 5.0.51a-3ubuntu5.4

推进1.3

Symfony 1.2.5


ORDER BY可能要花这么长时间。“使用文件排序”可能非常慢。我发现在应用程序逻辑中进行排序的速度比使用ORDER BY更快。
Maclema 2011年

我前一段时间(在此站点之前)在stackoverflow上问过同样的问题。检查链接以获取我在那里收到的答案。stackoverflow.com/questions/3805863/…–
Scott

2
@maclema-除非您的应用程序在比数据库快得多的计算机上运行,​​否则您的断言肯定是不正确的,更不用说应用程序中所有排序逻辑的无意义负担。order by属于数据库。
杰克·道格拉斯

Answers:


24

我不这么认为。查询优化器应该足够聪明。

您可以尝试重新排列WHERE子句,看看每种情况下EXPLAINS都会告诉您相同的内容。


关于如何优化此查询:ASI_EVENT_TIME是否有索引?(这是我认为对于此查询最关键的,因为您还可以使用它对结果进行排序)。

在其他两个字段(ASI_SEISMO_ID和ASI_ACTIVITY_ID)上是否有索引?

如果您发布表结构,这将很有帮助。


我从没想过要创建事件时间的索引。明天我将在开发数据库上尝试一下,看看是否有明显的区别。
Patrick

@Patrick假设所有其他将使用此索引的查询都按降序对日期进行排序,那么您也希望按降序对索引键(activity_seismo_info.ASI_EVENT_TIME)进行排序。
Matt M

@MattM我不知道您可以订购索引键。太棒了,如果我确实订购了索引键,这是否必定会损害性能订购,而相反,这要比没有索引键更糟糕?
Patrick

@帕特里克你是对的。我的大脑陷入了SQL Server领域。您可以在MYSQL中指定排序顺序,它将进行解析,但是会被忽略。所有索引在MYSQL中按升序排序。对困惑感到抱歉。
Matt M

13

文档中

如果表具有多列索引,那么优化器可以使用索引的任何最左前缀来查找行。例如,如果在(col1,col2,col3)上有一个三列索引,则在(col1),(col1,col2)和(col1,col2,col3)上都有索引搜索功能。

如果列不构成索引的最左前缀,则MySQL无法使用索引。

所以是的,它应该与复合索引中列的顺序相同。


4
如果表具有多列索引,则从左侧选择列很重要-但是选择顺序无关紧要。因此,如果您拥有索引a,b,c,并且确实拥有WHERE c = 'foo' AND a = 'bar' AND b = 'foobar'该索引,则该索引仍然可以使用。
消失

10

不,没关系。

优化器在解析SQL之后立即进行了一系列简单的转换-这就是其中之一。


8

foo和bar在哪里

与优化相同

酒吧和foo

然而,

非等号#1和非等号#2

无法同时优化两个部分。例如,

在1和3之间且b> 17之间

无法充分利用INDEX(a,b)或INDEX(b,a)

换句话说,首先使用WHERE子句中与在一起的所有“ =”测试,然后再处理一个非“ =”(IN,BETWEEN,>等)。最多可以有效地优化一个。

您的查询包含3个此类子句。

事实证明,INDEX(EVENT_TIME)可能是最有用的-它可以帮助AND之一,并且可以用来避免ORDER BY的“文件排序”。

如果没有重复的行(为什么会有重复的行?),请摆脱DISTINCT。这需要更多的努力。

在询问性能问题时,请提供SHOW CREATE TABLE和SHOW TABLE STATUS。

更新... 在某些情况下,较新的版本(例如MySQL 5.7)IN( list of constants )几乎可以像对待=。为了安全起见,请遵循以下顺序(每个部分都是可选的):

  1. 任意数量的=
  2. 有的INs
  3. 最多一个范围。

1

MySQL的优化文档说:

您可能会想重写查询以使算术运算更快,同时又牺牲了可读性。由于MySQL自动进行类似的优化,因此您通常可以避免这项工作,而将查询保留为更易于理解和维护的形式。MySQL执行的一些优化如下:

  • ...

  • 对于联接中每个表,构造一个更简单的WHERE 以获得表的快速WHERE评估,并尽快跳过行

  • 查询每个表索引,并使用最佳索引,除非优化程序认为使用表扫描更有效。一次使用扫描是基于最佳索引是否跨越了表的30%以上,但是固定百分比不再决定使用索引还是扫描。现在,优化器更加复杂,其估计基于其他因素,例如表大小,行数和I / O块大小。

这样,查询优化器就可以合理地省略我们在查询中使用的列的HOW顺序(不仅是MySQL,而且SQL是一种声明性语言,必须做我们想做的而不是我们想做的)。

但是,我仍然喜欢对查询中的复合键的列进行相同的排序,但是有时这是不可避免的,例如当我们使用ORM或ActiveRecord时,在诸如yii2之类的某些框架中,自定义关系标准将附加到处于“开启”状态,但我们仍然需要应用程序不同部分中的QueryBuilder功能。


-2

必须索引在WHERE / HAVING子句中使用的,具有高选择性(唯一值的数量/记录的总数> 10%〜20%)的任何字段。

因此,如果您的ASI_EVENT_TIME列有许多可能的值,请首先将它们全部索引。然后按照@ypercube的说明,尝试重新排列它们,看看EXPLAIN会告诉您什么。应该都是一样的。

另外,希望您看看索引SQL LIKE过滤器。尽管这不是您需要的答案,但是您仍将了解索引的工作原理。

* 编辑: 请参阅下面注释中提供的链接,以了解有关索引的更多信息。


8
-1索引每列不是最佳实践。每个索引都会以多种方式花费您。确保选择良好的索引,该索引通常由多列组成,通常按使用的选择性和频率排序。这可能是SQL Server倾斜的,但是索引信息仍然有效:sqlskills.com/BLOGS/KIMBERLY/post/…
埃里克·汉弗莱

@Eric Humphrey +1有关解释和指向Kimberly网站的链接。
Matt M

您错了,在列上建立索引有时会损害您在某些查询上的性能:mysqlperformanceblog.com/2007/08/28/…。您永远不要使用经验法则:有时它有用,有时却没有。
2011年

是的,我同意。但是,这在值选择性低的情况下有效。考虑到Patrick(此问题作者)使用的数据类型为DATETIME,建议建立索引。通常,这种类型的字段具有很大的一组值,除非在他仅使用几个可能的日期时出现一种奇怪的情况。*我将在上面编辑我的答案,以使陈述更加清楚有效。
眼部
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.