锁定老帖子 主题:关于删除数据库中百万级数据的解决方案
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-12-15
问题描述:在我们数据中由于是根据当时的情况对客户表和客户分类表新增一个中间,又因为是中期新增,所以中间表的建表结构是将客户表的ID和客户分组表的ID分别写入到中间表里面,这样中间表就有三个字段主键客户表ID客户分组表ID,当时由于数据量大处理不过来所以没有建立级联,在客户表里面有许多导入数据的功能,也有删除数据的功能由于删除和导入操作频繁没有管理中间表的空间,致使中间表荣升到数据库第一大表快超过1达到1千万数据,苦于找方法瘦身,就找到了中间表的内容,删除当时删除客户资料没有删除中间表数据的内容:就有了以下的解决方案: 利用sql语句删除:delete from m_customer_category where customer_sid_fk not in(select customer_sid from customer); 由于customer表中的数据是680W,m_customer_category表数据是890w,上面的一条语句在服务器上执行了 3个小时后没有任何反应state状态是end一直是这样的情况,所以放弃没有进行删除。 第二次删除数据又想想利用存储过程删除也想就会快点所以就找相关的资料写存储过程,如下: create procedure del() begin declare coun1 int; select count(*) into coun1 from m_customer_category where customer_sid_fk not in(select customer_sid from customer); while coun1 > 0 do delete from m_customer_category where customer_sid_fk not in(select customer_sid from customer) limit 10000; commit; set coun1=coun1-10000; end while;
end 因为在本机上数据比服务器上的数据少了很多,在本机上可以正常执行就是没什么输出,数据也删除,本以为可以执行,可是在第二次晚上更新的时候还是如上的情况还是没有反应,在执行过2个小时后我又放弃了。 查找原因可能是数据量大并且建立有所以,所以造成批量删除并没什么效果,再次思考能不能做单个删除,也就是说找到一条记录的ID后在根据Id删除数据,在利用存储过程在循环中删除数据应该就没有问题了,所以做了如下修改: 我将符合条件的数据的id都查找出来放到一张自己新建立的临时表里面如下语句: insert into m_customer_category_back (select id from m_customer_category where customer_sid_fk not in(select customer_sid from customer)); 表中是建立索引的所以执行查询的时候是不会很慢的,我是看中他的查询条件才这样操作的,数据很快20多分钟就执行完了130+W数据,这下好了,修改下存储过程就可以实现单条删除数据了,根据这些条件即时不关闭数据的情况也可以正常的删除数据存储过程如下: begin declare coun1 int; declare count2 int; select count(*) into coun1 from m_customer_category_back limit 300000; while coun1 > 0 do select id into count2 from m_customer_category_back LIMIT 1; delete from m_customer_category where id = count2; delete from m_customer_category_back where id=count2; SELECT '删除一条'+count2; commit; set coun1=coun1-1; end while;
end 由于害怕服务器长时间造成占用时间过程所以在查询的时候做了小小的修改也就是说我调用一次这个存储过程的时候只删除30w数据。基本告一段落如果有数据偶尔执行一下就好了有输出,删除数据不是很快但也很有效果,也不影响业务的正常使用。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-12-23
楼主
你这是基本的SQL问题 换成如下语句试试: delete from m_customer_category where not exists(select 1 from customer where m_customer_category.customer_sid_fk=customer_sid) 如果需要花费的时间还是很长,你可以将m_customer_category中的数据分成10次来执行。 如:delete from m_customer_category where ID>=1000000 and ID <200000 not exists(select 1 from customer where m_customer_category.customer_sid_fk=customer_sid) 这样基本可以解决你的问题。 |
|
返回顶楼 | |
发表时间:2010-12-24
一般備份后 truncate 的路過。。
|
|
返回顶楼 | |
发表时间:2010-12-24
如果删一条提交一条,会加重数据库很大的负担的!这是基本的知识。至少你应该在100-200之间去提交一次。
|
|
返回顶楼 | |
发表时间:2010-12-24
xiaoshan5634 写道 楼主
你这是基本的SQL问题 换成如下语句试试: delete from m_customer_category where not exists(select 1 from customer where m_customer_category.customer_sid_fk=customer_sid) 如果需要花费的时间还是很长,你可以将m_customer_category中的数据分成10次来执行。 如:delete from m_customer_category where ID>=1000000 and ID <200000 not exists(select 1 from customer where m_customer_category.customer_sid_fk=customer_sid) 这样基本可以解决你的问题。 这个是正解 in 是不走索引的,所以非常慢 |
|
返回顶楼 | |
发表时间:2010-12-25
in本来就不提倡的,lz居然还用not in
补补吧 |
|
返回顶楼 | |
发表时间:2010-12-25
最后修改:2010-12-25
oracle 可以这么写:
declare type id_tab is table of varchar2(20); customers id_tab; cursor c_delete is select id from m_customer_category where customer_sid_fk not in(select customer_sid from customer); begin open c_delete; loop fetch c_delete bulk collect into customers limit 10000; forall i in customers.first .. customers.last delete m_customer_category a where a.id = customers(i); commit; exit when customers.count() = 0; end loop; close c_delete; end; |
|
返回顶楼 | |
发表时间:2010-12-26
难道我眼花了... in 不走索引? 看执行计划是走的。
|
|
返回顶楼 | |
发表时间:2010-12-27
兄弟们呀,我现在还有个头大的问题,就是我们的customer已经860万了,而中间表m_customer_category 也有900多万了,如果按类型查找客户资料的话巨慢,如何解决呀,就是customer,m_customer_category,custoemr_category三张表多对多关系,怎么按类型快速查找呀
|
|
返回顶楼 | |
发表时间:2010-12-27
分批次交提交更快,一批1000条
|
|
返回顶楼 | |