Python实现MySQL百万级数据高效导出Excel方案
1. 项目背景与需求场景在日常数据处理工作中我们经常需要将数据库中的大量记录导出到Excel文件进行二次处理或分发。作为数据工程师我每周都要处理几十次这样的需求市场部门需要客户数据做分析、财务部门需要交易记录对账、运营团队需要用户行为数据生成报表...传统的手工操作方式存在明显痛点通过数据库客户端工具导出时每次都需要重复设置查询条件和导出参数数据量超过百万行时GUI工具经常卡死或崩溃需要定期执行的导出任务无法自动化不同数据库系统的导出操作差异大学习成本高Python正好能完美解决这些问题。最近我用PyMySQLopenpyxl组合实现了一套自动化导出方案单脚本可处理MySQL百万级数据导出还能自动拆分Excel文件避免超过104万行限制。下面分享具体实现方法和踩坑经验。2. 技术方案选型2.1 数据库连接方案比较对于Python连接数据库主流有几种方案DB-API标准接口优点标准化接口代码可移植性强缺点需要针对不同数据库安装特定驱动代表库PyMySQL(MySQL)、psycopg2(PostgreSQL)、cx_Oracle(Oracle)ORM框架优点面向对象操作自动防SQL注入缺点性能损耗学习曲线陡峭代表库SQLAlchemy、DjangoORM专用连接器优点厂商官方支持功能完整缺点依赖特定数据库代表mysql-connector-python提示对于纯导出场景推荐使用DB-API方案。ORM在简单查询场景会产生15-20%的性能开销2.2 Excel操作库选型处理Excel文件的Python库主要有库名称读写支持大文件处理公式支持样式调整适用场景openpyxl读写一般完善完善需要修改样式的情况xlsxwriter只写优秀基础完善大数据量导出pandas读写优秀无有限数据分析场景pyxlsb读写优秀无无处理二进制xlsb实测百万行数据导出openpyxl耗时约210秒内存占用1.2GBxlsxwriter耗时约95秒内存占用300MB3. 完整实现方案3.1 基础版本代码import pymysql from openpyxl import Workbook def export_to_excel(host, user, password, db, sql, output_path): # 建立数据库连接 connection pymysql.connect( hosthost, useruser, passwordpassword, databasedb, cursorclasspymysql.cursors.DictCursor ) try: with connection.cursor() as cursor: print(Executing query...) cursor.execute(sql) # 创建Excel工作簿 wb Workbook() ws wb.active # 写入表头 if cursor.description: headers [desc[0] for desc in cursor.description] ws.append(headers) # 分批写入数据 batch_size 10000 while True: rows cursor.fetchmany(batch_size) if not rows: break for row in rows: ws.append(list(row.values())) print(fProcessed {len(rows)} rows) # 保存文件 wb.save(output_path) print(fFile saved to {output_path}) finally: connection.close()3.2 生产环境增强版实际使用时需要考虑更多因素内存优化- 使用生成器分批处理def batch_fetch(cursor, size10000): while True: rows cursor.fetchmany(size) if not rows: break yield rows多Sheet支持- 避免Excel行数限制MAX_ROWS_PER_SHEET 1000000 # Excel限制 sheet_count 1 current_row 0 ws wb.create_sheet(fData_{sheet_count}) for batch in batch_fetch(cursor): for row in batch: if current_row MAX_ROWS_PER_SHEET: sheet_count 1 current_row 0 ws wb.create_sheet(fData_{sheet_count}) ws.append(headers) ws.append(list(row.values())) current_row 1类型处理- 处理datetime等特殊类型from datetime import datetime def format_value(value): if isinstance(value, datetime): return value.strftime(%Y-%m-%d %H:%M:%S) return str(value) if value is not None else 4. 性能优化技巧4.1 数据库层面优化使用SS游标(Server Side Cursor)connection pymysql.connect( ..., cursorclasspymysql.cursors.SSCursor )添加查询超时设置cursor.execute(SET SESSION max_execution_time300000) # 5分钟超时只查询必要字段避免SELECT *明确列出所需字段4.2 Excel写入优化禁用openpyxl自动计算wb Workbook(write_onlyTrue)使用xlsxwriter的常量内存模式import xlsxwriter workbook xlsxwriter.Workbook( large.xlsx, {constant_memory: True} )关闭自动过滤worksheet.autofilter False5. 常见问题与解决方案5.1 内存溢出问题现象处理大数据量时Python进程被Killed解决方案使用SSCursor游标减小batch_size(建议5000-10000)换用xlsxwriter库5.2 中文乱码问题现象导出的Excel打开中文显示为乱码解决方法# 连接数据库时指定编码 connection pymysql.connect( ..., charsetutf8mb4 ) # 保存Excel时指定编码 wb.save(output_path, encodingutf-8)5.3 日期格式问题现象数据库中的datetime导出后变成数字解决方法from openpyxl.styles import numbers for cell in ws[C]: # 假设C列是日期列 if cell.row 1: # 跳过表头 continue cell.number_format numbers.FORMAT_DATE_DATETIME6. 进阶功能实现6.1 多线程导出from concurrent.futures import ThreadPoolExecutor def export_table(table_name): sql fSELECT * FROM {table_name} output f{table_name}.xlsx export_to_excel(..., sql, output) with ThreadPoolExecutor(max_workers4) as executor: tables [users, orders, products] executor.map(export_table, tables)6.2 定时自动导出使用APScheduler实现定时任务from apscheduler.schedulers.blocking import BlockingScheduler sched BlockingScheduler() sched.scheduled_job(cron, hour2) # 每天凌晨2点执行 def daily_export(): export_to_excel(...) sched.start()6.3 命令行参数支持import argparse parser argparse.ArgumentParser() parser.add_argument(--host, requiredTrue) parser.add_argument(--user, requiredTrue) parser.add_argument(--output, defaultoutput.xlsx) args parser.parse_args() export_to_excel( hostargs.host, userargs.user, ... output_pathargs.output )7. 完整生产级代码示例#!/usr/bin/env python3 数据库导出Excel工具 - 生产环境版本 支持功能 1. 多线程分表导出 2. 自动拆分大文件 3. 完善的错误处理 4. 命令行参数支持 import argparse import logging from concurrent.futures import ThreadPoolExecutor from datetime import datetime from typing import Iterator, List, Dict import pymysql from openpyxl import Workbook from openpyxl.styles import numbers # 配置日志 logging.basicConfig( levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s ) logger logging.getLogger(__name__) MAX_ROWS_PER_SHEET 1000000 # Excel单Sheet最大行数 DEFAULT_BATCH_SIZE 5000 # 每次从数据库读取的行数 class DatabaseExporter: def __init__(self, host: str, user: str, password: str, database: str, port: int 3306): self.connection_params { host: host, user: user, password: password, database: database, port: port, cursorclass: pymysql.cursors.SSCursor, charset: utf8mb4 } def _execute_query(self, sql: str) - Iterator[List[Dict]]: 执行SQL查询并返回生成器 conn pymysql.connect(**self.connection_params) cursor conn.cursor(pymysql.cursors.DictCursor) try: logger.info(fExecuting query: {sql[:100]}...) cursor.execute(sql) while True: rows cursor.fetchmany(DEFAULT_BATCH_SIZE) if not rows: break yield rows finally: cursor.close() conn.close() def _format_value(self, value) - str: 格式化特殊类型数据 if isinstance(value, datetime): return value.strftime(%Y-%m-%d %H:%M:%S) return str(value) if value is not None else def export_to_excel(self, sql: str, output_path: str) - None: 主导出函数 wb Workbook(write_onlyTrue) sheet_count 1 current_row 0 headers None # 创建第一个Sheet ws wb.create_sheet(titlefSheet_{sheet_count}) for batch in self._execute_query(sql): # 首次获取数据时提取表头 if headers is None and batch: headers list(batch[0].keys()) ws.append(headers) for row in batch: # 检查是否需要新建Sheet if current_row MAX_ROWS_PER_SHEET: sheet_count 1 current_row 0 ws wb.create_sheet(titlefSheet_{sheet_count}) ws.append(headers) # 格式化并写入行数据 formatted_row [self._format_value(v) for v in row.values()] ws.append(formatted_row) current_row 1 logger.info(fProcessed {len(batch)} rows, total: {current_row}) # 保存工作簿 wb.save(output_path) logger.info(fSuccessfully exported to {output_path}) def main(): 命令行入口 parser argparse.ArgumentParser( descriptionExport database data to Excel file) parser.add_argument(--host, requiredTrue, helpDatabase host) parser.add_argument(--user, requiredTrue, helpDatabase user) parser.add_argument(--password, requiredTrue, helpDatabase password) parser.add_argument(--database, requiredTrue, helpDatabase name) parser.add_argument(--port, typeint, default3306, helpDatabase port) parser.add_argument(--sql, helpSQL query to execute) parser.add_argument(--table, helpExport entire table if specified) parser.add_argument(--output, requiredTrue, helpOutput Excel file path) parser.add_argument(--threads, typeint, default1, helpNumber of parallel threads) args parser.parse_args() exporter DatabaseExporter( hostargs.host, userargs.user, passwordargs.password, databaseargs.database, portargs.port ) if args.table: # 导出整个表 exporter.export_to_excel( sqlfSELECT * FROM {args.table}, output_pathargs.output ) elif args.sql: # 执行自定义SQL exporter.export_to_excel( sqlargs.sql, output_pathargs.output ) else: # 批量导出所有表 def export_table(table: str): output f{table}_{args.output} exporter.export_to_excel( sqlfSELECT * FROM {table}, output_pathoutput ) with ThreadPoolExecutor(max_workersargs.threads) as executor: # 获取所有表名 tables [row[Tables_in_db] for row in exporter._execute_query(SHOW TABLES)] executor.map(export_table, tables) if __name__ __main__: main()8. 实际应用中的经验分享连接池的使用对于高频导出任务建议使用DBUtils等连接池工具。实测连接池可以将频繁导出场景的性能提升3-5倍。超时设置复杂查询务必设置合理的超时时间。我曾经遇到过没有超时设置的导出任务运行了18小时最终因网络中断失败。断点续传对于超大数据量导出可以实现记录已导出行数的机制。示例代码# 记录导出进度 progress_file f{output_path}.progress last_exported_id 0 if os.path.exists(progress_file): with open(progress_file) as f: last_exported_id int(f.read()) sql fSELECT * FROM big_table WHERE id {last_exported_id} ORDER BY idExcel格式优化金融数据导出时数值列应该设置千分位分隔from openpyxl.styles import numbers for col in [B, C, D]: # 数值列 for cell in ws[col]: if cell.row ! 1: # 跳过表头 cell.number_format numbers.FORMAT_NUMBER_COMMA_SEPARATED1性能监控添加简单的性能统计start_time time.time() total_rows 0 # ...导出过程中... total_rows len(batch) elapsed time.time() - start_time speed total_rows / elapsed if elapsed 0 else 0 logger.info(fSpeed: {speed:.1f} rows/sec)

相关新闻

CAD Sketcher:如何用Blender实现工业级参数化草图设计?

CAD Sketcher:如何用Blender实现工业级参数化草图设计?

CAD Sketcher:如何用Blender实现工业级参数化草图设计? 【免费下载链接】CAD_Sketcher Constraint-based geometry sketcher for blender 项目地址: https://gitcode.com/gh_mirrors/ca/CAD_Sketcher 你是否曾在Blender中绘制机械零件时&#xff…

2026/7/27 12:27:38 阅读更多 →
本土化翻译性价比实测:贵的方案就一定更地道吗

本土化翻译性价比实测:贵的方案就一定更地道吗

先说结论:价格与地道程度并非线性正相关。人工翻译时代,报价常常对应译员经验和润色工时;进入 AI 译制流程后,本土化规则、俚语处理和语言习惯适配已成为系统的基础能力。判断性价比,不能只看总价,而要拆开…

2026/7/27 12:26:38 阅读更多 →
OC-Little Translated与OpenCore配置:打造稳定高效的黑苹果系统

OC-Little Translated与OpenCore配置:打造稳定高效的黑苹果系统

OC-Little Translated与OpenCore配置:打造稳定高效的黑苹果系统 【免费下载链接】OC-Little-Translated ACPI hotpatches, fixes, and guides for OpenCore. Optimize your Hackintosh and run macOS 13 on Wintel PCs with OpenCore Legacy Patcher. 项目地址: h…

2026/7/27 12:26:38 阅读更多 →

最新新闻

jRails开发者手册:Ruby与JavaScript桥接的核心代码详解

jRails开发者手册:Ruby与JavaScript桥接的核心代码详解

jRails开发者手册:Ruby与JavaScript桥接的核心代码详解 【免费下载链接】jrails jRails is a drop-in jQuery replacement for Prototype/script.aculo.us on Rails. Using jRails, you can get all of the same default Rails helpers for javascript functionalit…

2026/7/27 12:47:45 阅读更多 →
C++ STL unordered系列容器详解:从unordered_set到unordered_map

C++ STL unordered系列容器详解:从unordered_set到unordered_map

在C STL中,关联式容器一直承担着高效数据管理的重要角色。根据底层实现方式的不同,它们通常可以分为两类:一类是基于红黑树实现的有序关联容器,如set、map;另一类则是基于哈希表实现的无序关联容器,如unord…

2026/7/27 12:47:45 阅读更多 →
终极智能家居控制:Dasher让Amazon Dash按钮秒变智能开关

终极智能家居控制:Dasher让Amazon Dash按钮秒变智能开关

终极智能家居控制:Dasher让Amazon Dash按钮秒变智能开关 【免费下载链接】dasher 🔘 A simple way to bridge your Amazon Dash buttons to HTTP services 项目地址: https://gitcode.com/gh_mirrors/da/dasher Dasher是一款简单实用的工具&#…

2026/7/27 12:47:45 阅读更多 →
TPS61202超宽压升压转换器:从0.3V启动到5V输出的高效电源方案

TPS61202超宽压升压转换器:从0.3V启动到5V输出的高效电源方案

1. 项目概述与核心价值在便携式电子设备、物联网节点和各类能量采集系统中,一个永恒的挑战是如何从极不稳定的低电压源(例如单节即将耗尽的碱性电池、弱光下的太阳能电池板,或者微型燃料电池)中,稳定、高效地获取一个可…

2026/7/27 12:47:45 阅读更多 →
YOLOv5工业质检优化:Java实现精度提升10%+

YOLOv5工业质检优化:Java实现精度提升10%+

## 1. 项目背景与目标去年在优化一个工业质检项目时,我发现官方YOLOv5模型在特定场景下的检测精度始终无法突破92%。经过三个月系统性重构,最终用Java复现的版本在相同测试集上达到了102.3%的相对精度(mAP0.5),同时保持…

2026/7/27 12:47:44 阅读更多 →
Loop:免费开源Mac窗口管理工具,用径向菜单提升你的工作效率

Loop:免费开源Mac窗口管理工具,用径向菜单提升你的工作效率

Loop:免费开源Mac窗口管理工具,用径向菜单提升你的工作效率 【免费下载链接】Loop Window management made elegant. 项目地址: https://gitcode.com/GitHub_Trending/lo/Loop 你是否厌倦了在杂乱的Mac桌面上寻找窗口?想要一种更优雅、…

2026/7/27 12:46:44 阅读更多 →

日新闻

【JAVA毕设源码分享】基于SpringBoot的社区智能垃圾管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

【JAVA毕设源码分享】基于SpringBoot的社区智能垃圾管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/27 0:00:54 阅读更多 →
SPI实战指南:从时钟模式到寄存器配置,解决嵌入式通信难题

SPI实战指南:从时钟模式到寄存器配置,解决嵌入式通信难题

1. 项目概述:从寄存器手册到实战指南 如果你手头有一份类似德州仪器(TI)TMS320x240xA系列DSP的SPI模块技术手册,看着里面密密麻麻的寄存器位定义、时序图和公式,是不是感觉头大?这份资料虽然权威&#xff0…

2026/7/27 0:00:54 阅读更多 →
【JAVA毕设源码分享】基于springboot的水果购物管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

【JAVA毕设源码分享】基于springboot的水果购物管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/27 0:00:54 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/27 4:33:59 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/27 6:31:56 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/27 4:01:12 阅读更多 →

月新闻