pd.read_csv与.to_sql数据行数不符:5000万行仅存2.1万行求助
你提到有一个5000万行的CSV文件,用Pandas分块读取后写入SQLite,但最终仅成功存入约21000行。先看一下你的代码(已格式化):
chunksize = 100000 csv_database = create_engine('sqlite:///csv_database.db', pool_pre_ping=True) i=0 j=0 q=0 for df in pd.read_csv(filename, chunksize = chunksize, iterator = False): # df = df.rename(columns={c: c.replace(' ', '') for c in df.columns}) df.index += j i+= 1 df.to_sql('table', csv_database, if_exists='append') j = df.index[-1] +1 q+=1 print("q: " + repr(q)) columnx = df.iloc[:,0] columny = df.iloc[:,1] columnz = df.iloc[:,2] columnmass = df.iloc[:,3]
从你的输出看,最后一次循环的df只有21739行,而且q的打印次数应该只有1次?这说明循环可能只执行了一次,或者后续块读取/写入时悄悄失败了。下面是几个最可能的问题点和修复建议:
1. iterator=False的设置干扰分块逻辑
虽然Pandas文档说明指定chunksize时会自动返回可迭代的TextFileReader,但显式设置iterator=False可能会意外终止分块迭代。建议直接移除这个参数,或者显式设为iterator=True,确保能遍历所有数据块:
for df in pd.read_csv(filename, chunksize=chunksize, iterator=True):
2. CSV文件格式解析异常
如果CSV的分隔符不正确、存在未闭合的引号,或者换行符处理混乱,会导致Pandas读取完第一块后无法解析后续数据。可以尝试:
- 显式指定分隔符,比如
sep=','(如果是逗号分隔); - 用Python引擎处理复杂格式:
engine='python'; - 添加
on_bad_lines='skip'跳过损坏的行,验证是否能读取更多数据:
pd.read_csv(filename, chunksize=chunksize, sep=',', engine='python', on_bad_lines='skip')
3. 缺少异常捕获,隐藏了后续块的错误
你的代码没有任何异常处理,可能后续块在读取或写入时发生错误(比如数据类型不匹配、SQLite唯一性约束冲突),导致循环直接终止但你没看到报错。建议添加异常捕获:
for df in pd.read_csv(filename, chunksize=chunksize): try: # 移除不必要的索引操作(除非你确实需要把索引存入数据库) df.to_sql('table', csv_database, if_exists='append', index=False) q += 1 print(f"Processed chunk {q}, rows added: {len(df)}") except Exception as e: print(f"Error in chunk {q}: {str(e)}") break
4. 索引操作可能触发写入失败
你修改了DataFrame的索引(df.index += j),如果SQLite表中自动创建的index列被隐式设为主键,后续块的索引重复会触发唯一性约束错误,导致写入中断。如果不需要把索引存入数据库,建议在to_sql中设置index=False,彻底避免这个问题。
5. 确认CSV文件的实际行数
有可能你的CSV文件本身并没有5000万行,或者文件损坏。可以用命令行工具快速验证:
- Linux/macOS:
wc -l filename.csv - Windows:
find /c /v "" filename.csv
优化建议:用事务提升写入性能和完整性
写入大量数据时,手动开启事务可以大幅提升SQLite的写入速度,同时确保数据不会因为中途中断而丢失:
with csv_database.begin() as conn: q = 0 for df in pd.read_csv(filename, chunksize=chunksize, index_col=False): df.to_sql('table', conn, if_exists='append', index=False) q += 1 print(f"Completed chunk {q}, total rows processed: {q * chunksize}")
内容的提问来源于stack exchange,提问作者Dallin Barton

