【问题标题】:I need to get the whole row for all duplicate entries efficiently我需要有效地获取所有重复条目的整行
【发布时间】:2015-09-09 15:34:23
【问题描述】:

互联网!我对 SQL 很陌生,我需要在某些字段中获取所有具有重复信息的行,并让它们显示在其他重复项旁边(按重复项分组)。

例如,假设我有一个带有列的表:

A,B,C,D,E,F,G

我希望能够获取 B、C、D 和 E 与另一个条目共享相同值的所有条目(整行),并在原始条目旁边显示重复项。 我已经有了解决方案,但效率极低。我正在努力改善我的跑步时间

我原来的解决方案是这样的:

    SELECT TOP 1000 
    A,
    B,
    C,
    D,
    E,
    F,
    G
    FROM tbl_myTable
    WHERE (B+C+D+E+F+G) IN (
        SELECT                                  
            B+C+D+E+F+G                 
        FROM                                    
            tbl_myTable                             
        GROUP BY                                    
            B,C,D,E,F,G                 
        HAVING COUNT(*) > 1 
    )

    ORDER BY B,C,D,E,F,G ASC

这给了我想要的结果,但速度非常慢(运行时间超过 15 分钟)。我使用临时表重新设计了我的解决方案,并使用此脚本将运行时间缩短到 5 分钟:

    --Drop the temp table if it exists.
IF OBJECT_ID('tempdb..#Temp1') IS NOT NULL
DROP TABLE #Temp1

SELECT                              
     B+C+D+E+F+G AS CompareString       
 INTO #Temp1
 FROM tbl_myTable                           
 GROUP BY                                   
 B,C,D,E,F,G                
 HAVING COUNT(*) > 1

 SELECT TOP 1000 
 A,
 B,
 C,
 D,
 E,
 F,
 G
 FROM tbl_myTable
 WHERE (B+C+D+E+F+G) IN (
     SELECT * FROM #Temp1
 )
 ORDER BY B,C,D,E,F,G ASC

五分钟似乎仍然很长。有没有更快的方法来做到这一点?我是 SQL 新手,所以如果我做的不好,请告诉我!谢谢!

【问题讨论】:

标签: sql-server database performance count duplicates


【解决方案1】:

我会这样做:

with cte as (
   SELECT *
      , count(*) over (partition by B, C, D, E, F, G) as cnt
      , dense_rank() over (order by B, C, D, E, F, G) as grp
   FROM STI.[dbo].[tbl_Consignee]
)
select * 
from cte
where cnt > 1
order by grp

基本上,dense_rank() 调用为每个唯一元组提供了一个标识符(因此您可以使用 order by 子句将重复项彼此相邻放置),并且计数计算每个组的行数。

【讨论】:

  • 我必须说,这比 LDM Joe 的方法运行得快得多。两者都运行良好,但你的要快得多。谢谢!
  • 太棒了!现在作为一个延伸目标,看看你是否能找出原因。看看每个和统计 io 的执行计划。很好的狩猎!
【解决方案2】:

在没有实际数据的情况下,我不得不在这里做一些假设。

首先,我假设您的字母字段都是文本类型,并且您使用 + 来连接而不是添加数值(否则 A+B+C = 6 当 A = 1 B = 2 和 C = 3 时就像当 A=2 B=3 和 C=1 时,这将不匹配)。

接下来,我将假设在您的示例中未表示的每一行上都有某种类型的关键字段。 tbl_myTable.MyTableKey bigint IDENTITY (1,1) NOT NULL 之类的东西。

假设所有这些,我会尝试......

SELECT
    [BaseTable].MyTableKey AS [Original Record],
    [DupCheckTable].MyTableKey AS [Duplicate Record]
FROM
    tbl_myTable [BaseTable]
    LEFT OUTER JOIN tbl_myTable [DupCheckTable] ON 
            [BaseTable].A = [DupCheckTable].A
            AND
            [BaseTable].B = [DupCheckTable].B
            AND
            --... repeat for each actual field
            --AND
            [BaseTable].G = [DupCheckTable].G
            AND
            [BaseTable].MyTableKey  < [DupCheckTable].MyTableKey  --the less than operator prevents you from getting each match twice
WHERE
    [DupCheckTable].MyTableKey IS NOT NULL

我认为这会运行得更快,因为您可以使用可能已编入索引的表键作为连接的一部分。此外,您可以将您(或我的)任何查询提供给 Tuning Advisor,以查看它认为对统计数据和索引行有什么帮助。

【讨论】:

  • 我想我应该能够将原始行加入这些 MyTableKey 值以获得我需要的东西。非常感谢!
  • 我知道这是您的第一个问题。如果这可行,请accept 吗?我们在这里工作reputation,我正在努力赢得我的街头信誉。
  • 对不起 - 我是新来的。谢谢你告诉我。
猜你喜欢
  • 2018-02-07
  • 1970-01-01
  • 2013-10-30
  • 2021-07-01
  • 1970-01-01
  • 2016-10-29
  • 2020-08-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多