Mysql单表大数据量数据导出(备份)到本地的一个比较笨, 但很实在的方法: 蚂蚁搬家

需求

Mysql 某表的数据量很大(几十个G), 直接用mysql客户端的工具没法导出

所以干脆就写个脚本一批一批的导出, 就叫它: 蚂蚁搬家

代码清单

思路基本就有了: 先查数据库, 假如每次查询10w条记录, 然后写入到本地的文件里, 直到数据全部导出

直接上代码吧: db_tablename_backup.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# author: xu3352<xu3352@gmail.com>
# xx_tablename 数据备份

import sys

from utils import mysqlutils
from utils.timeutils import get_time, get_secs, timecost


def dojob(name):
    print('{} backup data start... tablename:{} '.format(get_time(), name))
    s_time = get_secs()
    con, cur = mysqlutils.get_connect_cursor()

    table_name = 'database_name.{}'.format(name)
    # 按 id 区间查询
    sql = ''' select min(id) minid, max(id) maxid, count(1) totalcnt from {table_name} '''.format(table_name=table_name)
    info = mysqlutils.queryone_process(con, cur, sql)
    print('table_name:{}   minid:{} maxid:{} totalcnt:{}'.format(table_name, info['minid'], info['maxid'], info['totalcnt']))

    currid = info['minid']
    maxid = info['maxid']
    #currid = 1
    #maxid = 123456789
    step = 10 * 10000
    while currid < maxid:
        sql = ''' select id, a, b, c, d, e, f, ...
                         from {table_name}
                         where id between %s and %s
                         '''.format(table_name=table_name)
        rows = mysqlutils.queryall_process(con, cur, sql, (currid, currid + step))
        cnt = write2file(rows)
        currid += step
        percent = '{0:.0%}'.format(currid / maxid)
        print('{} nextid:{} rows:{} time:{} process:{}'.format(get_time(), currid, cnt, timecost(s_time), percent))

    mysqlutils.close_cursor_connect(cur, con)
    print('{} backup data complate... time:{}'.format(get_time(), timecost(s_time)))


def write2file(rows):
    """ 简单处理后, 写入文件 """
    if not rows:
        return 0
    lines = []
    for row in rows:
    strs = '{}|{}|{}|{}|{}|{}|{}|...'.format(
            row['id'],
            row['a'],
            row['b'],
            row['c'].replace('|', ''),
            row['d'],
            row['e'],
            row['f'],
            ...
            )
        lines.append(strs)
    # 写入文件
    write_file(filename, lines)
    return len(lines)


def write_file(filepath, rows=[]):
    """ 写文件 """
    with open(filepath, 'a') as output:
        for text in rows:
            output.write(text + '\n')
    return len(rows)


if __name__ == "__main__":
    filename = '/data/xx_tablename.txt'
    name = 'xx_tablename'
    dojob(name)

还可以选择性的只备份重要的字段, 省网络流量, 省存储空间, 不过主键ID得是自增型的

注意事项

  • 由于耗时较长(几个小时), 本地网络可能不稳定, 建议放到找一台服务器跑: tmux 或 nohup 都是不错的选择, 可以无人值守
  • 磁盘空间要留足, 导出来也是几十个G
  • 如果执行过程中断了, 可以根据最后存的ID位置重新跑, 节省时间
  • 大文件不好传输(下载)的, 可以切分为多个小文件: split 命令

参考:



blog comments powered by Disqus

Published

17 February 2019

Tags