mysql千万级数据怎么删除,MySQL 快速删除大量数据(千万级别)的几种实践方案详解...
这篇文章主要介绍了MySQL 快速删除大量数据(千万级别)的几种实践方案详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
笔者最近工作中遇见一个性能瓶颈问题,MySQL表,每天大概新增776万条记录,存储周期为7天,超过7天的数据需要在新增记录前老化。连续运行9天以后,删除一天的数据大概需要3个半小时(环境:128G, 32核,4T硬盘),而这是不能接受的。当然如果要整个表删除,毋庸置疑用
TRUNCATE TABLE就好。
最初的方案(因为未预料到删除会如此慢),代码如下(最简单和朴素的方法):
delete from table_name where cnt_date <= target_date
后经过研究,最终实现了飞一般(1秒左右)的速度删除770多万条数据,单张表总数据量在4600万上下,优化过程的方案层层递进,详细记录如下:
批量删除(每次限定一定数量),然后循环删除直到全部数据删除完毕;同时key_buffer_size 由默认的8M提高到512M
运行效果:删除时间大概从3个半小时提高到了3小时
(1)通过limit(具体size 请酌情设置)限制一次删除的数据量,然后判断数据是否删除完,附源码如下(Python实现):
def delete_expired_data(mysqlconn, day):
mysqlcur = mysqlconn.cursor()
delete_sql = "DELETE from table_name where cnt_date<='%s' limit 50000" % day
query_sql = "select srcip from table_name where cnt_date <= '%s' limit 1" % day
try:
df = pd.read_sql(query_sql, mysqlconn)
while True:
if df is None or df.empty:
break
mysqlcur.execute(delete_sql)
mysqlconn.commit()
df = pd.read_sql(query_sql, mysqlconn)
except:
mysqlconn.rollback()
(2)增加key_buffer_size
mysqlcur.execute("SET GLOBAL key_buffer_size = 536870912")
DELETE QUICK + OPTIMIZETABLE
适用场景:MyISAM Tables
Why: MyISAM删除的数据维护在一个链表中,这些空间和行的位置接下来会被Insert的数据复用。 直接的delete后,mysql会合并索引块,涉及大量内存的拷贝移动;而OPTIMIZE TABLE直接重建索引,即直接把数据块情况,再重新搞一份(联想JVM垃圾回收算法)。
运行效果:删除时间大3个半小时提高到了1小时40分
具体代码如下:
def delete_expired_data(mysqlconn, day):
mysqlcur = mysqlconn.cursor()
delete_sql = "DELETE QUICK from table_name where cnt_date<='%s' limit 50000" % day
query_sql = "select srcip from table_name where cnt_date <= '%s' limit 1" % day
optimize_sql = "OPTIMIZE TABLE g_visit_relation_asset"
try:
df = pd.read_sql(query_sql, mysqlconn)
while True:
if df is None or df.empty:
break
mysqlcur.execute(delete_sql)
mysqlconn.commit()
df = pd.read_sql(query_sql, mysqlconn)
mysqlcur.execute(optimize_sql)
mysqlconn.commit()
except:
mysqlconn.rollback()
表分区,直接删除过期日期所在的分区(最终方案—秒杀)
MySQL表分区有几种方式,包括RANGE、KEY、LIST、HASH,具体参见官方文档。因为这里的应用场景日期在变化,所以不适合用RANGE设置固定的分区名称,HASH分区更符合此处场景
(1)分区表定义,SQL语句如下:
ALTER TABLE table_name PARTITION BY HASH(TO_DAYS(cnt_date)) PARTITIONS 7;
TO_DAYS将日期(必须为日期类型,否则会报错:Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed)转换为天数(年月日总共的天数),然后HASH;建立7个分区。实际上,就是 days MOD 7。
(2)查询出需要老化的日期所在的分区,SQL语句如下:
"explain partitions select * from g_visit_relation_asset where cnt_date = '%s'" % expired_day
执行结果如下(partitions列即为所在分区):
+----+-------------+------------------+------------+------+----------------+------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+------+----------------+------+---------+------+---------+----------+-------------+
| 1 | SIMPLE | table_name | p1 | ALL | cnt_date_index | NULL | NULL | NULL | 1325238 | 100.00 | Using where |
+----+-------------+------------------+------------+------+----------------+------+---------+------+---------+----------+-------------+
1 row in set, 2 warnings (0.00 sec)
(3)OPTIMIZE or REBUILD partition,SQL语句如下:
"ALTER TABLE g_visit_relation_asset OPTIMIZE PARTITION '%s'" % partition
完整代码如下【Python实现】,循环删除小于指定日期的数据:
def clear_partition_data(mysqlconn, day):
mysqlcur = mysqlconn.cursor()
expired_day = day
query_partition_sql = "explain partitions select * from table_name where cnt_date = '%s'" % expired_day
# OPTIMIZE or REBUILD after truncate partition
try:
while True:
df = pd.read_sql(query_partition_sql, mysqlconn)
if df is None or df.empty:
break
partition = df.loc[0, 'partitions']
if partition is not None:
clear_partition_sql = "alter table table_name TRUNCATE PARTITION %s" % partition
mysqlcur.execute(clear_partition_sql)
mysqlconn.commit()
optimize_partition_sql = "ALTER TABLE table_name OPTIMIZE PARTITION %s" % partition
mysqlcur.execute(optimize_partition_sql)
mysqlconn.commit()
expired_day = (expired_day - timedelta(days = 1)).strftime("%Y-%m-%d")
df = pd.read_sql(query_partition_sql, mysqlconn)
except:
mysqlconn.rollback()
其它
如果删除的数据超过表数据的百分之50,建议拷贝所需数据到临时表,然后删除原表,再重命名临时表为原表,附MySQL如下:
INSERT INTO New
SELECT * FROM Main
WHERE ...; -- just the rows you want to keep
RENAME TABLE main TO Old, New TO Main;
DROP TABLE Old; -- Space freed up here
可通过: ALTER TABLE table_name REMOVE PARTITIONING 删除分区,而不会删除相应的数据
参考:
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
************************************************************************
精力有限,想法太多,专注做好一件事就行
我只是一个程序猿。5年内把代码写好,技术博客字字推敲,坚持零拷贝和原创写博客的意义在于打磨文笔,训练逻辑条理性,加深对知识的系统性理解;如果恰好又对别人有点帮助,那真是一件令人开心的事
相关文章
mysql千万级数据怎么删除,MySQL 快速删除大量数据(千万级别)的几种实践方案详解...相关推荐
- 高并发架构系列:Redis缓存和MySQL数据一致性方案详解
需求起因 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库. 这个业务场景,主要 ...
- MySql索引查询优化 千万级数据普通查询和建立索引后数据查询耗时对比
前言 索引:拿汉语字典的目录页(索引)打比方,我们可以按拼音.笔画.偏旁部首等排序的目录(索引)快速查找到需要的字. 索引分单列索引和组合索引. 单列索引,即一个索引只包含单个列,一个表可以有多个单列 ...
- 分布式缓存redis 方案_Redis缓存和MySQL数据一致性方案详解
在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到Redis,而不是直接访问MySQL等数据库. 这个业务场景,主要是解决读数 ...
- redis一般缓存什么样数据_Redis缓存和MySQL数据一致性方案详解
关注我,可以获取最新知识.经典面试题以及技术分享 一.需求起因 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis, ...
- Mysql 优化器内部JOIN算法hash join On-Disk Hash Join Grace Hash Join Hybrid hash join过程详解
Mysql 各种hash join算法讲解 hash join的概述 提到hash join之前自然得说Nest loop join,以两个表的关联为例,它其实是个双层循环,先遍历外层的表(n条),再 ...
- Redis系列教程(六):Redis缓存和MySQL数据一致性方案详解
需求起因 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库. 这个业务场景,主要 ...
- 高并发用redis还是mysql_高并发架构系列:Redis缓存和MySQL数据一致性方案详解
需求起因 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库. 这个业务场景,主要 ...
- 二、MySQL连接查询学习笔记(多表连接查询:内连接,外连接,交叉连接详解)
MySQL连接查询(多表连接查询:内连接,外连接,交叉连接详解) 6:多表连接查询 笛卡尔乘积:如果连接条件省略或无效则会出现 解决办法:添加上连接条件 连接查询的分类: 1.按年代分类:1)sql ...
- mysql小计_Mysql必读用SQL实现统计报表中的小计与合计的方法详解
<Mysql必读用SQL实现统计报表中的"小计"与"合计"的方法详解>要点: 本文介绍了Mysql必读用SQL实现统计报表中的"小计&qu ...
最新文章
- python3 异步 semaphore 信号量 控制并发
- Normal Bayes 分类器过程详解
- 动态半导体ram依据什么存储信息_LPDDR4X和RAM两者有什么关系 它们有什么特点
- mysql 至少有2个年龄大于40岁,在MySQL中计算年龄时出错?
- python技巧 使用值来排序一个字典
- 【转】4.2SharePoint服务器端对象模型 之 使用CAML进行数据查询(Part 2)
- Java基础10(反射)
- seo日常工作表_seo工作者的日常和苦与甜
- Jersey +jetty 实现微服务(一)
- Chrome谷歌浏览器 强制跳转https解决方案
- AsnycTask的内部的实现机制
- jquery 添加可操作,编辑不可操作
- 用python排序算法_用Python实现常见的排序算法
- 让自己的网站可以被搜索
- 单独得省级行政区数据
- 5G+工业互联网行业解决方案
- 全球货币市场基础知识系列4
- python实现网页微信登录_django 微信网页授权登陆的实现
- Mac音频录制软件哪个好 怎么录制屏幕声音
- php实现报表拖拉拽,看!这款BI工具用拖拉拽的方式做报表
热门文章
- kotlin 尾递归阶乘_Kotlin程序查找数字的阶乘
- kaili更新国内源,“没有数字签名”错误
- java毕业设计西安财经大学校园一卡通管理系统源码+lw文档+mybatis+系统+mysql数据库+调试
- 题目9:要求输出国际象棋棋盘
- R语言入门教学(3)-不懂就问help()的使用及package的安装
- CA证书(数字证书原理)
- 第一章、安装、登录CentOS7
- 2019年京东无货源店群运营思路,新手怎么才能快速月入过万
- python数字推盘游戏怎么显示步数_用 Python 实现手机自动答题,这下百万答题游戏谁也玩不过我!...
- 视频转动图、图片压缩网站