重复数据删重技术

重复数据通常由于不恰当的数据完整性约束所导致,删重可以采用多种方法,而每种方法的效率取决于几个因素。一个是唯一行的重复数量(密度),另一个是整行都重复,还是只有一部分属性重复。

以mio_log_tmp表为例,删重代码如下:

--删除重复数据

UPDATE  mio_log_tmp
SET     incr_flag= 'z'
WHERE   upd_time<( SELECT MAX(upd_time)
                     FROM   mio_log_tmp a
                     WHERE  1 = 1
                        AND a.MIO_LOG_ID= mio_log_tmp.MIO_LOG_ID
                   ) 
go 
UPDATE  mio_log_tmp
SET     incr_flag= 'z'
WHERE   mirror_id<( SELECT    MAX(mirror_id)
                      FROM      mio_log_tmpa
                      WHERE     1 = 1
                         AND a.MIO_LOG_ID= mio_log_tmp.MIO_LOG_ID
                                AND a.incr_flag<> 'z'
                    )
        AND incr_flag<> 'z' 
DELETE  FROM mio_log_tmp
WHERE   incr_flag= 'z'
此方法在增量数据量较小的情况下问题不会很大,但是 并不适合于在大数据量表删重操作,当mio_log_tmp数据量为83000(虚拟构造的数据),运行时间大概为5秒。

  

处理整行重复且重复密度较高时的方法,可以采用SELECTDISTINCT …… INTO语句把不重复行复制到新表,删除原表,将新表重命名为源表名称,创建所有约束、索引和触发器。

SELECT DISTINCT* INTO mio_log_tmp_Dups FROM mio_log_tmp;
DROP TABLE mio_log_tmp;
EXEC sp_rename mio_log_tmp_Dups,mio_log_tmp
--添加约束、索引和触发器。

运行时间3秒。

下面的方法要求表中有唯一标识符。如果表中没有唯一标识符,需要添加一个标识列。如果已经存在可以被重写的数值列,可以使用以下的任意一种方法为已经存在的列分配序列值。重写已有数值列的过程相当快,因为不用重新构造和扩展行。要实现快速地移除重复,需要在重复的属性和唯一标识符(称之为KeyCol)上创建索引,运行一下代码: 

 

为mio_log_tmp_Dups表增加标识列并创建所需的索引:

ALTER TABLE mio_log_tmp ADD KeyCol INT NOT NULL IDENTITY;
CREATE UNIQUE INDEX inx_mio_log_id_KeyCol ON mio_log_tmp(mio_log_id,KeyCol);
GO 

使用以下DELETE语句删除重复数据: 

DELETE FROM mio_log_tmp
WHERE EXISTS
(SELECT *
    FROM mio_log_tmp AS O2
WHERE O2. mio_log_id =mio_log_tmp. mio_log_id
AND O2.KeyCol> mio_log_tmp.KeyCol)
整个方法运行时间为3秒,包括增加标识列和创建索引的时间。

比较前面的DISTINCT方法,该方法只需依赖于决定重复属性和代理键(KeyCol)。即使重复行的其他属性不相等也可以使用该方法。但是,当重复的密度较大时,这种方法显得非常慢。要优化在高密度场景下该解决方案的性能,改进如下:可以为每个mio_log_id保留具有最大KeyCol值的行。使用SELECTINTO语句将这些唯一行插入新表,然后删除源表,将新表重命名为源表名称,创建所有约束、索引和触发器。

以下代码使用这种方法,共运行了3秒。

ALTER TABLE mio_log_tmp ADD KeyColINT NOT NULL IDENTITY ;
CREATE UNIQUE INDEX inx_mio_log_id_KeyCol ON mio_log_tmp(mio_log_id,KeyCol) ;
GO
 
SELECT  O.mio_log_id, *
INTO    mio_log_tmp1
FROM    mio_log_tmpAS O
        JOIN( SELECT   mio_log_id ,
                        MAX(KeyCol)AS mx
               FROM     mio_log_tmp
               GROUP BY mio_log_id
             ) ASU ON O.mio_log_id= O.mio_log_id
                       AND O.KeyCol = U.mx;
                      
DROP TABLE mio_log_tmp ;
EXEC sp_rename'mio_log_tmp1','mio_log_tmp'
--添加约束、索引和触发器。

以上方法总结:

DISTINCT方法要求整行完全重复,另两种方法要求表中有唯一标识符,在SQL Server 2005中可以使用CTE(公用表表达式)和ROW_NUMBER函数实现一种快速的解决方案,而且没有上述限制:

WITH Dups AS
(
SELECT* , ROW_NUMBER()OVER(PARTITION BY mio_log_id ORDERBY mio_log_id)AS rn
FROM mio_log_tmp
)
delete from Dups where rn> 1 

该方案运行时间为0秒!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值