有问题的查询,我在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
#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
评论
ORDER BY可能要花这么长时间。 “使用文件排序”可能非常慢。我发现在应用程序逻辑中进行订购的速度比使用ORDER BY快得多。我前一段时间(在此站点之前)在stackoverflow上问过同样的问题。检查链接以获取我在那里收到的答案。 stackoverflow.com/questions/3805863 / ...
@maclema-除非您的应用程序在比数据库快得多的计算机上运行,否则您的断言肯定是不正确的,更不用说应用程序中所有排序逻辑的无意义负担了。 order by属于数据库中。