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 29 MySQL
MySql存储过程之逻辑判断和条件控制
May 26 MySQL
MySQL中使用or、in与union all在查询命令下的效率对比
May 26 MySQL
一文读懂navicat for mysql基础知识
May 31 MySQL
Mysql数据库值的添加、修改、删除及清空操作实例
Jun 20 MySQL
MySql 缓存查询原理与缓存监控和索引监控介绍
Jul 02 MySQL
MySQL基础快速入门知识总结(附思维导图)
Sep 25 MySQL
MySQL中CURRENT_TIMESTAMP的使用方式
Nov 27 MySQL
MySQL优化及索引解析
Mar 17 MySQL
MySQL RC事务隔离的实现
Mar 31 MySQL
Windows下载并安装MySQL8.0.x 版本的完整教程
Apr 10 MySQL
MySQL安装失败的原因及解决步骤
Jun 14 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
php设计模式 Observer(观察者模式)
2011/06/26 PHP
仿dedecms下拉分页样式修改的thinkphp分页类实例
2014/10/30 PHP
php获得客户端浏览器名称及版本的方法(基于ECShop函数)
2015/12/23 PHP
Jquery ThickBox插件使用心得(不建议使用)
2010/09/08 Javascript
javascript 基础篇3 类,回调函数,内置对象,事件处理
2012/03/14 Javascript
关于jQuery对象数据缓存Cache原理以及jQuery.data详解
2013/04/07 Javascript
关于include标签导致js路径找不到的问题分析及解决
2013/07/09 Javascript
Javascript图片上传前的本地预览实例
2014/06/16 Javascript
jquery中的常用事件bind、hover、toggle等示例介绍
2014/07/21 Javascript
Javascript实现找不同色块的游戏
2017/07/17 Javascript
JavaScript设计模式之原型模式分析【ES5与ES6】
2018/07/26 Javascript
详解Ubuntu安装angular-cli遇到的坑
2018/09/08 Javascript
Vue自定义组件的四种方式示例详解
2020/02/28 Javascript
js实现双色球效果
2020/08/02 Javascript
[01:24:34]2014 DOTA2华西杯精英邀请赛5 24 DK VS LGD
2014/05/25 DOTA
[03:40]DOTA2英雄梦之声_第01期_炼金术士
2014/06/23 DOTA
python读取浮点数和读取文本文件示例
2014/05/06 Python
详解Python的Django框架中的templates设置
2015/05/11 Python
Python常用算法学习基础教程
2017/04/13 Python
分析Python读取文件时的路径问题
2018/02/11 Python
Python 实现选择排序的算法步骤
2018/04/22 Python
python中subprocess批量执行linux命令
2018/04/27 Python
nohup后台启动Python脚本,log不刷新的解决方法
2019/01/14 Python
Python-opencv实现红绿两色识别操作
2020/06/04 Python
python 基于opencv实现图像增强
2020/12/23 Python
中国茶叶、茶具一站式网上购物商城:醉品茶城
2018/07/03 全球购物
Ibood荷兰:互联网每日最佳在线优惠
2019/02/28 全球购物
Viking Direct爱尔兰:办公用品和家具
2019/11/21 全球购物
10条PHP编程习惯
2014/05/26 面试题
实习护理工作自我评价
2013/09/25 职场文书
外国人聘用意向书
2014/04/01 职场文书
煤矿安全生产月活动总结
2014/07/05 职场文书
先进事迹演讲稿
2014/09/01 职场文书
新闻简讯格式及范文
2015/07/22 职场文书
幼儿园园长六一致辞
2015/07/31 职场文书
Android移动应用开发指南之六种布局详解
2022/09/23 Java/Android