MySQL单表千万级数据处理的思路分享


Posted in MySQL onJune 05, 2021

项目背景

在处理过程中,今天上午需要更新A字段,下午爬虫组完成了规格书或图片的爬取又需要更新图片和规格书字段,由于单表千万级深度翻页会导致处理速度越来越慢。

select a,b,c from db.tb limit 10000 offset 9000000

但是时间是有限的,是否有更好的方法去解决这种问题呢?

改进思路

是否有可以不需要深度翻页也可以进行数据更新的凭据?
是的,利用自增id列

观察数据特征

此单表有自增id列且为主键,根据索引列查询数据和更新数据是最理想的途径。

select a,b, c from db.tb where id=9999999;
update db.tb set a=x where id=9999999;

多进程处理

每个进程处理一定id范围内的数据,这样既避免的深度翻页又可以同时多进程处理数据。
提高数据查询速度的同时也提高了数据处理速度。
下面是我编写的任务分配函数,供参考:

def mission_handler(all_missions, worker_mission_size):
    """
    根据总任务数和每个worker的任务数计算出任务列表, 任务列表元素为(任务开始id, 任务结束id)。
    例: 总任务数100个,每个worker的任务数40, 那么任务列表为:[(1, 40), (41, 80), (81, 100)]
    :param all_missions: 总任务数
    :param worker_mission_size: 每个worker的最大任务数
    :return: [(start_id, end_id), (start_id, end_id), ...]
    """
    worker_mission_ids = []
    current_id = 0
    while current_id <= all_missions:
        start_id = all_missions if current_id + 1 >= all_missions else current_id + 1
        end_id = all_missions if current_id + worker_mission_size >= all_missions else current_id + worker_mission_size
        if start_id == end_id:
            if worker_mission_ids[-1][1] == start_id:
                break
        worker_mission_ids.append((start_id, end_id))
        current_id += worker_mission_size

    return worker_mission_ids

假设单表id最大值为100, 然后我们希望每个进程处理20个id,那么任务列表将为:

>>> mission_handler(100, 40)
[(1, 40), (41, 80), (81, 100)]

那么,
进程1将只需要处理id between 1 to 40的数据;
进程2将只需要处理id between 41 to 80的数据;
进程3将只需要处理id between 81 to 100的数据。

from concurrent.futures import ProcessPoolExecutor


def main():
    # 自增id最大值
    max_id = 30000000
    # 单worker处理数据量
    worker_mission_size = 1000000
    # 使用多进程进行处理
    missions = mission_handler(max_id, worker_mission_size)
    workers = []
    executor = ProcessPoolExecutor()
    for idx, mission in enumerate(missions):
        start_id, end_id = mission
        workers.append(executor.submit(data_handler, start_id, end_id, idx))


def data_handler(start_id, end_id, worker_id):
    pass

思路总结

  1. 避免深度翻页进而使用自增id进行查询数据和数据
  2. 使用多进程处理数据

数据处理技巧

记录处理成功与处理失败的数据id,以便后续跟进处理

# 用另外一张表记录处理状态
insert into db.tb_handle_status(row_id, success) values (999, 0);

循环体内进行异常捕获,避免程序异常退出

def data_handler(start_id, end_id, worker_id):
    # 数据连接
    conn, cursor = mysql()
    current_id = start_id
        try:
            while current_id <= end_id:
                try:
                    # TODO 数据处理代码
                    pass

                except Exception as e:
                    # TODO 记录处理结果
                    # 数据移动到下一条
                    current_id += 1
                    continue
                else:
                    # 无异常,继续处理下一条数据
                    current_id += 1
        except Exception as e:
            return 'worker_id({}): result({})'.format(worker_id, False)
        finally:
            # 数据库资源释放
            cursor.close()
            conn.close()

        return 'worker_id({}): result({})'.format(worker_id, True)

更新数据库数据尽量使用批量提交

sql = """update db.tb set a=%s, b=%s where id=%s"""
values = [
            ('a_value', 'b_value', 9999),
            ('a_value', 'b_value', 9998),
            ...
         ]
# 批量提交,减少网络io以及锁获取频率
cursor.executemany(sql, values)

以上就是MySQL单表千万级数据处理的思路分享的详细内容,更多关于MySQL单表千万级数据处理的资料请关注三水点靠木其它相关文章!

MySQL 相关文章推荐
MySQL入门命令之函数-单行函数-流程控制函数
Apr 05 MySQL
正确使用MySQL update语句
May 26 MySQL
MySQL完整性约束的定义与实例教程
May 30 MySQL
mysql中between的边界,范围说明
Jun 08 MySQL
MySQL 那些常见的错误设计规范,你都知道吗
Jul 16 MySQL
SQL实现LeetCode(176.第二高薪水)
Aug 04 MySQL
MySQL千万级数据表的优化实战记录
Aug 04 MySQL
SQL注入详解及防范方法
Dec 06 MySQL
MySQL磁盘碎片整理实例演示
Apr 03 MySQL
MySQL创建管理RANGE分区
Apr 13 MySQL
MySQL查询日期时间
May 15 MySQL
关于MySQL中explain工具的使用
May 08 MySQL
MySQL 时间类型的选择
Jun 05 #MySQL
MySQL索引失效的典型案例
Jun 05 #MySQL
MySQL库表名大小写的选择
Jun 05 #MySQL
mysql 带多个条件的查询方式
Mysql 如何实现多张无关联表查询数据并分页
Jun 05 #MySQL
Mysql中存储引擎的区别及比较
浅谈mysql返回Boolean类型的几种情况
Jun 04 #MySQL
You might like
thinkphp3.2.2实现生成多张缩略图的方法
2014/12/19 PHP
[原创]php使用curl判断网页404(不存在)的方法
2016/06/23 PHP
jquery load()在firefox(火狐)下显示不正常的解决方法
2011/04/05 Javascript
7款风格新颖的jQuery/CSS3菜单导航分享
2013/04/23 Javascript
javascript实现可改变滚动方向的无缝滚动实例
2013/06/17 Javascript
jquery $(&quot;#variable&quot;) 循环改变variable的值示例
2014/02/23 Javascript
JavaScript中九种常用排序算法
2014/09/02 Javascript
AngularJS初始化过程分析(引导程序)
2014/12/06 Javascript
浅谈JavaScript数据类型及转换
2015/02/28 Javascript
jQuery中animate用法实例分析
2015/03/09 Javascript
利用jQuery实现CheckBox全选/全不选/反选的简单代码
2016/05/31 Javascript
微信小程序 wx.login解密出现乱码的问题解决办法
2017/03/10 Javascript
node.js平台下利用cookie实现记住密码登陆(Express+Ejs+Mysql)
2017/04/26 Javascript
最通俗易懂的javascript变量提升详解
2017/08/05 Javascript
bootstrap-table实现服务器分页的示例 (spring 后台)
2017/09/01 Javascript
Vue实现底部侧边工具栏的实例代码
2018/09/03 Javascript
jQuery实现获取及设置CSS样式操作详解
2018/09/05 jQuery
重学JS 系列:聊聊继承(推荐)
2019/04/11 Javascript
微信小程序开发之点击按钮退出小程序的实现方法
2019/04/26 Javascript
一文读懂ES7中的javascript修饰器
2019/05/06 Javascript
前端使用crypto.js进行加密的函数代码
2020/08/16 Javascript
python中pass语句用法实例分析
2015/04/30 Python
Python使用bs4获取58同城城市分类的方法
2015/07/08 Python
python if not in 多条件判断代码
2016/09/21 Python
Python 支付整合开发包的实现
2019/01/23 Python
利用python实现PSO算法优化二元函数
2019/11/13 Python
Python完全识别验证码自动登录实例详解
2019/11/24 Python
jupyternotebook 撤销删除的操作方式
2020/04/17 Python
给老婆的婚前保证书
2014/02/01 职场文书
党支部换届选举方案
2014/05/08 职场文书
护理专业求职信
2014/06/15 职场文书
党的群众路线教育实践活动个人整改措施
2014/10/27 职场文书
公司客户答谢酒会祝酒词
2015/08/11 职场文书
《学会生存》读后感3篇
2019/12/09 职场文书
一文带你探究MySQL中的NULL
2021/11/11 MySQL
MongoDB数据库部署环境准备及使用介绍
2022/03/21 MongoDB