【问题标题】:MySQL indexing for multiple count(*) queriesMySQL 索引多个 count(*) 查询
【发布时间】:2011-05-25 03:18:51
【问题描述】:

我对索引感到迷茫。我正在为客户端构建一个中等复杂的 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` !=  ''

这里是解释..

 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

解释

1 SIMPLE vehicles ref Make,BodyStyle,VehicleLocation_province_2 Make 99 const 5821 Using where; Using filesort

我知道我需要在可能的情况下避免使用临时表和文件排序...但是当必须对每个请求执行多个 count(*) 查询并使用不同的 where 参数分组和排序时,这实际上是如何实现的?

【问题讨论】:

  • 这是 InnoDB 还是 MyISAM?它们在性能、索引和计数(*)方面完全不同。
  • @cherouvim,当然它们并不完全不同 :) - 一些一般规则仍应适用
  • MyISAM。显然 count(*) 性能在 InnoDB 中受到严重影响(所以我读过)

标签: mysql database indexing query-optimization


【解决方案1】:

好吧,让索引加速查询的唯一方法是让索引覆盖足够多的条件以使选择性变得有用(或者让 RDBMS 能够使用索引来计算诸如计数之类的聚合)。

不要忘记在(Make) 上拥有索引和在(BodyStyle) 上拥有索引不与在(Make, BodyStyle) 上拥有索引相同。

在您的第一个查询中,当您需要对记录进行计数时,覆盖default_image_URI 和VehicleLocation_province 的索引的存在应该足以让mysql 不进行表扫描,而是从索引中检索计数。

您可以通过创建索引 (VehicleLocation_province, default_image_URI) 然后运行查询和/或检查说明来检查这一点。

在第二个查询中,您有类似的情况,查询有更多条件(只要它们都是 AND 条件就很好),它不是关于计数记录,而是实际上从表中检索数据和 排序。

这里有几点说明:

  • 注意您的条件IS NOT NULL 和!='' - 如果这些条件通常出现在您的查询中,那么这些条件表明您的设计不正确,并且您已将不同的实体非规范化到一个表中,因此现在您必须对它们进行排序每次你想使用数据时都退出(这只是一个指示,我假设你应用了这些条件很多,这可能不是真的)
  • 话虽如此,如果您查看第二个查询,并且如果 Make 和 BodyStyle 被复合索引覆盖并且选择性低,则查询仍然会快速执行
  • mysql 必须选择一个索引来访问数据,它会尝试选择在给定统计信息和可用条件的情况下返回最少行数的索引(以便进一步的条件必须遍历最少数量的记录) - 如果该索引仅有助于减少结果集,排序将使用文件排序完成。要使索引对选择行和排序都有用,它应该具有有用的顺序或索引列,例如在上面的查询索引中 (Make, BodyStyle, VehicleReceivedDate) 可能会起作用
  • 在您的表上添加适当的索引应该会有所帮助,但索引不能解决设计问题

【讨论】:

  • 解释得很好。我也喜欢解释某些事情是如何/为什么会发生的,而不是仅仅给出答案。
  • 我发现这篇文章有助于解释让 MySQL 使用 GROUP 的索引必须遵循的实际“规则”dev.mysql.com/doc/refman/5.0/en/group-by-optimization.html 在那张纸条上——我现在有几个查询运行得更顺畅,理解更深入多列索引排序..这个项目将极大地受益于我返回并优化模型并以某种方式构建查询,以便他们可以使用更通用的索引..我不确定这背后的理论(有很多可变参数) 不幸的是,这个项目的时间快到了。
  • 索引 + 查询缓存似乎以足够的性能发挥作用。谢谢大家。
  • @FelixHCat,很高兴为您提供帮助。关于链接,请记住它专门针对 GROUP BY(您的查询不使用它)。另外,如果我的回答有帮助,请随时点赞并接受。
  • @FelixHCat,关于查询缓存 - 应该考虑它,但不要使用它来评估性能 - 如果结果集小于,它将在第二次运行时使执行时间始终为零query_cache_size 在 my.cnf 中。使用SELECT SQL_NO_CACHE 评估性能 + EXPLAIN(或者理想情况下使用缓存,但创建现实的测试工作负载,这些工作负载也会执行更新,以现实的方式使缓存失效=这不是那么简单)。
【解决方案2】:

另一个我没有考虑过的选项(我现在认为这是理想的解决方案)是使用像 Sphinx 这样的搜索服务器来处理索引和性能方面的繁重工作。 Sphinx 可以在几种不同的搜索配置中对许多列进行分组和计数以及全文和属性搜索/过滤。

Sphinx 甚至可以使用 @geodist 进行半径计算 SetGeoAnchor ( $attrlat, $attrlong, $lat, $long )

当运行复杂的搜索查询以尝试重新发明轮子并最终得到荒谬的多列索引列表试图涵盖所有类型的用例时,这几乎没有意义。

我希望我能在项目早期考虑使用搜索服务器 - 现在,在性能问题上挽回面子有点晚了。

http://sphinxsearch.com

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-31
    • 2011-04-10
    • 2013-10-03
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多