【问题标题】:What generic techniques can be applied to optimize SQL queries?可以应用哪些通用技术来优化 SQL 查询?
【发布时间】:2010-09-07 13:09:56
【问题描述】:

可以有效地应用哪些技术来提高 SQL 查询的性能?是否有适用的一般规则?

【问题讨论】:

    标签: sql performance


    【解决方案1】:

    我认为使用 SQL 查询分析器会是一个好的开始。

    【讨论】:

      【解决方案2】:

      在 Oracle 中,您可以查看 explain plan 以比较查询的变体

      【讨论】:

        【解决方案3】:
        • 使用主键
        • 避免选择 *
        • 在构建条件语句时尽可能具体
        • 去规范化通常更有效
        • 表变量和临时表(如果可用)通常比使用大型源表更好
        • 分区视图
        • 使用索引和约束

        【讨论】:

          【解决方案4】:

          确保表上有正确的索引。如果您经常使用列作为排序或限制数据集的一种方式,则索引可能会产生很大的不同。我在最近的一篇文章中看到 select distinct 确实会减慢查询速度,尤其是在没有索引的情况下。

          【讨论】:

            【解决方案5】:

            SELECT 查询的明显优化是确保您在用于连接的列或 WHERE 子句中具有索引。

            由于添加索引会减慢数据写入速度,因此您确实需要监控性能以确保不会破坏数据库的写入性能,但这就是使用良好的查询分析工具可以帮助您相应地平衡事情的地方。

            【讨论】:

              【解决方案6】:

              你能做的最重要的事情是在 sql server 查询分析器中查找表扫描(确保打开“显示执行计划”)。否则,在 MSDN 和其他地方有无数的文章可以提供很好的建议。

              顺便说一句,当我开始学习优化查询时,我针对跟踪运行了 sql server 查询分析器,查看了生成的 SQL,并试图找出改进的原因。查询分析器远非最佳,但它是一个不错的开始。

              【讨论】:

                【解决方案7】:
                • 索引
                • 统计数据
                • 在 microsoft stack 上,数据库引擎优化顾问

                【讨论】:

                  【解决方案8】:

                  了解幕后的真实情况 - 您应该能够详细了解以下概念:

                  • 索引(不仅仅是它们是什么,而是它们的实际工作方式)。
                  • 聚集索引与堆分配表。
                  • 文本和二进制查找以及何时可以内联。
                  • Fill factor
                  • 如何为更新/删除创建幻影记录。
                  • 何时发生页面拆分以及原因。
                  • 统计信息,以及它们如何影响各种查询速度。
                  • 查询规划器,以及它如何为您的特定数据库工作(例如,在某些系统上“select *”很慢,在现代 MS-Sql DB 上规划器可以处理它)。

                  【讨论】:

                    【解决方案9】:

                    您可以通过以下几个方面来优化查询性能。

                    1. 确保您只有最少的数据。确保仅选择所需的列。将字段大小降至最低。

                    2. 考虑对数据库进行反规范化以减少连接

                    3. 避免循环(即获取游标),坚持设置操作。

                    4. 将查询实现为存储过程,因为这是预编译的,执行速度更快。

                    5. 确保设置了正确的索引。如果您的数据库主要用于搜索,请考虑更多索引。

                    6. 使用执行计划查看处理是如何完成的。您要避免的是表扫描,因为这很昂贵。

                    7. 确保自动统计设置为开启。 SQL 需要它来帮助确定最佳执行。有关更多信息,请参阅 Mike Gunderloy 的精彩帖子。 Basics of Statistics in SQL Server 2005

                    8. 确保您的索引没有碎片化。 Reducing SQL Server Index Fragmentation

                    9. 确保您的表没有碎片化。 How to Detect Table Fragmentation in SQL Server 2000 and 2005

                    【讨论】:

                      【解决方案10】:

                      使用 with 语句来处理查询过滤。 将每个子查询限制为尽可能少的行数。 然后加入子查询。

                      WITH
                      master AS
                      (
                          SELECT SSN, FIRST_NAME, LAST_NAME
                          FROM MASTER_SSN
                          WHERE STATE = 'PA' AND
                                GENDER = 'M'
                      ),
                      taxReturns AS
                      (
                          SELECT SSN, RETURN_ID, GROSS_PAY
                          FROM MASTER_RETURNS
                          WHERE YEAR < 2003 AND
                                YEAR > 2000
                      )
                      SELECT *
                      FROM master,
                           taxReturns
                      WHERE master.ssn = taxReturns.ssn
                      

                      with 语句中的子查询可能最终与内联视图相同, 或自动生成的临时表。我发现在我所做的工作(零售数据)中,大约 70% 到 80% 的时间都有性能优势。

                      100% 的时间,有维护收益。

                      【讨论】:

                        【解决方案11】:

                        其他几点(我的基于 SQL 服务器,因为每个数据库后端都有自己的实现,它们可能适用于所有数据库,也可能不适用):

                        避免在语句的选择部分出现相关子查询,它们本质上是游标。

                        设计您的表以使用正确的数据类型,以避免必须对其应用函数来获取数据。例如,当您将数据存储为 varchar 时,进行日期数学运算要困难得多。

                        如果您发现您经常执行包含函数的联接,那么您需要考虑重新设计您的表。

                        如果您的 WHERE 或 JOIN 条件包含 OR 语句(速度较慢),则使用 UNION 语句可能会获得更快的速度。

                        如果(且仅当)两个语句互斥并且以任何方式返回相同的结果时,UNION ALL 比 UNION 快。

                        NOT EXISTS 通常比 NOT IN 或使用带有 ID = null 的 WHERE 子句的左连接更快

                        在 UPDATE 查询中添加 WHERE 条件以确保您不会更新已经相等的值。更新 10,000,000 条记录和 4 条记录之间的差异可能非常显着!

                        如果您要经常查询某些值或用于大型报告,请考虑预先计算它们。订单中的值的总和只需要在订单下达或调整时进行,而不是在报表中汇总 10,000,000 亿个订单的结果时进行。应在触发器中进行预计算,以便它们始终是最新的底层数据更改。它也不必只是数字,我们有一个计算字段,可以连接我们在报告中使用的名称。

                        小心标量 UDF,它们可能比将代码放入行中要慢。

                        对于大型数据集,临时表往往更快,而对于小型数据集,表变量往往更快。此外,您还可以索引临时表。

                        在用户界面中格式化通常比在 SQL 中更快。

                        不要返回比实际需要更多的数据。

                        这似乎很明显,但你不会相信我最终修复它的频率。不要加入您不用于过滤记录或实际调用语句选择部分中的字段之一的表。不必要的连接可能非常昂贵。

                        创建调用其他视图的视图调用其他视图是一个非常糟糕的主意。您可能会发现您加入同一个表 6 次,而您只需要一次并在基础视图中创建 100,000,00 条记录以获得最终结果中的 6 条记录。

                        在设计数据库时,不仅要考虑报告输入数据的用户界面。数据不使用就没有用,所以要考虑它在数据库中之后将如何使用,以及如何维护或审计这些数据。这通常会改变设计。 (这就是为什么让 ORM 设计你的表是一个糟糕的主意的原因之一,它只考虑数据的一个用例。)影响最多数据的最复杂的查询是在报告中,因此设计更改以帮助报告可以大大加快查询(并简化查询)。

                        特定于数据库的功能实现可能比使用标准 SQL 更快(这是他们销售产品的一种方式),因此请了解您的数据库功能并找出哪些更快。

                        而且因为不能说的太频繁,所以要正确使用索引,不要太多也不要太少。并让你的 WHERE 子句成为 sargable(能够使用索引)。

                        【讨论】:

                          猜你喜欢
                          • 2017-01-16
                          • 2011-08-26
                          • 1970-01-01
                          • 2010-09-20
                          • 2010-09-25
                          • 2022-09-23
                          • 1970-01-01
                          • 2010-09-27
                          • 2019-03-28
                          相关资源
                          最近更新 更多