如何证明在 SQL 中使用子选择查询会降低服务器的性能

Posted

技术标签:

【中文标题】如何证明在 SQL 中使用子选择查询会降低服务器的性能【英文标题】:How to Prove that using subselect queries in SQL is killing performance of server 【发布时间】:2010-12-28 12:28:33 【问题描述】:

我的工作之一是维护我们的数据库,通常我们在获取报告并在该基础上工作时会遇到性能不足的问题。 当我开始查看我们的 ERP 发送到数据库的查询时,我在主查询中看到了很多完全不必要的子选择查询。 由于我不是我们使用的程序的创建者开发人员的成员,所以当我批评他们的代码和工作时,他们不太喜欢。假设他们不将我的评论视为严肃的陈述。 所以我问你几个关于 SQL 中的 subselect 的问题

子选择是否比左外连接花费更多时间? 是否存在任何博客、文章或我选择不建议使用的任何内容? 我如何证明如果我们在查询中避免 subselect 查询会更快?

我们的数据库服务器是MSSQL2005

【问题讨论】:

【参考方案1】:

“Show, Don't Tell” - 检查并比较使用 SQL Profiler 识别的查询的查询计划。特别注意表扫描和书签查找(您希望尽可能频繁地查看索引搜索)。查询计划的“拟合优度”取决于最新的统计数据、定义的索引以及整体查询工作负载。

Execution Plan Basics

Understanding More Complex Query Plans

Using SQL Server Profiler(2005版)

在 SQL Server Management Studio (SSMS) 中运行查询并打开 Query->Include Actual Execution Plan (CTRL+M)

认为自己很幸运,它们只是子选择(在某些情况下,优化器会产生等效的“加入计划”)而不是相关的子查询!

确定执行大量逻辑读取的查询,使用您喜欢的技术重写它,然后通过比较显示它执行的逻辑读取次数。

这里有一个提示。要获得执行的逻辑读取的总数,请将相关查询包装为:

SET STATISTICS IO ON
GO

-- Run your query here

SET STATISTICS IO OFF
GO

运行查询,然后切换到结果窗格中的消息选项卡。

如果您有兴趣了解更多信息,没有比 SQL Server 2008 Query Performance Tuning Distilled 更好的书了,它涵盖了监控、解释和修复性能问题的基本技术。

【讨论】:

【参考方案2】:

您可以做的一件事是加载 SQL Profiler 并向他们显示子查询的成本(在 CPU 周期、读取和写入方面)。很难与冷酷的统计数据争论。

我还会检查这些查询的查询计划,以确保使用了适当的索引,并将表/索引扫描保持在最低限度。

一般来说,如果使用正确并且有适当的索引,我不会说子查询不好。

【讨论】:

【参考方案3】:

我对 MSSQL 不是很熟悉,因为我们在大多数应用程序中都使用 postrgesql。但是应该存在类似“EXPLAIN”的东西,它向您显示查询的执行计划。在那里,您应该能够看到查询为检索所需数据而将产生的各个步骤。

如果您看到有很多表扫描或循环连接没有使用任何索引,这绝对是查询执行缓慢的提示。使用这样的工具,您应该能够比较两个查询(一个有连接,另一个没有)

很难说哪种方法更好,因为它实际上高度依赖于优化器在各种情况下可以采用的索引,并且根据 DBMS,优化器可能能够隐式地将子查询重写为连接-查询并执行。

如果你真的想展示哪个更好,你必须同时执行并测量时间、cpu 使用率等。

更新: MSSQL大概就是这个吧-->QueryPlan

【讨论】:

【参考方案4】:

根据我自己的经验,这两种方法都是有效的,例如 EXISTS 子选择可以避免大量处理过早的中断。

但大多数时候,带有大量子选择的查询是由开发人员完成的,他们并不真正了解 SQL,而是使用他们经典的过程程序员的查询思维方式。然后他们甚至不考虑连接,并提出一些糟糕的查询。所以我更喜欢连接,而且我总是检查子查询。老实说,我跟踪慢查询,我第一次尝试包含子选择的慢查询是尝试进行连接。工作很多时间。

但是没有规则可以确定子选择比连接不好或慢,只是糟糕的 sql 程序员经常做子选择:-)

【讨论】:

【参考方案5】:

子选择是否比左外连接花费更多时间?

这取决于子选择和左外连接。

一般来说,这个结构:

SELECT  *
FROM    mytable
WHERE   mycol NOT IN
        (
        SELECT  othercol
        FROM    othertable
        )

比这更有效率

SELECT  m.*
FROM    mytable m
LEFT JOIN
        othertable o
ON      o.othercol = m.mycol
WHERE   o.othercol IS NULL

看这里:

NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL: SQL Server

是否存在建议不要使用 subselect 的任何博客、文章或任何内容?

我会避开那些盲目推荐避免子选择的博客。

它们的实现是有原因的,不管你信不信,开发人员已经付出了一些努力来优化它们。

我如何证明如果我们在查询中避免子选择,查询会更快?

编写一个不带子选择的查询,运行速度更快。

如果您在此处发布您的查询,我们可能会改进它。但是,带有子选择的版本可能会更快。

【讨论】:

【参考方案6】:

尝试重写一些查询以消除子选择和比较运行时。

分享和享受。

【讨论】:

以上是关于如何证明在 SQL 中使用子选择查询会降低服务器的性能的主要内容,如果未能解决你的问题,请参考以下文章

如何在子查询 SQL Server 中选择多个项目

查询优化,(子查询)(sql-transact)

更改视图定义会改进/降低两个不同的查询

当不使用 EXISTS 引入子查询时,选择列表中只能指定一个表达式。 - SQL 服务器

如何在访问报告详细信息部分中选择前 N 个或在 sql 子查询中选择前 N 个

SQL在where子句中使用子选择中的列