代码之家  ›  专栏  ›  技术社区  ›  Robert

检查SQL查询是否返回结果的有效方法

sql
  •  20
  • Robert  · 技术社区  · 15 年前

    我想编写一个查询,它只返回1或0,这取决于是否会有结果。

    我想用这个

    IF EXISTS(
          select * from myTable 
          where id=7 and rowInsertDate BETWEEN '01/01/2009' AND GETDATE()
    )
    SELECT 1
    ELSE
    SELECT 0
    

    这是一般的前提。

    最终的结果实际上是一个更复杂的查询,使用一对多的参数和使用sp_executesql构建和执行的字符串。

    我的问题是,假设“count”返回376986,需要4秒来计算。正在使用if exists,当它找到一行满足条件时将立即停止。

    我正在决定是否使用if exists,或者只查询@@rowcount并查看它是否大于零。

    我试过一些测试,两个都以相同的速度运行,但是在2年时间里,当有更多的数据时,如果存在的话,是否会有性能提升呢?

    谢谢

    8 回复  |  直到 15 年前
        1
  •  7
  •   AdaTheDev    15 年前

    如果存在的话应该更有效,因为一旦找到第一行,它就被优化为停止。这就是我总是要做这种检查的方式,而不是使用count()。

    为了进行性能比较,只需在每次测试之前清除数据和执行计划缓存(仅限非生产数据库服务器),以确保测试是公平的:

    DBCC FREEPROCCACHE
    DBCC DROPCLEANBUFFERS
    
        2
  •  11
  •   Nathan Feger    15 年前

    你有身份证和日期的索引吗?

    也许你只是想:

    select top 1  1 from myTable where id=7 and rowInsertDate > '01/01/2009' 
    

    注意:如果数据存在,则返回1,否则不返回任何值。

    另一个编辑。如果没有数据,这不会返回值为空的行,而是不会返回任何行。在更形象的意义上更像空值。

        3
  •  10
  •   Alex Bagnolini    15 年前

    这是我在项目中能获得的最快速度:

    SELECT CASE WHEN EXISTS (
      select top 1 1 
      from myTable 
      where id=7 
      and rowInsertDate BETWEEN '01/01/2009' AND GETDATE()
    ) THEN 1 ELSE 0 END AS AnyData
    
        4
  •  3
  •   Ender    15 年前

    我就这么写:

    IF EXISTS(
          SELECT 0 FROM myTable 
          WHERE id=7 and rowInsertDate BETWEEN '01/01/2009' AND GETDATE()
    )
    SELECT 1
    ELSE
    SELECT 0
    

    这样,您就不会返回任何数据,只需检查条件即可。我发现这个查询结构非常快。

        5
  •  2
  •   statenjason    15 年前

    如果你不需要376986行,只想知道某个东西是否存在,那么如果存在就更有意义了。 另外,另一个有用的地方是要求索引列(主键)而不是*因为您不关心实际的数据。

        6
  •  1
  •   Kristen    15 年前

    最终结果实际上是 更复杂的查询,需要一个 许多参数和构建的字符串 使用sp_executesql启动和执行

    我认为您至少需要完整的From、Join和Where语法,否则您的实际查询可能会发现Nothiong(例如,通过添加原始if-exists查询中不存在的内部联接,结果发现不满足)。

    如果您要解决这个问题,您可能需要将pk放入某种“batch id holding table”中,这样您就可以为查询的第二个“presentation”部分引用pk。

    如果你得到376986个结果,你打算怎么做?如果要在屏幕上向用户显示它们,并进行某种分页,那么将结果显示在“batch id holding table”中可能有助于实现这一点(尽管,显然,对用户数据的任何添加/删除等操作都会破坏分页显示)。

    或者,如果您要使用分页,只需使用top/limit/set rowcount将结果限制为第一页已满(确保您有一个order by以便序列可重复),然后在用户按下Next-page按钮时对第2页进行排序(我们通过包含las的pk的Next-page按钮进行处理)。t按排序顺序显示记录,以便下一页可以从该点继续)。

    查询优化程序将根据选择列表的内容做不同的事情,因此询问“if exists”后面跟着“select col1,col2,…”“来自…”实际上可能意味着您使用不同的缓存数据和查询计划运行了两次完整的查询,因此总体而言,这可能对您的服务器造成更大的压力,并导致用户等待更长时间,而不仅仅是获取第一页/100行等。

    SQL Server将缓存sp_executesql的查询计划,但请确保将查询参数化,以便在可能的情况下恢复缓存的计划。

        7
  •  0
  •   Philip Kelley    15 年前

    首先,您应该尝试虚拟一个数据库,其中包含的数据量与您(或您的继任者)两年内可能需要处理的数据量相同。那么你的测试将会更有效率。

    如果存在()将更快,因为数据库引擎只需找到符合条件的第一条匹配记录。当然,使用适当的索引也会更快。

    另一个提示,不要使用*,因为实际上不需要检索列。

    IF EXISTS(select 1 from myTable where id=7 and rowInsertDate BETWEEN '01/01/2009' AND GETDATE())
    

    …应该(根据我读到的)更快一点。

        8
  •  0
  •   MandoMando    15 年前

    我认为亚历克斯·巴格诺里尼的回答是正确的。系统不会让我评论他的回答(新账户)。我唯一要做的修改是将第二个1改为ID。

    有时,在项目部分中减少列表(即列列表)会使DB引擎只访问索引,而不访问表,因此速度更快。当然,这取决于数据库引擎和索引结构/大小。(所有rowInsertDate日期都应为<getDate(),因此可以跳过该比较)

    存在时选择案例( 选择前1 ID 从我的表 其中ID=7 和行插入日期>'01/01/2009' )然后1,否则0以anydata结尾