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之DML语言
Apr 05 MySQL
详细谈谈MYSQL中的COLLATE是什么
Jun 11 MySQL
MySQL系列之二 多实例配置
Jul 02 MySQL
通过shell脚本对mysql的增删改查及my.cnf的配置
Jul 07 MySQL
MySql子查询IN的执行和优化的实现
Aug 02 MySQL
SQL实现LeetCode(175.联合两表)
Aug 04 MySQL
为什么MySQL 删除表数据 磁盘空间还一直被占用
Oct 16 MySQL
深入讲解数据库中Decimal类型的使用以及实现方法
Feb 15 MySQL
mysql数据插入覆盖和时间戳的问题及解决
Mar 25 MySQL
MySQL sql模式设置引起的问题
May 15 MySQL
MySQL主从切换的超详细步骤
Jun 28 MySQL
MySQL常用慢查询分析工具详解
Aug 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中数组首字符过滤功能代码
2012/07/31 PHP
编译php 5.2.14+fpm+memcached(具体操作详解)
2013/06/18 PHP
PHP多态代码实例
2015/06/26 PHP
用PHP做了一个领取优惠券活动的示例代码
2019/07/05 PHP
重定向实现代码
2006/11/20 Javascript
利用javascript移动div层-javascript 拖动层
2009/03/22 Javascript
JS Excel读取和写入操作(模板操作)实现代码
2010/04/11 Javascript
javascript new后的constructor属性
2010/08/05 Javascript
JavaScript自执行闭包的小例子
2013/06/29 Javascript
javascript 获取浏览器版本
2015/01/21 Javascript
js实现模拟计算器退格键删除文字效果的方法
2015/05/07 Javascript
JavaScript实现多种排序算法
2016/02/24 Javascript
JavaScript实现斗地主游戏的思路
2016/02/29 Javascript
JavaScript面向对象程序设计教程
2016/03/29 Javascript
JS实现鼠标框选效果完整实例
2016/06/20 Javascript
AngularJS过滤器filter用法分析
2016/12/11 Javascript
解决Vue 项目打包后favicon无法正常显示的问题
2018/09/01 Javascript
详解原生JS回到顶部
2019/03/25 Javascript
webpack DllPlugin xxx is not defined解决办法
2019/12/13 Javascript
jQuery实现滑动开关效果
2020/08/02 jQuery
微信小程序实现打卡签到页面
2020/09/21 Javascript
vue中使用router全局守卫实现页面拦截的示例
2020/10/23 Javascript
NestJs使用Mongoose对MongoDB操作的方法
2021/02/22 Javascript
从源码解析Python的Flask框架中request对象的用法
2016/06/02 Python
Pycharm学习教程(6) Pycharm作为Vim编辑器使用
2017/05/03 Python
英国鲜花速递:Serenata Flowers
2018/04/03 全球购物
Theory美国官网:后现代都市风时装品牌
2018/05/09 全球购物
纽约市的奢华内衣目的地:Anya Lust
2019/08/02 全球购物
中英文自我评价语句
2013/12/20 职场文书
知识就是力量演讲稿
2014/09/13 职场文书
2014年领导班子专项整治整改方案
2014/09/28 职场文书
法学专业大学生实习自我鉴定
2014/10/05 职场文书
2014年妇委会工作总结
2014/12/10 职场文书
酒店辞职书范文
2015/02/26 职场文书
委托收款证明
2015/06/23 职场文书
React实现动效弹窗组件
2021/06/21 Javascript