我想在没有主键的情况下删除表中的重复行 已定义(非标准化DB)。
我的问题是 - 我的桌子有大约5.4亿条记录。以前我使用CTE删除记录但是花费的时间超过8小时。我想优化查询。 例如:如果我们有table1,数据如下,
ID FNAME LNAME
1 AAA CCC
2 BBB DDD
1 AAA CCC
2 BBB DDD
1 AAA CCC
2 BBB DDD
3 BCB DGD
删除重复的行,并使用单个查询将数据保存到表中。
ID FNAME LNAME
1 AAA CCC
2 BBB DDD
3 BCB DGD
以前我应用过这种类型的查询 -
;with TBLCTE(EmpID,Ranking)
AS
(
select
EmpID,
Ranking = DENSE_RANK() over (PARTITION BY EmpID order by newID())
from @TBL
)
delete from TBLCTE where Ranking > 1
select * from @TBL order by EmpID
但是花了太多时间。
我想要一个能够满足这些条件的解决方案:
答案 0 :(得分:1)
通过块传输到OldTable的NewTable数据:
DECLARE @ChunkSize INT = 1000;
WHILE (EXISTS(
SELECT TOP(1)1 FROM OldTable ot
WHERE
NOT EXISTS(
SELECT TOP(1) 1
FROM NewTable nt
WHERE
nt.FNAME = ot.FNAME AND nt.LNAME = ot.LNAME)))
BEGIN
BEGIN TRANSACTION;
INSERT INTO NewTable(FNAME, LNAME)
SELECT DISTINCT TOP(@ChunkSize)
FNAME, LNAME
FROM
OldTable ot
WHERE
NOT EXISTS(
SELECT TOP(1) 1
FROM NewTable nt
WHERE
nt.FNAME = ot.FNAME AND
nt.LNAME = ot.LNAME);
COMMIT TRANSACTION;
END;
清除源表
TRUNCATE TABLE OldTable;
将数据传回OldTable
WHILE (EXISTS(
SELECT TOP(1)1 FROM NewTable nt
WHERE
NOT EXISTS(
SELECT TOP(1) 1
FROM OldTable ot
WHERE
nt.FNAME = ot.FNAME AND nt.LNAME = ot.LNAME)))
BEGIN
BEGIN TRANSACTION;
INSERT INTO OldTable(FNAME, LNAME)
SELECT DISTINCT TOP(@ChunkSize)
FNAME, LNAME
FROM
NewTable nt
WHERE
NOT EXISTS(
SELECT TOP(1) 1
FROM OldTable ot
WHERE
nt.FNAME = ot.FNAME AND
nt.LNAME = ot.LNAME);
COMMIT TRANSACTION;
END;
清除转移表:
TRUNCATE TABLE NewTable;
SELECT TOP(1000) * FROM OldTable
结果:
我认为使用SSIS是将数据传输到另一个表然后将其返回的最快方法。
尝试用鼠标右键单击数据库,任务 - >导入数据。然后选择相同的DB作为数据源并选择“Write custom query ...”选项:SELECT DISTINCT FNAME,LNAME FROM Old Table并选择NewTable作为目标表。
最后,运行导入
答案 1 :(得分:1)
试试这个
WITH TempId AS (
SELECT *,
row_number() OVER(PARTITION BY ID, FNAME,LNAME ORDER BY ID) AS [Num]
FROM Employee)
DELETE TempId WHERE [Num] > 1
Select * from Employee
中找到解决方案
答案 2 :(得分:0)
试试这个
Select * into #temp from @TBL
create nonclustered index Temp_Index on #temp(EmpId)
;with TBLCTE(EmpID,Ranking)
AS
(
select
EmpID,
Ranking = DENSE_RANK() over (PARTITION BY EmpID order by newID())
from #temp
)
delete from #temp where Ranking > 1
truncate table @TBL
insert into @TBL
Select * from #temp
答案 3 :(得分:0)
您必须删除较小块中的重复数据 - 进行循环并相互处理块。最小块被定义为1个唯一记录的所有重复...
你的陈述花了这么长时间,因为它必须在内存中创建整个快照。
答案 4 :(得分:0)
你可以这样做:
1.将不同的记录插入临时表中。
2.Truncate原始表。
3.将记录插回原始表格。
SELECT DISTINCT T.*
INTO #TEMPTABLE
FROM T;
TRUNCATE TABLE T;
INSERT INTO t
SELECT tt.*
FROM #temptable tt;
OR
1.将不同的记录插入临时表中。
2.Drop原始表。
3.重命名临时表
SELECT DISTINCT *
INTO NewTable
FROM OldTable;
DROP TABLE OldTable;
EXEC sp_rename 'OldTable', 'NewTable'
您可以用更快的方式替换SELECT DISTINCT
以获取不同的记录。但程序仍然保持不变。
这是使用Paul White的递归CTE的超快DISTINCT
。请参阅this以获取参考:
CREATE CLUSTERED INDEX c ON dbo.T(EmpID);
WITH RecursiveCTE
AS (
SELECT data = MIN(T.data)
FROM dbo.Test T
UNION ALL
SELECT R.data
FROM (
-- A cunning way to use TOP in the recursive part of a CTE :)
SELECT T.data,
rn = ROW_NUMBER() OVER (ORDER BY T.data)
FROM dbo.Test T
JOIN RecursiveCTE R
ON R.data < T.data
) R
WHERE R.rn = 1
)
SELECT *
FROM RecursiveCTE
OPTION (MAXRECURSION 0);