【问题标题】:SQL Server - alternative to using NOT EXISTSSQL Server - 使用 NOT EXISTS 的替代方法
【发布时间】:2016-04-19 09:53:05
【问题描述】:

我有一个包含 EntityID 列的大约 200,000 条记录的列表,我将其加载到临时表变量中。

如果 dbo.EntityRows 表中不存在 Temp 表中的 EntityID,我想插入 Temp 表变量中的任何记录。 dbo.EntityRows 表包含大约 800,000 条记录。

与 dbo.EntityRows 表有大约 500,000 条记录时相比,该过程非常缓慢。

我的第一个猜测是因为 NOT EXISTS 子句,Temp 变量中的每一行都必须扫描 dbo.EntityRows 表的整个 800k 行以确定它是否存在。

问题:是否有其他方法可以在不使用 NOT EXISTS 的情况下运行此比较检查,这会产生巨大的成本并且随着 dbo.EntityRows 的持续增长只会变得更糟?

编辑:欣赏 cmets。这是查询(我在 IF NOT EXISTS 检查之后省略了部分。之后,如果 NOT EXISTS,我插入到 4 个表中)。

declare @EntityCount int, @Counter int, @ExistsCounter int, @AddedCounter int
declare @LogID int
declare @YdataInsertedEntityID int, @YdataSearchParametersID int
declare @CurrentEntityID int
declare @CurrentName nvarchar(80)
declare @CurrentSearchParametersID int, @CurrentSearchParametersIDAlreadyDone int 
declare @Entities table 
(
    Id int identity,
    EntityID int,
    NameID nvarchar(80), 
    SearchParametersID int
)

insert into @Entities
select EntityID, NameID, SearchParametersID from YdataArvixe.dbo.Entity     order by entityid;


set @EntityCount = (select count(*) from @Entities);
set @Counter = 1;
set @LogID = null;
set @ExistsCounter = 0;
set @AddedCounter = 0;
set @CurrentSearchParametersIDAlreadyDone = -1;

While (@EntityCount >= @Counter)
begin
    set @CurrentEntityID = (select EntityID from @Entities
                                where id = @Counter)

    set @CurrentName = (select nameid from @Entities
                                    where id = @Counter);

    set @CurrentSearchParametersID = (select SearchParametersID from @Entities
                                            where id = @Counter)

    if not exists (select 1 from ydata.dbo.entity
                    where NameID = @CurrentName)
    begin
       -- I insert into 4 tables IF NOT EXISTS = true
    end

【问题讨论】:

  • 一般情况下,NOT EXISTS is the fastest method。您可能需要添加索引以加快查询速度。
  • 你能发布你的查询吗?
  • 你能用temporary-table 替换table-variable 吗?根据您的实例设置,服务器可以选择使用并行计划并优化查询。 table-variable 不能成为此类计划的一部分,因为服务器“认为”它只有一行。
  • 发布您的查询,包括您的actual execution plan。执行计划很可能已经给您建议您缺少索引(我相信会是这种情况)。总帐。
  • Gotqn 说的也很到位。通常表变量的性能很差。 (本地)临时表的性能要好得多(从技术上讲,会产生更好的执行计划)。

标签: sql-server performance tsql not-exists query-tuning


【解决方案1】:

我不确定,但我们可以通过以下方式进行检查

(SELECT COUNT(er.EntityID) FROM dbo.EntityRows er WHERE er.EntityID = EntityID) <> 0

(SELECT er.EntityID FROM dbo.EntityRows er WHERE er.EntityID = EntityID) IS NOT NULL

EntityID NOT EXISTS  (SELECT er.EntityID FROM dbo.EntityRows er)

EntityID NOT IN (SELECT er.EntityID FROM dbo.EntityRows er)

但根据我的信念,计数会带来良好的性能。 正如“Felix Pamittan”所说,索引也将有助于提高性能

【讨论】:

  • 获取计数可能会给您带来非常糟糕的性能 - 因为它需要遍历 所有行 才能确定计数 - 当您真的只想知道给定值是否存在......NOT EXISTS 将在找到匹配值后停止循环......
【解决方案2】:

正如@gotqn 所说,从使用临时表开始。填表后在 EntityID 上创建索引。如果 EntityRows 中的 EntityID 上没有索引,请创建一个。

我经常做这样的事情,我一般使用以下模式:

INSERT INTO EntityRows (
    EntityId, ...
)

SELECT T.EntityId, ...
FROM #tempTable T
LEFT JOIN EntityRows E
ON T.EntityID = E.EntityID
WHERE E.EntityID IS NULL

如果您想了解更多信息,请发表评论。

【讨论】:

  • 我应该使用临时表,因为涉及的行不小。我将在临时表上添加一个索引。将发布结果,谢谢!
【解决方案3】:

嗯,答案很基本。 @Felix 和 @TT 提出了正确的建议。谢谢!

我在 ydata.dbo.entity 的 NameID 字段上放置了一个非聚集索引。

if not exists (select 1 from ydata.dbo.entity
                    where NameID = @CurrentName)

因此它现在可以使用索引快速处理 NOT EXISTS 部分,而不是扫描整个 dbo.entity 表。它再次快速移动。

【讨论】:

    猜你喜欢
    • 2010-11-13
    • 1970-01-01
    • 2021-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-06
    • 1970-01-01
    相关资源
    最近更新 更多