多计数(*)查询的MySQL索引
关于索引,我迷路了。我有一个为客户端构建的中等复杂的web应用程序,它有几个count(*)查询,这些查询都运行得非常慢(0.3秒) 这里有一个简单的例子多计数(*)查询的MySQL索引,mysql,database,indexing,query-optimization,Mysql,Database,Indexing,Query Optimization,关于索引,我迷路了。我有一个为客户端构建的中等复杂的web应用程序,它有几个count(*)查询,这些查询都运行得非常慢(0.3秒) 这里有一个简单的例子 SELECT COUNT( * ) AS `count` FROM `vehicles` WHERE `VehicleLocation_province` = 'Alberta' AND `default_image_URI` IS NOT NULL AND `default_image_URI` != '' 下面是解释
SELECT COUNT( * ) AS `count`
FROM `vehicles`
WHERE `VehicleLocation_province` = 'Alberta'
AND `default_image_URI` IS NOT NULL
AND `default_image_URI` != ''
下面是解释
1 SIMPLE vehicles ref VehicleLocation_province,VehicleLocation_province_... VehicleLocation_province 2 const 14128 Using where
我甚至不能让这个查询使用适当的索引,更不用说一些更复杂的查询,比如
SELECT * , ( 6371 * ACOS( COS( RADIANS( 53.543564 ) ) * COS( RADIANS( lat ) ) * COS( RADIANS( lng ) - RADIANS( - 113.490456 ) ) + SIN( RADIANS( 53.543564 ) ) * SIN( RADIANS( lat ) ) ) ) AS `distance`
FROM `vehicles`
WHERE `Make` = 'Pontiac'
AND `BodyStyle` = 'Sedan'
AND `VehiclePrice` >= '1'
AND `VehiclePrice` <= '36000'
AND `VehiclePrice` IS NOT NULL
AND `default_image_URI` IS NOT NULL
AND `default_image_URI` != ''
HAVING `distance` < 50
ORDER BY `VehicleReceivedDate` DESC LIMIT 25
我知道我需要尽可能避免临时表和文件端口。。。但是,当必须在每个请求上使用不同的where参数分组和排序来执行这些count(*)查询时,这实际上是如何实现的呢?好的,获取索引加速查询的唯一方法是让索引覆盖足够的条件,以使选择性变得有用(或者让RDBMS能够使用索引来计算聚合,如count) 不要忘记,在
(Make)
和(BodyStyle)
上建立索引与在(Make,BodyStyle)
上建立索引是不同的
在第一次查询中,当您需要对记录进行计数时,包含default\u image\u URI
和VehicleLocation\u province
的索引的存在应该足以让mysql不进行表扫描,而是从索引中检索计数
您可以通过创建一个索引(VehicleLocation\u province,默认的\u image\u URI)
,然后运行查询和/或检查解释来检查这一点
在第二个查询中,您遇到了与具有更多条件的查询类似的情况(只要它们都是和条件就好),并且它不是关于计数记录,而是实际上从表中检索数据并进行排序
以下是几点注意事项:
- 请注意,您的条件
和不是空的
-如果这些条件通常出现在您的查询中,那么这些条件表明您的设计不正确,并且您已经将不同的实体反规范化为一个表,因此现在您必须在每次使用数据时对它们进行排序(这只是一个指示,我假设您经常应用这些条件,这可能不是真的)!='
- 话虽如此,如果您查看第二个查询,如果Make和BodyStyle包含一个复合索引,并且具有低选择性,那么查询仍然会执行得很快
- mysql必须选择一个索引来访问数据,并且在给定统计信息和可用条件的情况下,它将尝试选择返回最少行数的索引(以便进一步的条件必须循环通过最少数量的记录)-如果该索引仅有助于减少结果集,则将使用文件排序来完成排序。为了使索引对选择行和排序都有用,它应该具有有用的顺序或索引列,例如在上面的查询索引中,
可以做到这一点(Make、BodyStyle、VehiclerReceivedDate)
- 在表中添加适当的索引应该会有所帮助,但索引无法解决设计问题
这是InnoDB还是MyISAM?它们在性能、索引和计数(*)方面完全不同。@cherouvim,它们肯定不是完全不同:)-一些一般规则应该仍然适用于MyISAM。显然计数(*)性能在InnoDB中受到严重影响(我已经读过)解释得很好。我也喜欢解释某些事情是如何/为什么发生的,而不仅仅是给出答案。我发现这篇文章有助于解释实际的“规则”让MySQL使用组索引是必须遵循的——我现在有几个查询运行得更顺畅,对多列索引排序有了更深入的了解。我回去优化模型,以某种方式构造查询,使它们可以使用更通用的索引,这一项目将大大受益。我不确定这背后的理论(有许多可变参数)不幸的是,这个项目的时间快到了。索引+查询缓存似乎以足够的性能完成了这项任务。谢谢大家。@FelixHCat,很乐意提供帮助。关于链接,请记住它专门针对分组(您的查询不使用它)。此外,如果我的答案有帮助,请随意投票并接受它。@FelixHCat,关于查询缓存-应该考虑它,但不要使用它来评估性能-如果结果集小于my.cnf中的
query\u cache\u size
,则在第二次运行时,它将使执行时间始终为零。使用选择SQL\u NO\u cache
评估性能+解释(或理想情况下使用缓存,但创建真实的测试工作负载,该工作负载还将以真实的方式进行更新,从而使缓存失效=这并不是那么简单)。
1 SIMPLE vehicles ref Make,BodyStyle,VehicleLocation_province_2 Make 99 const 5821 Using where; Using filesort