帮忙优化 以下语句
目标:去除member_id和my_friend_id中非数字的所有记录
同时去除 交叉重复 以及 简单重复 的 重复值 保留max(id)该条记录。表 test_unionpk 结构如下
id int identity pk
member_id varchar(25) with index
my_friend_id varchar(25) with index
create_date datetime default getdate()
isactive bit default 0
聚集索引为 id,其余还有几个相互column之间的非聚集索引表的数据级别为 2千万+
SET NOCOUNT ON
declare @OperId int
, @OperFlag int
, @OperRows int
, @OperCurrent int
set @OperId=0
set @OperFlag=0
set @OperRows=10000
set @OperCurrent=9201230while @OperFlag=0
begin
--第一步 将表中全角数字转化为半角。
begin tran
update Test_UnionPK set
member_id=replace(replace(
replace(replace(
replace(replace(
replace(replace(
replace(replace(member_id,'0',0),'1',1)
,'2',2),'3',3)
,'4',4),'5',5)
,'6',6),'7',7)
,'8',8),'9',9)
,my_friend_id=replace(replace(
replace(replace(
replace(replace(
replace(replace(
replace(replace(My_friend_id,'0',0),'1',1)
,'2',2),'3',3)
,'4',4),'5',5)
,'6',6),'7',7)
,'8',8),'9',9)
where isnumeric(member_id)=0 and isnumeric(my_friend_id)=0 and id<@OperCurrent+@OperRows and id>@OperCurrent
if @@error>0 rollback tran-- 第二步 删除掉 表中member_id 或 my_friend_id中含非数字 的记录。delete Test_UnionPK where id in (
select id
from Test_UnionPK where isnumeric(member_id)=0 and id<@OperCurrent+@OperRows and id>@OperCurrent
union all
select id as member_id
from Test_UnionPK where isnumeric(my_friend_id)=0 and id<@OperCurrent+@OperRows and id>@OperCurrent
)
if @@error>0 rollback tran-- 第三步 删除掉 表中的重复记录,此重复记录包括 mid=Mid ,fid=Fid 以及 mid=Fid ,fid=Mid 这两种情况的重复。保证内部数据的唯一性。
delete Test_UnionPK where id<@OperCurrent+@OperRows and id>@OperCurrent and id not in(
select max(id) from Test_UnionPK b
where b.id<@OperCurrent+@OperRows and b.id>@OperCurrent
group by (
case when (convert(float,b.member_id)>convert(float,b.my_friend_id)
) then
b.my_Friend_id+b.member_id
else
b.member_id+b.my_Friend_id
end
)
)
If @@error>0 rollback tran
If @@RowCount=0
begin
if (select top 1 id from Test_UnionPK where id>@OperCurrent)>0 set @OperFlag=2
End
set @OperCurrent=@OperCurrent+@OperRows
end
commit tran
SET NOCOUNT Off
目标:去除member_id和my_friend_id中非数字的所有记录
同时去除 交叉重复 以及 简单重复 的 重复值 保留max(id)该条记录。表 test_unionpk 结构如下
id int identity pk
member_id varchar(25) with index
my_friend_id varchar(25) with index
create_date datetime default getdate()
isactive bit default 0
聚集索引为 id,其余还有几个相互column之间的非聚集索引表的数据级别为 2千万+
SET NOCOUNT ON
declare @OperId int
, @OperFlag int
, @OperRows int
, @OperCurrent int
set @OperId=0
set @OperFlag=0
set @OperRows=10000
set @OperCurrent=9201230while @OperFlag=0
begin
--第一步 将表中全角数字转化为半角。
begin tran
update Test_UnionPK set
member_id=replace(replace(
replace(replace(
replace(replace(
replace(replace(
replace(replace(member_id,'0',0),'1',1)
,'2',2),'3',3)
,'4',4),'5',5)
,'6',6),'7',7)
,'8',8),'9',9)
,my_friend_id=replace(replace(
replace(replace(
replace(replace(
replace(replace(
replace(replace(My_friend_id,'0',0),'1',1)
,'2',2),'3',3)
,'4',4),'5',5)
,'6',6),'7',7)
,'8',8),'9',9)
where isnumeric(member_id)=0 and isnumeric(my_friend_id)=0 and id<@OperCurrent+@OperRows and id>@OperCurrent
if @@error>0 rollback tran-- 第二步 删除掉 表中member_id 或 my_friend_id中含非数字 的记录。delete Test_UnionPK where id in (
select id
from Test_UnionPK where isnumeric(member_id)=0 and id<@OperCurrent+@OperRows and id>@OperCurrent
union all
select id as member_id
from Test_UnionPK where isnumeric(my_friend_id)=0 and id<@OperCurrent+@OperRows and id>@OperCurrent
)
if @@error>0 rollback tran-- 第三步 删除掉 表中的重复记录,此重复记录包括 mid=Mid ,fid=Fid 以及 mid=Fid ,fid=Mid 这两种情况的重复。保证内部数据的唯一性。
delete Test_UnionPK where id<@OperCurrent+@OperRows and id>@OperCurrent and id not in(
select max(id) from Test_UnionPK b
where b.id<@OperCurrent+@OperRows and b.id>@OperCurrent
group by (
case when (convert(float,b.member_id)>convert(float,b.my_friend_id)
) then
b.my_Friend_id+b.member_id
else
b.member_id+b.my_Friend_id
end
)
)
If @@error>0 rollback tran
If @@RowCount=0
begin
if (select top 1 id from Test_UnionPK where id>@OperCurrent)>0 set @OperFlag=2
End
set @OperCurrent=@OperCurrent+@OperRows
end
commit tran
SET NOCOUNT Off
解决方案 »
- 求教各位前辈:复制文本文件,系统提示:拒绝访问,这是为何啊?十万火急,在线等......
- 在执行存储过程中,如何获取其返回值?
- 请问大侠,myeclipse和sqlserver连接出现的问题
- 如何让web服务器能访问MS-SQL Server服务器?
- 安装sqlserver失败,请教
- 远程连接sql2000已启用1433,但连接速度超慢,急求原因和解决方法
- 关于数据库表的合理设计的讨论,请教
- 求SQL语句(夺标查询排序后结果列合并为行的问题)
- 如何把由compute by生成的汇总名称改为“合计”?马上给份!
- 问题:select * from servername.dbname.username.tablename
- 问题又来了呵呵,今天问了很多问题,谢谢大家哦
- 记录的行的顺序
http://topic.csdn.net/u/20080716/11/2317d040-48e7-42da-822e-040b4c55b46d.html
--第一步的where条件可以改为这样
where id <@OperCurrent+@OperRows and id>@OperCurrent and isnumeric(member_id)=0 and isnumeric(my_friend_id)=0--第二步删除完全可以写两个语句,效率更好一些,where条件中,还是把id的条件放在前面--第三步个人认为把not in 改为exists效率会高一些,没有测试过delete b
from Test_UnionPK b
where id <@OperCurrent+@OperRows and id>@OperCurrent and
exists (select 1 from Test_UnionPK
where id <@OperCurrent+@OperRows and id>@OperCurrent
and (convert(float,b.member_id)>convert(float,b.my_friend_id) and my_Friend_id+member_id = b.my_Friend_id+b.member_id and id > b.id
or convert(float,b.member_id)<=convert(float,b.my_friend_id) and member_id+my_Friend_id = b.member_id+b.my_Friend_id and id > b.id
)
)
delete Test_UnionPK where id<@OperCurrent+@OperRows and id>=@OperCurrent
and id not in
(
select max(id) from Test_UnionPK b
where b.id<@OperCurrent+@OperRows and b.id>=@OperCurrent
group by
(
case when
(
convert(float,b.member_id)>convert(float,b.my_friend_id)
)
then
b.my_Friend_id+b.member_id
else
b.member_id+b.my_Friend_id
end
)
)
select id
from Test_UnionPK where isnumeric(member_id)=0 and id <@OperCurrent+@OperRows and id>@OperCurrent
union all
select id as member_id
from Test_UnionPK where isnumeric(my_friend_id)=0 and id <@OperCurrent+@OperRows and id>@OperCurrent
) --建议写成下面这样。sql2005可能会找到更好的执行计划
delete Test_UnionPK
where id <@OperCurrent+@OperRows and id>@OperCurrent and (isnumeric(member_id)=0 or isnumeric(my_friend_id)=0)
delete Test_UnionPK where id in
(
select id
from Test_UnionPK where id<@OperCurrent+@OperRows and id>=@OperCurrent and isnumeric(member_id)=0
union all
select id
from Test_UnionPK where id<@OperCurrent+@OperRows and id>=@OperCurrent and isnumeric(my_friend_id)=0
)个人觉得 union all比 or 效率高很多。。特别是大数据的时候。。
补充 数据库是 2005 Standard Edition
不是 Enterprise Edition
虽然每一遍的效率都还可以,但加起来未必……这个也很难说,跟具体环境有关,保留意见先
up b
up c...唉,执行一半我的测试机器居然死机了。。还有大家有好的日志查看的软件么。。能用就好。。有点晕,为啥微软不提供个给大家用。。
如果只是100W:1之类的,建议使用临时表来处理。
首先在member_id和my_friend_id上建立索引,
然后将异常纪录剔除出来,单独处理.
这样避免多次扫描全表.
2.如果异常纪录比较多,
确定你数据库的版本,如果是2005以及以后的版本,建议先分区或者分组,
先将数据分开来处理.这样比较好一些.也就是建立已分区表来处理.
同时建立好索引.
/..//\\fd\\fsa\fadfsaf\sdfsf/s/fasf/\sda\fs\/df/\af\ds\af\f\//\\/\/\/\/\/\/\/\//\\/\/\/
\///\\\\/\\\\/\\\\////\\\\\////\\\/\/\/\/\//\///\\\\///\\///\\\/\/\/\/\/\/\\\////\\\\\/\/
/..//\\fd\\fsa\fadfsaf\sdfsf/s/fasf/\sda\fs\/df/\af\ds\af\f\//\\/\/\/\/\/\/\/\//\\/\/\/
-----=======----------========------=======---------========---------=====-----=====--------\///\\\\/\\\\/\\\\////\\\\\////\\\/\/\/\/\//\///\\\\///\\///\\\/\/\/\/\/\/\\\////\\\\\/\/
也就是说将一个表拆分成多个表,
每个表只存储几百万条纪录,然后在处理。
还有你那三段SQL中,
第二段和第三段貌似都有优化的空间.
看看前面的一些回复,
DELETE FROM test_unionpk
WHERE ISNUMERIC(Member_ID) = 0 OR ISNUMERIC(My_Friend_ID) = 0 OR MemberID = My_Friend_ID--删除Member_ID、My_Friend_ID重复的记录
DELETE a FROM(
SELECT id, MAX(id) OVER(PARTITION BY Member_ID, My_Friend_ID) AS 'mx' FROM test_unionpk
)Tmp a
WHERE id < mx
使用了两个表,设计如下CREATE TABLE [dbo].[test_unionpk](
[id] [int] IDENTITY(1,1) NOT NULL,
[member_id] [nchar](10) NULL,
[my_friend_id] [nchar](10) NULL,
[create_date] [smalldatetime] NOT NULL CONSTRAINT [DF_test_unionpk_create_date] DEFAULT (getdate()),
[isactive] [bit] NOT NULL CONSTRAINT [DF_test_unionpk_isactive] DEFAULT ((0)),
CONSTRAINT [PK_test_unionpk] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]CREATE TABLE [dbo].[test_unionpk2](
[id] [int] IDENTITY(1,1) NOT NULL,
[member_id] [int] NULL,
[my_friend_id] [int] NULL,
[create_date] [smalldatetime] NOT NULL CONSTRAINT [DF_test_unionpk_create_date2] DEFAULT (getdate()),
[isactive] [bit] NOT NULL CONSTRAINT [DF_test_unionpk_isactive2] DEFAULT ((0)),
CONSTRAINT [PK_test_unionpk2] PRIMARY KEY NONCLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]test_unionpk表中包含18490693行数据,其中有18490693行数据的member_id和my_friend_id都包含全角数字(极端情况),有一行数据包含字符'a'。
本次执行耗时250秒(数据库系统配置为:PC机。2G内存,CPU:E4500 2.2G)。SSIS包也很简单(不能贴图,只能口述):
一个数据源从test_unionpk读出所有数据,传到“数据转换”数据流转换元素中,将member_id,和my_friend_id转换为整数型。并且将错误数据重定向(这样,不能转换为整数类型的数据就不会包含在输出中,即删除了不是数字的数据)。然后将“数据转换”的输出输入到test_unionpk2中。
这样,就简单的完成了转换全角数字和去除不是数字的行的任务。这里运用了数据转换中能识别全角数字的功能。
最后去重时,可以建立member_id,my_friend_id的联合聚集索引。然后使用Group by来去重。这里就不说了。不知道这样是否能满足你的性能要求。
好了,下班了,不多说了。
当存在 重复 member_id,my_friend_id的时候是无法建立联合聚集索引的
这样就可以不用建立聚合索引.SQL Server 2005 数据转换服务中的模糊查找和模糊分组
http://msdn.microsoft.com/zh-cn/library/ms345128.aspx
不晓得在迁移过程中是否还有一些动作可作呢。
Fuzzy Grouping实在是太慢了,几万数据去重,其速度我都不能接受,别说几千万了。
或者我的用法不对,请指教。