如何将 SQL 服务器查询的性能提高到 select 行的值不在具有一个计数的子查询中

How to improve performance of SQL Server query to select rows with value not in subquery with one count

我是 运行 SQL 服务器 2016。

对于只有一行具有特定 ConvID(大整数)值的情况,我正在尝试消除所有行。我的最终目标是在特定 ConvID 值的行数为奇数时也消除最后一行对话。如果我可以直接针对每个具有奇数行的 convID(即具有该特定 convID 值的奇数行)消除最后一行(按 chat_id 排序)的解决方案,那将是理想的。

源数据的示例在我的另一个问题中,标记为 "the desired output":

这是我的查询:

INSERT INTO dbo.RestoredConversationLinesConcatenated_WithChatIDWithoutSingleChats
       (chat_id,
        SpeakerName,
        RelativeSpeakerID,
        ConvID,
        customer_id,
        student_id,
        teacher_id,
        district_id,
        school_id,
        classroom_id,
        item_id,
        math_lesson_id,
        Label)
    SELECT * 
    FROM dbo.RestoredConversationLinesConcatenated_WithChatID AS B
    WHERE B.ConvID NOT IN (SELECT A.ConvID--, COUNT(*) AS Instances
                           FROM dbo.RestoredConversationLinesConcatenated_WithChatID AS A
                           GROUP BY A.ConvID
                           HAVING COUNT(*) = 1)
    ORDER BY B.chat_id

这是估计的查询执行计划(您可能需要在新 window 中打开并调整大小才能完整查看):

我的来源 table 大小约为 1700 万行,因此查询性能需要更好。当上面的查询 运行 超过一个小时时,我停止了上面的查询,但只向目标 table 插入了 40 行,并且在实时查询统计面板中完成了 0%。

我使用 INSERT INTO 而不是 SELECT INTO 的原因是因为 table 有一个 IDENTITY 列可以自动递增,因为删除行会使 ID 全部乱序。 (否则,我不反对删除 table 并使用 SELECT INTO。)

编辑: 这是我消除只有一个 ConvID 值的行的最终解决方案:

SELECT * 
INTO dbo.RestoredConversationLinesConcatenated_WithChatIDWithoutSingleChats
FROM dbo.RestoredConversationLinesConcatenated_WithChatID c
EXCEPT
SELECT *
FROM dbo.RestoredConversationLinesConcatenated_WithChatID b
WHERE NOT EXISTS (SELECT 1
                  FROM dbo.RestoredConversationLinesConcatenated_WithChatID a
                  WHERE a.ConvId = b.ConvId 
                  AND 
                        a.chat_id <> b.chat_id  -- or something that uniquely identifies each row
                  )

我还根据 SQL Server Database Engine Tuning Advisor 的建议创建了很多分区和统计信息以及两个索引。最终查询在 42 秒内完成。

使用not exists:

SELECT * 
FROM dbo.RestoredConversationLinesConcatenated_WithChatID b
WHERE NOT EXISTS (SELECT 1
                  FROM dbo.RestoredConversationLinesConcatenated_WithChatID a
                  WHERE a.ConvId = b.ConvId AND 
                        a.ChatId <> b.ChatId  -- or something that uniquely identifies each row
                  );

我不确定哪一个 id 唯一标识每一行。但这就是 ChatId 的目的——如果这不是正确的 ID,请使用正确的 ID。

为了使其发挥最佳效果,您需要 (ConvId, ChatId) 上的索引 -- 一个复合索引,列按该顺序排列。