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

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

子句很重要吗?

例如,如果我把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

Propel 1.3

> Symfony 1.2.5

评论

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

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

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

#1 楼

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

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


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

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

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

评论


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

–帕特里克(Patrick)
2011-3-18在0:40

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

–马特M
2011-3-18在20:25

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

–帕特里克(Patrick)
2011-3-18在20:29



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

–马特M
2011年3月18日在20:35

#2 楼

来自文档:


如果表具有多列索引,则优化器可以将索引的任何最左前缀用于优化器
查找行。例如,如果在(col1,col2,
col3)上有一个
三栏索引,则在(col1),(col1,col2),
和(col1,col2,col3)。

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


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

评论


如果表具有多列索引,则从左侧选择列很重要-但选择的顺序无关紧要。因此,如果您具有索引a,b,c,并且在其中c ='foo'AND a ='bar'AND b ='foobar'并且索引仍然可以使用。

– texelate
16年5月13日在6:27



#3 楼

不,没关系。

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

#4 楼


WHERE栏和foo


优化与


WHERE栏和foo



/>但是



非等号#1和非等号#2


不能同时优化两个部分。例如,


1和3 AND b之间的a> 17


不能充分利用INDEX(a,b)或INDEX (b,a)

用不同的措辞,首先使用WHERE子句中AND一起的所有'='测试,然后使用一个非'='(IN,BETWEEN,>等) )可以处理。没有一个可以被有效地优化。

您的查询有3个这样的子句。

事实证明,INDEX(EVENT_TIME)可能是最有用的-它会帮助使用AND中的一个,并且它可以用于避免对ORDER BY进行“文件排序”。

如果没有重复的行(为什么会有这种麻烦?),那么就摆脱掉不同。这会导致更多的工作。

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

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


任意数量的=
一些INs
最多一个范围。


#5 楼

MySQL,优化文档说:

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


...


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


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




这种方式是合理的为了使查询优化器省略HOW顺序,我们使用了查询中的列(不仅MySQL,而且SQL是一种声明性语言,必须做我们想要的而不是我们想要的)。
但是我仍然喜欢拥有相同的排序对于查询中复合键的列,但是有时这是不可避免的,例如当我们使用ORM或ActiveRecord时,在某些框架(如yii2)中,自定义关联条件将附加到“ on”条件的末尾,但我们仍然在应用程序的不同部分需要QueryBuilders的功能。

#6 楼

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

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

此外,希望您看看索引SQL LIKE过滤器。尽管这不是您需要的答案,但是您仍将了解如何在后台进行索引。

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

评论


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

–埃里克·汉弗莱-lotahelp
2011-3-18在13:42



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

–马特M
2011年3月18日在20:19

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

–摘要
2011-3-19在10:52



是的,我同意。但是,这在值选择性低的情况下有效。考虑到Patrick(此问题作者)使用的数据类型为DATETIME,建议建立索引。通常,这种类型的字段具有很大的一组值,除非在他仅使用几个可能的日期时出现一种奇怪的情况。 *我将在上面编辑我的答案,以使陈述更加清晰和有效。

–眼睛
2011年3月21日在8:40