Django下快速导入大Excel(1万行250列)数据至MySQL的方案咨询
优化Excel导入MySQL的方案(Django环境)
一、优化Pandas导入逻辑
- 避免逐行遍历:放弃
iterrows()这类低效遍历方式,直接用to_sql的批量参数优化- 设置
chunksize:比如df.to_sql('your_table', engine, if_exists='append', chunksize=1000),控制单次写入行数,降低内存负载 - 关闭索引写入:添加
index=False参数,避免把DataFrame的索引列写入数据库
- 设置
- 批量添加文件标识:在DataFrame中新增
file_id列,一次性赋值后再执行写入,不要逐行追加 - 更换高效引擎:使用
SQLAlchemy的mysql+pymysql引擎时,加上pool_recycle=3600避免连接超时;或改用mysql-connector-python,部分场景下写入速度更快
二、改用Django原生批量操作
- 轻量解析Excel:用
openpyxl直接读取(纯数值型数据场景下比pandas更高效),将每行数据转为带file_id的字典 - 用
bulk_create批量插入:把字典列表转为Django Model实例,调用YourModel.objects.bulk_create(instances, batch_size=500),批量插入速度远高于逐行save()- 示例代码:
from openpyxl import load_workbook workbook = load_workbook('your_uploaded_file.xlsx', read_only=True) sheet = workbook.active headers = [cell.value for cell in sheet[1]] instances = [] file_id = 'your_unique_file_tag' for row in sheet.iter_rows(min_row=2, values_only=True): row_data = dict(zip(headers, row)) row_data['file_id'] = file_id instances.append(YourModel(**row_data)) # 每攒够500条批量插入一次 if len(instances) >= 500: YourModel.objects.bulk_create(instances) instances = [] # 处理剩余不足500条的数据 if instances: YourModel.objects.bulk_create(instances)
- 示例代码:
- 注意:
bulk_create不会触发Model的save()信号,若有信号相关逻辑需要手动处理
三、异步处理导入任务
- 用Celery异步执行导入:用户上传文件后立即返回成功,后台异步处理解析和入库,避免接口超时
- 执行步骤:
- 将上传的Excel文件保存到本地或对象存储(如MinIO)
- 生成唯一
file_id,记录文件元信息到数据库 - 发送Celery任务,传入文件路径和
file_id - 异步任务中执行解析、批量入库逻辑
- 执行步骤:
- 这种方式既提升用户体验,也避免长时间占用接口线程
四、数据库层面优化
- 多值插入优化:使用
to_sql时,设置method='multi'(SQLAlchemy 1.4+支持),生成多值插入语句,减少SQL执行次数 - 临时关闭非主键索引:导入前关闭目标表的非主键索引,导入完成后再重建,避免每次插入都更新索引
- 示例SQL:
ALTER TABLE your_table DISABLE KEYS; -- 执行导入操作 ALTER TABLE your_table ENABLE KEYS;
- 示例SQL:
- 调整MySQL配置:增大
innodb_buffer_pool_size、innodb_log_file_size提升写入性能;开启innodb_flush_log_at_trx_commit=2(牺牲少量一致性换取批量写入速度,适合导入场景)
五、文件解析优化
- 开启只读模式读取:不管用pandas还是openpyxl,都开启只读模式,减少内存占用,加快读取速度
- pandas:
pd.read_excel('file.xlsx', engine='openpyxl', usecols=range(250))(指定列数避免读取冗余内容) - openpyxl:
load_workbook('file.xlsx', read_only=True)
- pandas:
- 固定数据类型:直接指定数值类型,避免pandas自动推断类型的开销,比如
pd.read_excel(..., dtype='float64')
内容的提问来源于stack exchange,提问作者Dany Anderson Chavez Pauca
相关产品推荐
相关产品推荐

