确定记录是不是存在的最快方法
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 1
、SELECT NULL
或SELECT 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.Exists
与select
一起使用,一旦找到一行就退出。此外,存在仅记录记录的存在,而不是记录中的实际值,从而节省了从磁盘加载行的需要(当然,假设搜索条件是索引的)。至于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 在数据库中获取不需要的特定记录的最快方法