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 外键约束和表关系相关总结
Jun 20 MySQL
新手入门Mysql--sql执行过程
Jun 20 MySQL
MySQL七种JOIN类型小结
Oct 24 MySQL
教你使用VS Code的MySQL扩展管理数据库的方法
Jan 22 MySQL
Mysql事务索引知识汇总
Mar 17 MySQL
你真的会用Mysql的explain吗
Mar 31 MySQL
mysql 8.0.27 绿色解压版安装教程及配置方法
Apr 20 MySQL
在MySQL中你成功的避开了所有索引
Apr 20 MySQL
MySQL 数据库 增删查改、克隆、外键 等操作
May 11 MySQL
MySql数据库触发器使用教程
Jun 01 MySQL
MySQL数据库如何查看表占用空间大小
Jun 10 MySQL
MySQL控制流函数(-if ,elseif,else,case...when)
Jul 07 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&amp;mysql(六)
2006/10/09 PHP
PHP+DBM的同学录程序(4)
2006/10/09 PHP
PHP IPV6正则表达式验证代码
2010/02/16 PHP
PHP版国家代码、缩写查询函数代码
2011/08/14 PHP
Laravel 实现Controller向blade前台模板赋值的四种方式小结
2019/10/22 PHP
Laravel等框架模型关联的可用性浅析
2019/12/15 PHP
JavaScript高级程序设计 阅读笔记(二十一) JavaScript中的XML
2012/09/14 Javascript
js截取字符串的两种方法及区别详解
2013/11/05 Javascript
JavaScript数值转换的三种方式总结
2014/07/31 Javascript
推荐25个超炫的jQuery网格插件
2014/11/28 Javascript
javascript实用方法总结
2015/02/06 Javascript
分享javascript实现的冒泡排序代码并优化
2016/06/05 Javascript
使用Bootstrap typeahead插件实现搜索框自动补全的方法
2016/07/07 Javascript
js实现小窗口拖拽效果
2016/12/03 Javascript
Bootstrap弹出框modal上层的输入框不能获得焦点问题的解决方法
2016/12/13 Javascript
javascript中闭包概念与用法深入理解
2016/12/15 Javascript
Vue.js实现一个漂亮、灵活、可复用的提示组件示例
2017/03/17 Javascript
微信小程序使用input组件实现密码框功能【附源码下载】
2017/12/11 Javascript
vuejs实现标签选项卡动态更改css样式的方法
2018/05/31 Javascript
JS通用方法触发点击事件代码实例
2020/02/17 Javascript
详解python string类型 bytes类型 bytearray类型
2017/12/16 Python
python 获取微信好友列表的方法(微信web)
2019/02/21 Python
新手如何发布Python项目开源包过程详解
2019/07/11 Python
pip安装python库的方法总结
2019/08/02 Python
numpy ndarray 按条件筛选数组,关联筛选的例子
2019/11/26 Python
Python实现转换图片背景颜色代码
2020/04/30 Python
Django中如何用xlwt生成表格的方法步骤
2021/01/31 Python
Python抖音快手代码舞(字符舞)的实现方法
2021/02/07 Python
施华洛世奇英国官网:SWAROVSKI英国
2017/03/13 全球购物
SHEIN香港:价格实惠的女性时尚服装
2018/08/14 全球购物
美国领先的男士和女士内衣购物网站:Freshpair
2019/02/25 全球购物
总经理职责
2013/12/22 职场文书
信用社竞聘演讲稿
2014/05/16 职场文书
新品发布会策划方案
2014/06/08 职场文书
房屋租赁意向书范本
2015/05/09 职场文书
Win11 Dev 预览版25174.1000发布 (附更新修复内容汇总)
2022/08/05 数码科技