使用openpyxl匹配大小Excel表数据时如何优化过长运行时长?
性能问题根源
你当前的代码采用嵌套循环逻辑,时间复杂度为O(N*M),其中N是表格1的2万行,M是表格2的100万行,总运算量达到200亿次,必然会出现运行时间过长的问题。
最优优化方案:哈希字典查找
该方案时间复杂度为O(N+M),实现简单且查询效率比二分查找更高,是这类匹配场景的首选方案。
核心逻辑是先遍历一次表格2,将ID作为key、对应行数据作为value存入字典,后续遍历表格1时直接做O(1)的哈希查询即可。
实现代码如下:
import openpyxl import csv # 1. 预加载表格2构建ID映射字典 g2 = openpyxl.load_workbook('path/to/sheet2/sheet2.xlsx', read_only=True) grid2 = g2.active id_to_row = {} # 如果表格2有表头,可加下一行跳过表头 # next(grid2.rows) for row in grid2.rows: id_val = row[0].value if id_val is None: continue try: id_key = int(id_val) # 提前处理好行内容,避免后续重复计算 row_content = [str(c.value) for c in row[1:]] id_to_row[id_key] = row_content except (ValueError, TypeError): continue g2.close() # 2. 遍历表格1匹配写入结果 g1 = openpyxl.load_workbook('path/to/sheet/sheet1.xlsx', read_only=True) grid1 = g1.active with open('output.csv', 'w', encoding='utf-8', newline='') as f: writer = csv.writer(f) # 如果表格1有表头,可加下一行跳过表头 # next(grid1.rows) for row in grid1.rows: match_val = row[1].value output_key = row[0].value if match_val is None or output_key is None: continue try: search_key = int(match_val) if search_key in id_to_row: writer.writerow([str(int(output_key))] + id_to_row[search_key]) except (ValueError, TypeError): continue g1.close()
100万行的表格2数据完全可以正常存入内存,整个流程运行时间通常在分钟级甚至秒级。
二分查找实现方案(次选)
如果你需要按照指定的二分查找方案实现,需要注意该方案要求表格2的ID列有序,如果原表ID无序需要先做排序,整体时间复杂度为O(M logM + N logM),性能略低于哈希方案。
实现代码如下:
import openpyxl import csv import bisect # 1. 加载表格2数据 g2 = openpyxl.load_workbook('path/to/sheet2/sheet2.xlsx', read_only=True) grid2 = g2.active id_row_list = [] # next(grid2.rows) # 有表头则取消注释 for row in grid2.rows: id_val = row[0].value if id_val is None: continue try: id_key = int(id_val) row_content = [str(c.value) for c in row[1:]] id_row_list.append((id_key, row_content)) except: continue g2.close() # 2. 按ID排序(如果原表ID已经有序可以跳过这一步) id_row_list.sort(key=lambda x: x[0]) id_list = [item[0] for item in id_row_list] # 3. 遍历表格1二分查找匹配 g1 = openpyxl.load_workbook('path/to/sheet/sheet1.xlsx', read_only=True) grid1 = g1.active with open('output.csv', 'w', encoding='utf-8', newline='') as f: writer = csv.writer(f) # next(grid1.rows) # 有表头则取消注释 for row in grid1.rows: match_val = row[1].value output_key = row[0].value if match_val is None or output_key is None: continue try: search_key = int(match_val) idx = bisect.bisect_left(id_list, search_key) if idx < len(id_list) and id_list[idx] == search_key: writer.writerow([str(int(output_key))] + id_row_list[idx][1]) except: continue g1.close()
额外优化建议
- 大体积Excel文件读写优先用pandas、polars这类结构化数据处理库,比openpyxl性能高3-10倍,且匹配逻辑更简洁,pandas实现参考代码:
import pandas as pd # 读取两个表格 df1 = pd.read_excel('path/to/sheet1.xlsx', usecols=[0,1], names=['output_key', 'match_id']) df2 = pd.read_excel('path/to/sheet2.xlsx') # 关联匹配 result = df1.merge(df2, left_on='match_id', right_on='ID', how='inner') # 输出结果 result.to_csv('output.csv', index=False, encoding='utf-8')
- 删掉所有不必要的print语句,打印操作会大幅拖慢执行速度。
- 如果存在同一ID对应多行的场景,哈希方案中可以把字典的value改成列表,存储所有匹配的行即可。
内容的提问来源于stack exchange,提问作者NeutrinoBlue
相关产品推荐
相关产品推荐

