博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
无索引的亿级数据该如何删除?
阅读量:1906 次
发布时间:2019-04-26

本文共 4427 字,大约阅读时间需要 14 分钟。

点击蓝色“程序猿DD”关注我哟

加个“星标”,不忘签到哦

640?wx_fmt=jpeg

来源:yangyidba


关注我,回复口令获取可获取独家整理的学习资料:

001领取《Spring Boot基础教程》

002领取《Spring Cloud基础教程》

- 003:领取《Java开发规范1.5》最新版)

一、业务需求

某业务表a 数据量大约4.7亿,单表物理大小为370G,其中某些指定xxid='xxx'值的记录大约2亿。受限于磁盘空间比较紧张,需要对在无索引的情况下删除无效数据。如何优雅的删除呢?

二、思路

2.1 xxid本身有索引

存在索引的情况下就比较简单,直接利用索引进行删除,写一个for 循环语句 每次删除500行,每次判断delete 影响的行数可以累加计算删除了多少行,直到删除结果为0行。

delete from a where xxid='xxx' limit 500 ;

那么问题来了 ,如果要求不能创建索引怎么处理?

2.2 xxid 字段无索引

因为表占用的空间已经比较大 370G ,再添加索引会更大。因为没有索引,故我们不能直接像方法一 那样 根据 where xxxid='xxx' 删除数据,那样更慢,可能会引发故障。

我们采取分而治之的方式,基于主键把表的数据分段,比如每段1000行-2000行(如果主键id不连续 则实际数据量会小于指定分段数据)。然后在这1000行里面删除指定的数据,这样delete的执行效率会比直接依赖 xxxid='xxx' 好很多。

1 select min(a.id) min_id,max(a.id) max_id	from (select id from a where id>{init_id} order by id limit 1000) a	2 delete from a where xxid='xxx' and id >=min_id and id <=max_id	3 init_id = max_id

代码如下:

def get_current_max_id():	    """	    获取当前最大的id	    :return:	    """	    get_max_id = """select max(a.id) max_id from a"""	    try:	        mydb = pymysql.connect(	                    host=IP,	                    port=int(PORT),	                    user=USER,	                    read_timeout=5, write_timeout=5,	                    charset='utf8',  autocommit=True)	        cursor = mydb.cursor(pymysql.cursors.DictCursor)	        cursor.execute(get_max_id)	        data = cursor.fetchall()	    except Exception as e:	        print traceback.format_exc(e)	        exit(0)	    finally:	        mydb.close()	    print "we get max id of table : %s" % (data[0]['max_id'])	    return data[0]['max_id']	def get_min_max_id(min_id):	    """	    :param min_id:	    :return:	    """	    get_ids = """select min(a.id) min_id,max(a.id) max_id from	                 (select id from a where id>{init_id} order by id limit 2000) a	""".format(init_id=min_id)	    try:	        mydb = pymysql.connect(	                    host=IP,	                    port=int(PORT),	                    user=USER,	                    read_timeout=5, write_timeout=5,	                    charset='utf8', database='test', autocommit=True)	        cursor = mydb.cursor(pymysql.cursors.DictCursor)	        cursor.execute(get_ids)	        data = cursor.fetchall()	    except Exception as e:	        print traceback.format_exc(e)	        exit(0)	    finally:	        mydb.close()	    return data[0]['min_id'], data[0]['max_id']	def del_tokens(min_id, max_id):	    """	    :param min_id:	    :param max_id:	    :return:	    """	    del_token = """delete from a	                   where client_id in ('xxx','yyy') and id>=%s and id<=%s """	    try:	        mydb = pymysql.connect(	                    host=IP,	                    port=int(PORT),	                    user=USER,	                    read_timeout=5, write_timeout=5,	                    charset='utf8', database='test', autocommit=True)	        cursor = mydb.cursor(pymysql.cursors.DictCursor)	        rows = cursor.execute(del_token, (min_id, max_id))	    except Exception as e:	        print traceback.format_exc(e)	        exit(0)	    finally:	        mydb.close()	    return rows	def get_last_del_id(file_name):	    if not os.path.exists(file_name):	        print "{file} is not exist ,exit .".format(file=file_name)	        exit(-1)	    with open(file_name, 'r') as fh:	        del_id = fh.readline().strip()	    if not del_id.isdigit():	        print "it is '{delid}', not a num , exit ".format(delid=del_id)	        exit(-1)	    return del_id	def main():	    file_name = '/tmp/del_aid.id'	    rows_deleted = 0	    maxid = get_current_max_id()	    init_id = get_last_del_id(file_name)	    while True:	        min_id, max_id = get_min_max_id(init_id)	        if max_id > maxid:	            with open('/tmp/del_aid.id', 'w') as f:	                f.write(str(min_id))	            print "delete end at : {end_id}".format(end_id=init_id)	            exit(0)	        rows = del_tokens(int(min_id), int(max_id))	        init_id = max_id	        rows_deleted += rows	        print "delete at  %d ,and we have  deleted %d  rows " % (max_id, rows_deleted)	        time.sleep(0.3)  ### 可以控制每秒删除的速度	if __name__ == '__main__':	    main()

这个脚本可以记录上一次的id,用上一次id 作为 init_id进行删除。第一次使用的时候需要手工初始化/tmp/del_aid.id 比如写入 0 或者符合条件的最小主键 id。

2.3 如何更快速的删除

这个环节就当做思考题吧,可以不考虑从库的延迟。大家有什么好的思路,可以分享一下。

推荐关注

本文作者的个人公众号,长期关注于数据库技术以及性能优化,故障案例分析,数据库运维技术知识分享,个人成长和自我管理等主题,欢迎扫码关注。

640?wx_fmt=png


推荐阅读


活动介绍

活动奖励:

  • 一等奖:天猫精灵 * 1

  • 二等奖:我的星球会员 * 5

扫描下面二维码签到参与

640?wx_fmt=png

关注我,加个星标,不忘签到哦~

2019

与大家聊聊技术人的斜杠生活

640?wx_fmt=png

点一点“阅读原文”小惊喜在等你

转载地址:http://opvcf.baihongyu.com/

你可能感兴趣的文章
maven 多层次pom 新引入包,编译成功,还是没有将包引入到本地
查看>>
leetCode2 两数相加
查看>>
【工具使用】使用pip与conda安装、更新与卸载Pytorch和torchvision
查看>>
【深度学习笔记】batchsize, time step(iteration), epoch 区别与联系
查看>>
【解决错误】ModuleNotFoundError No module named matplotlib
查看>>
【工具使用】Google免费云环境Colaboratory使用
查看>>
【深度学习笔记】卷积层,全连接层,池化层的相关输出参数计算
查看>>
【NLP学习笔记】文本分类概述
查看>>
【深度学习笔记】文本分类
查看>>
【转载】炼丹实验室:深度学习网络调参技巧
查看>>
【论文阅读笔记】Graph Convolutional Networks for Text Classification
查看>>
【论文阅读笔记】文本分类论文汇总
查看>>
【论文阅读笔记】Convolutional Neural Networks for Sentence Classification
查看>>
【NLP学习笔记】One-hot encoding:独热编码
查看>>
【工具使用】CSDN编辑器markdown字体、颜色与字号的设置
查看>>
【NLP学习笔记】词共现矩阵
查看>>
【NLP学习笔记】NLP基础知识框架图
查看>>
【深度学习笔记】卷积的输入输出的通道、维度或尺寸变化过程
查看>>
【NLP学习笔记】训练集、验证集和测试集的概念及划分
查看>>
【NLP学习笔记】conda换源
查看>>