有时我需要检查是否存在至少一条记录,通常我会使用:
IF EXISTS (SELECT TOP 1 1 FROM [SomeTable] WHERE [Fields] = [Values]) BEGIN
-- action
END
是否有快速检查是否存在多个记录的方法?我可以做类似的事情:
IF EXISTS (SELECT 1 FROM [SomeTable]
WHERE [Fields] = [Values]
HAVING Count(*) > 1)
BEGIN
-- action
END
但是我不确定这是否是最快的方式,因为它会测试集合中的所有记录。有更快的方法吗?
'where'部分可能非常复杂,可能包含多个AND和OR。
答案 0 :(得分:7)
SQL Server通常不会使聚合查询短路。有时,它可以转换HAVING COUNT(*) > 0
查询以使用与EXISTS
(discussed in the comments here)相同的计划,但这是最直接的。
HAVING COUNT(*) > 1
查询将始终计算所有行,即使理论上它可能会在第2行之后停止计数。
考虑到这一点,我会使用
IF EXISTS(
SELECT * FROM (
SELECT TOP 2 *
FROM [SomeTable]
WHERE [Fields] = [Values]
) T
HAVING COUNT(*)=2)
TOP 2
迭代器将在返回第二个之后停止请求行,从而允许内部查询提前短路,而不是全部返回并计算它们。
两个版本的示例计划如下
关于
的评论中的问题“你怎么知道哪一个最好?这是查询成本吗?”
在上述计划中显示的特定情况下,成本将是一个合理的指示,因为估计和实际行计数非常准确,除了添加TOP
迭代器之外,两个计划非常相似。因此,计划中显示的额外成本完全表示需要扫描额外数量的行(并且可能从光盘读入)并计算。
在这种情况下,很明显这只是代表了额外的工作。在其他计划中它可能不是。添加TOP 2
可能会显着改变其下方的查询树(例如,使用blocking iterators对计划进行攻击)
在这种情况下,执行计划中显示的成本可能不是可靠的指标。即使在实际执行计划中,所显示的成本也基于估计,因此仅与那些一样好,即使估计的行数很好,所显示的成本仍然只是基于某些建模假设。
SQL Kiwi在this recent answer on the DBA site
中做得很好优化器成本估算主要仅对内部服务器有用 目的。它们不打算用于评估潜力 表现,即使是在“高水平”。该模型是一种抽象 恰好在内部目的下工作得相当好 专为。估计成本承担任何合理的可能性 与您的硬件和配置上的实际执行成本相似 确实很小。
根据实际情况选择其他指标来比较效果 问题对你很重要。
逻辑读取(在SET STATISTICS IO ON;
时显示)是一个这样的度量标准,可以查看,但再次专注于此可能会产生误导。测试查询持续时间可能是唯一可靠的方法,但即使这不是一门精确的科学,因为性能可能会因服务器上的并发活动而变化(等待内存授予,可用的DOP,缓存中的相关页面数)。
最后,它只是得到一个查询计划,该计划可以有效地利用服务器上的资源。
答案 1 :(得分:2)
我确信有一些技巧可以让你更快地执行此检查 - 虽然它很大程度上取决于你的模式(尤其是索引),并且特定检查可能适用于一种情况而不适用于另一种情况。
以下内容可能适合您。
IF EXISTS (SELECT * FROM [SomeTable] T1
INNER JOIN [SomeTable] T2
ON T1.UniqueID <> T2.UniqueID
WHERE T1.[Fields] = T1.[Values]
AND T2.[Fields] = T2.[Values])
BEGIN
-- action
END
答案 2 :(得分:1)
不要打扰top
或select 1
。
if exists (select * ...)
同样快。
答案 3 :(得分:1)
我在这个包含1900万条记录的表格中获得了出色的表现:
IF EXISTS (
SELECT '1' FROM (
SELECT TOP(2) '1' AS 'N'
FROM TBL_KV3) AS Z
HAVING COUNT(*) > 1
)
SELECT '1'
ELSE
SELECT '0'
答案 4 :(得分:0)
不确定效果,但您可以使用CTE
和COUNT(*)OVER
:
WITH Match AS
(
SELECT t1.*, COUNT(*)OVER(PARTITION BY t1.Fields)AS CountFields
FROM SomeTable t1
WHERE t1.Fields=@Values
)
SELECT m1.*
FROM Match m1
WHERE CountFields >= 2