慢SQL查询的特征

时间:2011-11-29 11:12:47

标签: mysql sql database query-performance

最近在面试中被问到为什么对MySQL数据库的SELECT查询会非常缓慢,并提出以下建议:

  1. 在选择
  2. 上执行了多个JOIN
  3. 关键过滤器字段中缺少索引(索引?)
  4. 还问了解决问题的方法,我说:

    1. 如果查询非常重要,则会对您的数据进行反规范化(我知道 这会导致数据重复,但还有另一种方法可以避免 JOIN S')
    2. 将索引添加到过滤列。
    3. 为什么SQL查询效率低下还有其他特性吗?请注意,我纯粹在寻找有关如何加速查询的提示,因此假设数据库服务器完美无瑕: - )

3 个答案:

答案 0 :(得分:8)

查询可能很慢的原因有几个。无论如何,要真正了解查询规划器正在做什么,您应该在其上运行explain。大多数DBMS上的explain命令将告诉您查询规划器将使用哪些索引,关于可以获得多少行数据,以及在开始之前需要处理多少行数据得到结果。

现在,为了给出查询可能运行缓慢的一些具体原因,您对索引是正确的。缺少索引将导致对查询中的表进行顺序扫描,如果这些表很大,可能会使事情变慢。在您正在加入或在where子句中使用的列上创建索引肯定有帮助。但有时候,查询规划器做得很差,你需要帮助它使用'force'命令来指示它应该使用哪个索引。

加入会减慢事情的速度,这是一种误解。单级连接通常很好。例如,您正在从表A中选择数据,并且您将B连接到A,将C连接到A.表B和C的连接是一个级别连接。多级联接需要更多时间来处理。这就是为什么在数据仓库和数据集市中,人们喜欢使用星型方案;这是一个包含度量的单个大表,一个事实表,该查询正在进行,还有其他表与描述性数据,维度表,它们加入了它。星型模式避免多级联接,因此可以快速执行报告查询。

非正规化你的桌子很诱人,但我强烈建议反对它。当你开始对数据库进行非规范化时,如果你存储的数据量越来越大,那么你将会遇到一些严重的问题。同样,维护非规范化表格需要您的工程师对模式有一个非常好的工作知识,这使得技术债务变得更加困难。当然这是一个短期的收获,但长期的痛苦意味着你必须有一个非常好的理由想要这样做。做一些需要扩展的多年项目,你会真正看到非规范化的痛苦。

现在,根据您的需求,通常需要使用生产数据库中的数据构建和更新分离报告数据库,数据集市或数据仓库。这使您可以更自由地设计真正支持您想要运行的报告查询的模式,并阻止您攻击生产数据库。

如果缺少资源,那么单独数据库的一个不错的替代方法是临时表。临时表是在数据库连接/会话的生命周期中存在的表。其他连接/会话无法查看或访问它,隔离质量,您可以使用它们来存储和索引要在更大更复杂的查询中使用的数据。如果您通过控制台与数据库交互,则非常简单易用。如果您以编程方式使用其中一个并拥有连接池,我认为您可能必须在完成后删除该表;不太清楚,但清理绝不是坏事。

查询速度慢的一个明显原因是您正在选择大量数据。如果您尝试交叉连接多个表,每个表都有几亿行字符(1000)字段,您的DBMS可能会开始挖掘虚拟内存以执行连接。即使使用索引,也可能导致交换磁盘,一旦开始发生,欢迎来到slowville。

选择子选择(select a, b, (select c, d from e where e.id = a) from f)或在where子句中使用子选项也可能非常慢,因为该子选择实际上是为每行数据执行的查询。在连接中使用子选择不会受到该问题的影响,但是,您实际上是在没有索引的情况下连接到临时表,并且根据您使用该子选择检索的数据量,这也会减慢速度。

如果您的集非常大,in命令也可能会出现问题。同样,一个大型集合基本上是一个没有索引的大型临时表,所以每次检查一下特定值是否在您的集合中时,您都在执行顺序扫描。

这些是我现在能想到的最突出的原因。还有其他但我认为这将超出堆栈溢出响应的范围; - )

答案 1 :(得分:2)

sargable查询 - 即。即使存在合适的索引,DBMS也无法利用合适的索引。解决方案 - 重构查询是可以攻击的。

内存密集型查询,需要磁盘缓存。解决方案 - 使用额外的RAM和更快的磁盘访问(更快的磁盘,RAID条带化等)升级服务器

答案 2 :(得分:0)

您可能会发现以下链接有用:MySQL-performance-tuning-step-by-step

它描述了如何提高MySQL性能,例如,架构,查询等......