3

最近在一次采访中被问到为什么SELECT对 MySQL 数据库的查询会非常慢,并提出以下问题:

  1. JOIN在 select 上执行多个s
  2. 关键过滤器字段上没有索引(索引?)

还被要求解决问题,我说:

  1. 如果查询非常重要,则非规范化您的数据(我知道这会导致数据重复,但还有其他方法可以避免 JOINs 吗?)
  2. 向过滤列添加索引。

是否还有其他特征说明 SQL 查询效率低下的原因?请注意,我纯粹是在寻找有关如何加快查询速度的提示,因此假设数据库服务器完美无缺:-)

4

3 回答 3

8

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

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

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

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

现在,根据您的需要,通常最好有一个使用生产数据库中的数据构建和更新的独立报告数据库、数据集市或数据仓库。这使您可以更自由地设计真正支持您想要运行的报告查询并阻止您入侵生产数据库的模式。

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

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

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

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

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

于 2011-11-29T11:59:04.177 回答
2

不可搜索的查询 - 即。即使存在合适的索引,DBMS 也无法利用它。解决方案 - 将查询重构为 sargable。

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

于 2011-11-29T11:53:05.137 回答
0

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

它描述了如何提高 MySQL 的性能,例如,模式、查询等......

于 2011-11-29T12:04:54.303 回答