【问题标题】:select top 1 * vs select top 1 1选择前 1 * 与选择前 1 1
【发布时间】:2015-12-07 11:58:20
【问题描述】:

我知道有很多这样的问题,但我找不到与我的问题相关的问题。

看这个问题,Is Changing IF EXIST(SELECT 1 FROM ) to IF EXIST(SELECT TOP 1 FROM ) has any side effects?

具体参考答案中的这一段:

select * from sys.objects
select top 1 * from sys.objects
select 1 where exists(select * from sys.objects)
select 1 where exists(select top 1 * from sys.objects)

我正在运行一些自己的测试以正确理解它。如答案所示:

select 1 where exists(select top 1 * from sys.objects)
select 1 where exists(select top 1 1 from sys.objects)

两者都导致相同的执行计划,也导致相同的计划

select 1 where exists(select * from sys.objects)
select 1 where exists(select 1 from sys.objects)

根据我对此类问题的研究,“SELECT TOP 1 1” VS “IF EXISTS(SELECT 1”。我推断这是公认的最佳做法:

select 1 where exists(select * from sys.objects)

我的第一个问题是为什么这比这个更受欢迎:

select 1 where exists(select 1 from sys.objects)

为了理解它,我将它们分解为更基本的表达方式(我使用“top 1”来模拟类似于存在的执行计划):

select top 1 * from sys.objects
select top 1 1 from sys.objects

我现在看到第一个是执行时间的 80%(相对于 2 个批次),而第二个只有 20%。那么使用它不是更好的做法吗

select 1 where exists(select 1 from sys.objects)

因为它可以应用于这两种情况,从而减少可能的人为错误?

【问题讨论】:

  • 注意:这里有一篇很好的文章:sqlservercentral.com/articles/T-SQL/154149
  • 是的,我也刚刚读过那篇文章,这是一个确定的测试。在使用 null 而不是 * 或 1 时,我很想找时间来测试他的结果,因为 null 使用的是 CPU 与内存上的指针。

标签: sql-server tsql database-performance


【解决方案1】:

SQL Server 在查询编译/优化过程中相对较早地检测到EXISTS 谓词,并消除对此类子句的实际数据检索,代之以存在性检查。所以你的假设:

我现在看到第一个是执行时间的 80%(相对于 2 个批次),而第二个只有 20%。

是错误的,因为在前面的比较中,您实际上检索到了一些数据,如果将查询放入 (not) exists 谓词中,则不会发生这种情况。

大多数时候,除了一个重要的捕获之外,如何测试行的存在是没有区别的。假设你说:

if exists (select * from dbo.SomeTable)
...

代码模块中的某处(视图、存储过程、函数等)。然后,稍后,当其他人决定将WITH SCHEMABINDING 子句放入此代码模块时,SQL Server 将不允许这样做,并且可能会绑定到当前列列表,而不是可能会引发错误:

消息 1054,级别 15,状态 7,过程 BoundView,第 6 行
模式绑定对象中不允许使用语法“*”。

所以,简而言之:

if exists (select 0 from ...)

是一种最安全、最快且通用的存在性检查方法。

【讨论】:

  • 我真的很喜欢这个答案,因为WITH SCHEMABINDING 信息,因为这绝对是一个巨大的游戏规则改变者,是SELECT 1SELECT * 的最佳论据。请问您是否有相关参考的链接?
  • 嗯,我只听说过这样的漏洞,说实话。现在我已经自己测试过了,SQL Server 不允许您通过抛出错误 1054,Syntax '*' is not allowed in schema-bound objects. 来打自己的腿,这使我的论点有些弱,尽管作为一种万能的方法仍然有效。哦,是的,我在 2012 版本上遇到了这个错误 - 不知道旧版本会如何反应。
【解决方案2】:

这两者的区别:

select top 1 * from sys.objects
select top 1 1 from sys.objects

在第一个子句中,SQL 服务器必须从表中获取所有列(从任何随机行),但在第二个子句中,从任何索引中获取“1”就可以了。

当这些子句位于exists 子句中时,情况会发生变化,因为在这种情况下,SQL Server 知道它实际上不需要获取数据,因为它不会被分配给任何东西,因此它可以处理select *处理select 1的方式相同。

由于存在只检查一行,它内置了内部顶部 1,因此手动添加它不会改变任何内容。

在存在子句中有select *select 1 的天气只是基于意见,您当然可以使用2 或“X”或其他任何您喜欢的东西来代替1。就我个人而言,我总是使用... and exists (select 1 ...

【讨论】:

  • 谢谢,我明白了(大部分都在我的操作中)。我的问题是关于为什么一个比另一个更受欢迎(因为当嵌套在和EXIST 语句中时它们在语义上是相同的)。对我来说,SELECT 1 似乎是“更安全的一般经验法则”,特别是在为不将 SQL 作为职业研究的技术顾问提供建议时
【解决方案3】:

EXISTS 是一种子查询,它只能根据子查询是否返回任何行来返回布尔值。选择 1 或 * 或在此上下文中无关紧要的任何内容,因为结果始终只是 true 或 false。

您可以通过测试这两个语句是否产生完全相同的计划来验证这一点。

select 1 where exists(select * from sys.objects)
select 1 where exists(select 1 from sys.objects)

您在外部查询中选择的内容很重要。如您所见,这两条语句产生了非常不同的执行计划:

select top 1 * from sys.objects
select top 1 1 from sys.objects

第一个会更慢,因为它必须实际返回真实数据。在这种情况下,连接到三个基础表:syspalnames、syssingleobjrefs 和 sysschobjs。

至于您在 EXISTS 子查询中放入的内容的偏好 - SELECT 1 或 SELECT * - 没关系。我通常说 SELECT 1,但 SELECT * 也一样好,您会在很多 Microsoft 文档中看到它。

【讨论】:

    【解决方案4】:

    我正在寻找只是标题中包含的实际问题的答案。我找到了at this link:

    Select Top 1 或 Top n 基本返回前n行数据 关于sql查询。选择 Top 1 1 或 Top n s 将返回第一个 n 数据为 s 的行取决于 sql 查询。

    例如,下面的查询产生的名字和姓氏 前 10 场比赛。此查询将返回名字和姓氏 仅限。

    SELECT TOP 10 FirstName, LastName
      FROM [tblUser]
      where EmailAddress like 'john%'
    

    现在,用 select top 10 'test' 查看这个查询 - 这将产生 与上一个查询中相同的行数(相同的数据库,相同的 条件),但值将是“测试”。

    SELECT TOP 10 'test'
      FROM [tblUser]
      where EmailAddress like 'john%'
    

    所以,select TOP 1 * 返回第一行,而select TOP 1 1 返回一个 只包含“1”。如果查询返回至少一行,则返回此值,否则为 Null will be returned in both cases

    作为另一个例子,这个:

    SELECT TOP 10 'test', FirstName
      FROM [tblUser]
      where EmailAddress like 'john%'
    

    将返回一个表,其中包含一个用“test”填充的列和另一个用查询的前 10 个匹配项的名字填充的列。

    【讨论】:

      猜你喜欢
      • 2012-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-16
      • 2011-10-06
      • 2019-03-20
      • 1970-01-01
      相关资源
      最近更新 更多