确定记录是不是存在的最快方法

Posted

技术标签:

【中文标题】确定记录是不是存在的最快方法【英文标题】:Fastest way to determine if record exists确定记录是否存在的最快方法 【发布时间】:2013-08-09 11:35:44 【问题描述】:

正如标题所暗示的...我试图找出开销最小的最快方法来确定表中是否存在记录。

示例查询:

SELECT COUNT(*) FROM products WHERE products.id = ?;

    vs

SELECT COUNT(products.id) FROM products WHERE products.id = ?;

    vs

SELECT products.id FROM products WHERE products.id = ?;

假设?'TB100' 交换...第一个和第二个查询将返回完全相同的结果(例如...1 用于此对话)。最后一个查询将按预期返回 'TB100',如果表中不存在 id,则返回任何内容。

目的是确定id 是否在表中。如果不是,程序接下来会插入该记录,如果是,程序将跳过它或执行基于本问题范围之外的其他程序逻辑的 UPDATE 查询。

哪个更快并且开销更少? (每次程序运行都会重复上万次,一天会运行很多次)。

(通过 M$ 提供的 JDBC 驱动程序从 Java 对 M$ SQL Server 运行此查询)

【问题讨论】:

这可能取决于数据库。例如,依靠 Postgres 是相当缓慢的。 抱歉,这是 Java 通过 jdbc 驱动程序与 M$ SQL 对话。我会更新我的 OP。 还有exists。 @Nikola Markovinović:在这种情况下你会如何使用它? @zerkms 取决于上下文。如果在存储过程中,它将是if exists(select null from products where id = @id);如果在由客户端 select case when exists (...) then 1 else 0 end 直接调用的查询中。 【参考方案1】:

EXISTS(或NOT EXISTS)专为检查是否存在而设计,因此应该是(并且是)最佳选择。它将在匹配的第一行停止,因此它不需要TOP 子句,并且它实际上不选择任何数据,因此没有列大小的开销。您可以在这里安全地使用SELECT * - 与SELECT 1SELECT NULLSELECT AnyColumn...(you can even use an invalid expression like SELECT 1/0 and it will not break) 没有什么不同。

IF EXISTS (SELECT * FROM Products WHERE id = ?)
BEGIN
--do what you need if exists
END
ELSE
BEGIN
--do what needs to be done if not
END

【讨论】:

这不是必须先执行 SELECT 语句,然后执行 IF EXISTS 语句...导致额外的开销,因此需要更多的处理时间吗? @SnakeDoc No. Existsselect 一起使用,一旦找到一行就退出。此外,存在仅记录记录的存在,而不是记录中的实际值,从而节省了从磁盘加载行的需要(当然,假设搜索条件是索引的)。至于if 的开销 - 无论如何,您将不得不花费这微不足道的时间。 @NikolaMarkovinović 有趣的一点。我不确定该字段上是否存在索引,而且我的新手 SQL 不知道如何找到。我正在通过 JDBC 从 Java 使用这个数据库,并且该数据库远程位于某处的 colo 中。我只获得了一个“数据库摘要”,其中详细说明了每个表中存在哪些字段、它们的类型以及任何 FK 或 PK。这有什么改变吗? @SnakeDoc 要了解表结构,包括外键和索引,请运行sp_help table_name。无论是使用select top 还是exists,在从多行中检索几行时,索引都是必不可少的;如果它们不存在,则 sql 引擎将不得不执行表扫描。这是最不理想的表搜索选项。如果您无权创建索引,则必须与对方的技术人员沟通,以了解他们是自动调整索引还是希望您建议索引。 @Konstantin 你可以做类似SELECT CASE WHEN EXISTS(..) THEN 1 ELSE 0 END;【参考方案2】:

SELECT TOP 1 products.id FROM products WHERE products.id = ?; 将优于您的所有建议,因为它会在找到第一条记录后终止执行。

【讨论】:

在通过 PK(或任何其他唯一键)搜索时,优化器是否不考虑自身? 他从未说过这是 PK,但如果是这样,那么优化器会考虑到这一点。 @Declan_K:在这种情况下,我的魔法球似乎失败了,标题为id 的列不是PK。所以 +1 你的建议。 如果不是PK,我还建议确保该列上有索引。否则,查询将不得不进行表扫描,而不是更快的表查找。 我认为我们应该考虑@nenad-zivkovic 回答这个问题。【参考方案3】:

没有什么可以打败 -

SELECT TOP 1 1 FROM products WHERE id = 'some value';

您无需数数即可知道表中是否有数据。并且不要在不需要时使用别名。

【讨论】:

尽管它的名字 id 不是主键。因此,即使您没有计数,您仍然需要找到所有匹配的记录,可能有数千条记录。关于别名 - 代码一直在进行中。你永远不知道什么时候必须回去。别名有助于防止愚蠢的运行时错误;例如,唯一的列名不需要别名不再是唯一的,因为有人在另一个连接表中创建了同名的列。 是的,你完全正确。别名有很大帮助,但我认为不使用连接时没有任何区别。所以,我说如果没有必要就不要使用它。 :) 你可以找到关于检查存在性的长时间讨论here。 :) 我不知道为什么我接受了aliasing这个词。正确的术语是qualifying。这里是longer explanation by Alex Kuznetzov。关于单表查询 - 现在是单表。但是后来,当发现错误并且您试图控制洪水时,客户很紧张,您加入另一个表只是为了面对错误消息 - 很容易纠正的消息,但不是在这个汗流浃背的时刻,一个小中风来袭 - 你纠正了记住永远不要离开列时出错... 现在不能忽视这一点。谢谢!! :)【参考方案4】:
SELECT CASE WHEN EXISTS (SELECT TOP 1 *
                         FROM dbo.[YourTable] 
                         WHERE [YourColumn] = [YourValue]) 
            THEN CAST (1 AS BIT) 
            ELSE CAST (0 AS BIT) END

这种方法会为您返回一个布尔值。

【讨论】:

可以省略 Top 语句和 * 语句以使其更快一些,因为 Exist 一旦找到记录就会退出,所以像这样:SELECT CASE WHEN EXISTS (SELECT 1 FROM dbo .[YourTable] WHERE [YourColumn] = [YourValue]) THEN CAST (1 AS BIT) ELSE CAST (0 AS BIT) END 这个建议没有提到为什么这会比 SQL Server 中的内置存在/不存在语句更快。如果没有任何基准测试,我很难相信案例陈述会比直接的真/假响应产生更快的结果。【参考方案5】:

不要认为任何人都提到过它,但如果您确定数据不会在您下方更改,您可能还需要应用 NoLock 提示以确保它在读取时不会被阻止。

SELECT CASE WHEN EXISTS (SELECT 1 
                     FROM dbo.[YourTable] WITH (NOLOCK)
                     WHERE [YourColumn] = [YourValue]) 
        THEN CAST (1 AS BIT) 
        ELSE CAST (0 AS BIT) END

【讨论】:

【参考方案6】:

你也可以使用

 If EXISTS (SELECT 1 FROM dbo.T1 WHERE T1.Name='Scot')
    BEGIN
         --<Do something>
    END 

ELSE    
     BEGIN
       --<Do something>
     END

【讨论】:

【参考方案7】:

以下是确定数据库中是否存在记录的最简单和最快的方法 好消息是它适用于所有关系数据库

SELECT distinct 1 products.id FROM products WHERE products.id = ?;

【讨论】:

【参考方案8】:
SELECT COUNT(*) FROM products WHERE products.id = ?;

这是适用于所有数据库的跨关系数据库解决方案。

【讨论】:

但是你强制数据库循环遍历所有记录,在大表上非常慢 @amd 解释一下为什么? @amd 你的评论很有道理。这个查询更像是 FIND ALL 而不是 FIND ANY。【参考方案9】:

对于那些在 mysql 或 Oracle 背景中遇到此问题的人 - MySQL 支持 LIMIT 子句来选择有限数量的记录,而 Oracle 使用 ROWNUM。

【讨论】:

【参考方案10】:
create or replace procedure ex(j in number) as
i number;
begin
select id into i from student where id=j;
if i is not null then
dbms_output.put_line('exists');
end if;
exception
   when no_data_found then
        dbms_output.put_line(i||' does not exists');

end;

【讨论】:

可能您的代码运行良好,但如果您添加一些额外信息会更好,以便更好地理解。【参考方案11】:

我过去使用过它,它不需要全表扫描来查看是否存在某些东西。速度超级快……

UPDATE TableName SET column=value WHERE column=value
IF @@ROWCOUNT=0
BEGIN
     --Do work
END             

【讨论】:

【参考方案12】:

对于 MySql,您可以像下面这样使用 LIMIT(php 中的示例)

  $sql = "SELECT column_name FROM table_name WHERE column_name = 'your_value' LIMIT 1";
  $result = $conn->query($sql);
  if ($result -> num_rows > 0) 
      echo "Value exists" ;
   else 
      echo "Value not found";
  

【讨论】:

【参考方案13】:

SQL SERVER 2012+

SELECT IIF((SELECT TOP 1 1 FROM dbo.[YourTable] WHERE [YourColumn] = [YourValue]) IS NULL, 0, 1)

【讨论】:

【参考方案14】:

为什么不简单地使用

SELECT EXISTS (SELECT 1 FROM products WHERE products.id = ?)

【讨论】:

为什么不呢?也许是因为它的语法不正确?

以上是关于确定记录是不是存在的最快方法的主要内容,如果未能解决你的问题,请参考以下文章

如果不存在插入新记录的最快方法,请仔细检查?

查看实体的子表是不是包含任何记录的最快方法

使用 Django 在数据库中获取不需要的特定记录的最快方法

根据多对多关系返回记录列表的最快方法

CloudKit,NSPredicate 在私有容器中返回计数或确定是不是存在任何记录?

如何确定记录是不是是 NOT IN 的一部分而不是不存在?