最近在一次采访中被问到为什么SELECT数据库上的MySQL查询会非常慢,并提出如下建议:
JOIN也有人要求解决这些问题,我说:
JOIN?)关于为什么SQL查询效率低下,还有其他特征吗?请注意,我纯粹是在寻找有关如何加快查询速度的技巧,因此假设DB服务器完美无缺:-)
发布于 2011-11-29 11:59:04
查询可能比较慢的原因有几个。无论如何,要真正了解查询计划器在做什么,您应该在它上运行explain。大多数DBMS上的explain命令将告诉您查询计划器将使用哪些索引,您可以预期得到多少行数据,以及在返回结果之前需要处理多少行数据。
现在,为了给出查询可能运行缓慢的一些具体原因,您对索引是正确的。缺少索引将导致对查询中的表进行顺序扫描,如果这些表很大,这会使事情变慢。在where子句中加入或使用的列上创建索引肯定有帮助。但是,有时查询计划器做的工作很糟糕,您需要使用“force”命令来帮助它指示应该使用的索引。
这是一种误解,认为加入会使事情变慢。单一级别的连接通常都很好。例如,您从表A中选择数据,将B连接到A,将C连接到表A,连接到表B和表C是一个级别联接。多级连接需要更多的时间来处理。这就是为什么在数据仓库和数据集市中,人们喜欢使用星型方案;这是一个包含度量的单个大表,一个事实表,这个查询正在做的事情,还有其他具有描述性数据、维度表的表,它们被加入到其中。星型模式避免多级连接,因此可以快速执行报告查询。
但是,我强烈建议您不要这样做。当您开始去规范化您的数据库时,您将遇到一些严重的痛苦,如果您存储的数据量越来越大,缩放问题。此外,维护非规范化表需要工程师对模式有很好的工作知识,这会使技术债务变得更加困难。当然,这是一个短期的收获,但长期的痛苦意味着你必须有一个真正的理由想要这样做。做几个需要扩展的多年项目,你就会真正体会到去正规化的痛苦。
现在,根据您的需要,通常最好使用生产数据库中的数据构建和更新分离报告数据库、数据集市或数据仓库。这给了您更多的自由来设计真正支持您想要运行的报告查询的模式,并阻止您侵入生产数据库。
如果您缺少资源,那么替代单独数据库的一个很好的方法就是临时表。临时表是在数据库连接/会话的生存期内存在的表。其他连接/会话无法查看或访问它,这是隔离性的,您可以使用它们来存储和索引您想要在更大、更复杂的查询中使用的数据。如果您是通过控制台与数据库交互,那么使用起来非常简单。如果您正在以编程的方式使用一个连接池,我认为您可能必须在完成时删除该表;不太记得,但清理从来都不是坏事。
查询速度慢的一个明显原因是您选择了大量的数据。如果您尝试交叉连接多个表,每个表都有数亿行chars(1000)字段,那么DBMS可能会开始挖掘虚拟内存以执行连接。即使有索引,这也会导致磁盘上的交换,一旦发生这种情况,欢迎来到慢维尔。
在where子句中选择子Selecting (select a, b, (select c, d from e where e.id = a) from f)或使用子Selecting也可能非常慢,因为该子Selecting实际上是对每一行数据执行的查询。然而,在联接中使用子选择并不会受到此问题的影响,实际上,您是在没有索引的情况下连接到临时表,这取决于您使用该子选择检索的数据数量,这也会减慢速度。
如果您的集合非常大,in命令也会出现问题。同样,大集合基本上是一个没有索引的大型临时表,因此每次您检查是否有特定值在您的集合中时,您都在执行顺序扫描。
这些是我现在能想到的最突出的原因。还有其他的,但我认为这超出了堆栈溢出响应的范围;)
发布于 2011-11-29 11:53:05
非易懂查询-例如。DBMS无法利用适当的索引,即使存在索引。解决方案-将查询重构为sargable。
内存密集型查询,需要磁盘缓存。解决方案-使用额外的RAM和更快的磁盘访问(更快的磁盘、RAID条带等)升级服务器
发布于 2011-11-29 12:04:54
您可能会找到以下有用的链接:MySQL-性能调优-一步一步
它描述了如何提高MySQL的性能,例如,模式、查询等。
https://stackoverflow.com/questions/8309773
复制相似问题