从表中删除重复的 ID - 性能改进

Posted

技术标签:

【中文标题】从表中删除重复的 ID - 性能改进【英文标题】:Delete repeated Ids from Table - Performance Improvement 【发布时间】:2016-08-26 14:38:47 【问题描述】:

我有一张重复代码的表格,我需要清理表格以删除重复的代码,但表格中至少有一个左侧。

我的桌子是这样的:

FriendlyFunctionCode      MemberFirmId     FunctionLevel3Desc
1                         Value1           Value2
1                         Value2           Value3
2                         Value4           Value5

我需要这样的东西:(剩下哪一行并不重要,至少要有一个)

FriendlyFunctionCode      MemberFirmId     FunctionLevel3Desc
1                         Value1           Value2
2                         Value4           Value5

我有这个查询,但性能很糟糕

SELECT MemberFirmId, FriendlyFunctionCode
INTO #ToDeleteRepeated
FROM [dbo].[FirmFunction]
GROUP BY MemberFirmId, FriendlyFunctionCode
HAVING COUNT(1) > 1

DECLARE @Code VARCHAR(100), @Desc VARCHAR(250)

WHILE ((SELECT COUNT(1) FROM #ToDeleteRepeated) > 0) 
BEGIN
    SELECT TOP 1 @Code = FriendlyFunctionCode FROM #ToDeleteRepeated
    WHILE ((SELECT COUNT(1) FROM [FirmFunction] WHERE FriendlyFunctionCode = @Code) > 0) 
    BEGIN
        SELECT TOP 1 @Desc = FunctionLevel3Desc FROM [FirmFunction] WHERE FriendlyFunctionCode = @Code
        DELETE FROM [FirmFunction] WHERE FriendlyFunctionCode = @Code AND FunctionLevel3Desc = @Desc
    END
END

有什么建议吗?

【问题讨论】:

首先,当它们具有与 FriendlyFunctionCode 相关的不同值时,您是否关心您保留或删除哪些记录?您的查询表明您没有。实际上只是要注意,如果 FunctionLevel3Desc 也重复,您的查询将删除多条记录。 【参考方案1】:
WITH CTE AS (SELECT MemberFirmId, FriendlyFunctionCode, 
                ROW_NUMBER() over (PARTITION by FriendlyFunctionCode      ORDER BY FriendlyFunctionCode      ) AS RN
                FROM [dbo].[FirmFunction]
        )
        DELETE CTE WHERE CTE.RN >1

【讨论】:

我认为你只需要FriendlyFunctionCode分区 很棒的答案,也试过了,效果很好。【参考方案2】:

使用 CTE 和 row_number() 删除

;with cte as (
select *, row_number() over(partition by friendlyfunctioncode order by memberfirmid) rn
 from deletingtable)
delete from cte where rn > 1

这将按照以下执行计划执行:

表/聚集索引扫描 --> 排序(如果没有索引) --> 段 --> 序列项目 --> 过滤然后删除,

如果它在 FriendlyFunctionCode 上有正确的索引,它在单次扫描中执行得更快

【讨论】:

表上可能的附加索引怎么样? 没有重复删除。 意思是,如果有更多的索引,那么这些索引会因为删除而产生开销【参考方案3】:

您可以使用这样的窗口函数。无需使用游标(在 SQL Server 中表现不佳)。您可以自行运行内部选择以查看它对行号的作用。

测试数据

CREATE TABLE #TestData (FriendlyFunctionCode int, MemberFirmId nvarchar(10), FunctionLevel3Desc nvarchar(10))
INSERT INTO #TestData
VALUES
(1,'Value1','Value2')
,(1,'Value2','Value3')
,(2,'Value4','Value5')

查询

SELECT
a.FriendlyFunctionCode
,a.MemberFirmId
,a.FunctionLevel3Desc
INTO #SavedData
FROM
(
    SELECT
    FriendlyFunctionCode
    ,MemberFirmId
    ,FunctionLevel3Desc
    ,ROW_NUMBER() OVER(PARTITION BY FriendlyFunctionCode ORDER BY FriendlyFunctionCode) RowNum
    FROM #TestData
) a
WHERE a.RowNum = 1

TRUNCATE TABLE #TestData

INSERT INTO #TestData (FriendlyFunctionCode, MemberFirmId, FunctionLevel3Desc)
SELECT
FriendlyFunctionCode
,MemberFirmId
,FunctionLevel3Desc
FROM #SavedData

DROP TABLE #SavedData

结果

FriendlyFunctionCode    MemberFirmId    FunctionLevel3Desc  
1                       Value1          Value2              
2                       Value4          Value5                  

【讨论】:

正确的概念,但实际上并没有删除记录 这很公平。我已经更新了我的答案以截断原始表并插入保存的记录。应该比删除更好。【参考方案4】:

您可以在 FunctionCode 上使用 MAX 和分组。

SELECT 
   FriendlyFunctionCode, 
   MAX(MemberFirmId) as MemberFirmId, 
   MAX(FunctionLevel3Desc) as FuncationLevel3Desc
INTO #StagingTable
FROM
   FirmFunction
GROUP BY
   FriendlyFunctionCode

然后截断您的表,然后选择回其中...或者只是一起创建一个表并将不同的(最大)记录插入其中。

TRUNCATE TABLE FirmFunction

INSERT INTO FirmFunction (FriendlyFunctionCode,MemberFirmId,FunctionLevel3Desc)
SELECT * FROM #StagingTable

这比创建一个表 FirmFunction2 更安全

SELECT TOP 1 INTO FirmFunction2 FROM FirmFunction WHERE 1=0

INSERT INTO FirmFunction2 (FriendlyFunctionCode, MemberFirmId, FunctionLevel3Desc)
SELECT 
       FriendlyFunctionCode, 
       MAX(MemberFirmId) as MemberFirmId, 
       MAX(FunctionLevel3Desc) as FuncationLevel3Desc
    INTO #StagingTable
    FROM
       FirmFunction
    GROUP BY
       FriendlyFunctionCode

然后您可以检查 FirmFunction2 中的日期,如果您满意...在删除另一个表后重命名它。

【讨论】:

好方法,修改它并像魅力一样工作。谢谢。 @Rednaxel 我只想强调 CTE 很棒,但使用时要格外小心。通常初学者(不是说你是初学者)像临时表一样使用它们,而临时表不能使用。这通常没有任何问题,除了 CTE 会影响原始数据源,因为您在您的情况下有意这样做。因此,如果您使用 CTE 执行和插入、删除等操作,则无法返回。确保语法正确...您正确分区和排序等等。我提供的方法没有那么精简,但不太容易出错。 感谢您的 cmets,我会小心 CTE。

以上是关于从表中删除重复的 ID - 性能改进的主要内容,如果未能解决你的问题,请参考以下文章

从表中删除后自动递增[重复]

如何从表中删除重复值 [重复]

如何从表中删除重复记录? [复制]

从表中的多个重复项中删除特定记录

在Oracle中从表中删除重复行

BigQuery 标准 SQL:从表中删除重复项