Python 使用df.to_sql()将块写入数据库时出错
现有数据库和预期结果: 我有一个更大的SQLite数据库12gb,表中有4400多万行,我想在Python3中使用Pandas修改这些表 示例目标:我希望将这些大表中的4400万行以块的形式读入DF,操作DF块,并将结果写入新表。如果可能的话,我想替换新表(如果它存在),并将每个块追加到它 因为我的操作只添加或修改列,所以新表的行数应该与原始表的行数相同 问题: 主要问题似乎源于以下代码中的以下行: df.to_sqlnew_表,con=db,如果_存在=append,index=False 当这一行在下面的代码中运行时,我似乎总是得到一个size=N的额外块,加上一个比我预期的要多的观察值。 第一次使用新表名运行此代码时,我收到一个错误: 回溯最近一次呼叫上次: 文件example.py,第23行,在 对于df_发生器中的df: 文件/usr/local/lib/python3.5/site-packages/pandas/io/sql.py,第1420行,在查询迭代器中 data=cursor.fetchmanychunksize sqlite3.0错误:SQL逻辑错误或缺少数据库 如果我使用相同的新表名重新运行脚本,它将针对每个块和一个额外的块+1行运行 当df.to_sql行被注释掉时,循环将按预期的块数运行 完整代码问题的测试示例: 完整代码:example.py 作为pd进口熊猫 导入sqlite3 示例中使用的Helper函数 def REINVAR、outvar、df: df.renamecolumns={invar:outvar},inplace=True 返回DF def计数结果,表: [打印[*]总计:{}表中的{,}行 .formator[0],表 对于c.executeSELECT COUNT*中的r,从{};.formattable]中选择 连接到数据 db=sqlite3.connecttest.db c=db.cursor 新建表格=新建表格 分块加载数据 df_generator=pd.read_sql_queryselect*from test_table limit 10000;,con=db,chunksize=5000 对于df_发生器中的df: 用于修改数据的函数,例如 df=renname,重命名为_name,df printdf.shape df.to_sqlnew_表,con=db,如果_存在=append,index=False 如果创建了新表,则计数 尝试: 计数结果,新表格 除: 通过 一,。结果当 df.to_sqlnew_表,con=db,如果_存在=append,index=False 问题行被注释掉: $python3 example.py 5000, 22 5000, 22 因为示例代码将我的大表限制为10k行,所以我希望这样 二,。结果当 df.to_sqlnew_表,con=db,如果_存在=append,index=False a。问题行没有被注释掉 b。这是第一次使用新的_表运行代码: $python3 example.py 5000, 22 回溯最近一次呼叫上次: 文件example.py,第23行,在 对于df_发生器中的df: 文件/usr/local/lib/python3.5/site-packages/pandas/io/sql.py,第1420行,在查询迭代器中 data=cursor.fetchmanychunksize sqlite3.0错误:SQL逻辑错误或缺少数据库 三,。结果当 df.to_sqlnew_表,con=db,如果_存在=append,index=False a。问题行没有被注释掉 b。上述代码将在新的_表中再次运行: $python3 example.py 5000, 22 5000, 22 5000, 22 1, 22 [*]总计:新_表中有20001行 因此,在运行第一次结果2时,我遇到了第一次代码中断的问题,第二次运行第二次结果3时,总行数是我预期的两倍多Python 使用df.to_sql()将块写入数据库时出错,python,pandas,sqlite,pandas-to-sql,Python,Pandas,Sqlite,Pandas To Sql,现有数据库和预期结果: 我有一个更大的SQLite数据库12gb,表中有4400多万行,我想在Python3中使用Pandas修改这些表 示例目标:我希望将这些大表中的4400万行以块的形式读入DF,操作DF块,并将结果写入新表。如果可能的话,我想替换新表(如果它存在),并将每个块追加到它 因为我的操作只添加或修改列,所以新表的行数应该与原始表的行数相同 问题: 主要问题似乎源于以下代码中的以下行: df.to_sqlnew_表,con=db,如果_存在=append,index=False 当
如果您对我如何解决此问题提出任何建议,我们将不胜感激。您可以尝试指定:
db = sqlite3.connect("test.db", isolation_level=None)
# ----> ^^^^^^^^^^^^^^^^^^^^
除此之外,您可以尝试增加chunksize,因为否则提交之间的时间是SQLite DB的一种缩短方式-我想这是导致此错误的原因。。。我还建议使用PostgreSQL、MySQL/MariaDB或类似的工具-它们更可靠,更适合这种数据库大小…上述解决方案中的时间延迟
@MaxU向数据库连接添加isolation_level=None的解决方案既短又甜。然而,无论出于何种原因,它都会大大降低将每个块写入/提交到数据库的速度。例如,当我在1200万行的表上测试解决方案时,代码花费了6个多小时才完成。相反,从几个文本文件构建原始表需要几分钟的时间
这一洞察导致了一个更快但不那么优雅的解决方案,在一个1200万行的表上完成该解决方案只需不到7分钟,而不是超过6小时。输出行与输入行匹配,解决了我原来问题中的问题
更快但不太优雅的解决方案
由于从文本文件/csv文件构建原始表并使用SQL脚本加载数据,因此我将该方法与Panda的块功能结合起来。基本步骤如下:
低点:
连接到数据库
使用SQL脚本创建一个新表,列和顺序应与您对表所做的任何操作相匹配
把这张庞大的表格分块读
对于每个区块,根据需要修改df,写入csv,使用sql加载csv,并提交更改。
解决方案的主要代码:
作为pd进口熊猫
导入sqlite3
注意:我使用了在build_db.py中编写的函数
在示例解决方案之后显示如下
从构建数据库导入*
示例中使用的Helper函数
def下_varvar,df:
s=df[var].str.lower
df=df.dropvar,轴=1
df=pd.concat[df,s],轴=1
返回DF
连接到数据
db=sqlite3.connecttest.db
c=db.cursor
创建语句
创建\u tablec,创建\u test.sql,path='sql\u clean/'
分块加载数据
df_generator=pd.read_sql_queryselect*来自示例_表;,con=db,chunksize=100000
对于df_发生器中的df:
用于修改数据的函数,例如
df=较低的变量名,df更改列顺序
将df恢复为sql表中的列顺序
db_order=[cmte_id,amndt_ind,rpt_tp,transaction_pgi,image_num,transaction_tp\
实体、名称、城市、州、邮政编码、雇主、职业、交易、\
交易金额、其他交易id、交易id、文件编号、备忘cd、备忘文本、子备忘id]
df=df[db_顺序]
将区块写入csv
file=df_chunk.csv
df.to_csvfile,sep='|',header=None,index=False
将区块csv插入数据库
将_文件_插入_tablec,插入_test.sql,文件“|”,path='sql_clean/'
db.commit
计数结果
计数结果,测试独立
为上述代码导入了用户函数
build_db.py中的相关函数
def计数结果,表:
[打印[*]总计:{}表中的{,}行
.formator[0],表
对于c.executeSELECT COUNT*中的r,从{};.formattable]中选择
def create_tablecursor,sql_脚本,path='sql/':
打印[*]使用{}{}.formatpath、sql\U脚本创建表
qry=打开{}{}.formatpath,sql_脚本'rU'。读取
cursor.executeDescriptory
def insert_file_插入_表格光标,sql_脚本,文件,sep=',',path='sql/':
打印[*]将{}插入到带有{}{}.formatfile、path、sql_脚本的表中
qry=打开{}{}.formatpath,sql_脚本'rU'。读取
fileObj=openfile'rU',encoding='latin-1'
csvReader=csv.readerfileObj,分隔符=sep,引号=
尝试:
对于csvReader中的行:
尝试:
cursor.executeqry,第行
除了sqlite3.IntegrityError作为e:
通过
例外情况除外,如e:
处理文件时打印[*]错误:{},错误代码:{}.formatfile,e
打印[*]sed替换文件{}.formatfile中的空字节
sed_replace_nullfile,clean_null.sh
subprocess.callbash clean_null.sh,shell=True
尝试:
打印[*]将{}插入到带有{}{}.formatfile、path、sql_脚本的表中
fileObj=openfile'rU',encoding='latin-1'
csvReader=csv.readerfileObj,分隔符=sep,引号=
对于csvReader中的行:
尝试:
cursor.executeqry,第行
除了sqlite3.IntegrityError作为e:
通过
版画
例外情况除外,如e:
处理文件时打印[*]错误:{},错误代码:{}.formatfile,e
SQL用户脚本
-创建_test.sql
如果存在测试独立,则丢弃表格;
创建表test_indiv
cmte_id文本不为空,
amndt_ind TEXT,
rpt_tp文本,
事务_pgi文本,
图像编号文本,
事务处理文本,
实体文本,
名称文本,
城市文本,
国家文本,
邮政编码文本,
雇主文本,
职业文本,
交易文本,
交易金额文本,
其他id文本,
传输id文本,
文件编号为数字,
备忘录和光盘文本,
备忘录文本,
子单元id数字不为空
;
在test_indiv sub_id上创建唯一索引idx_test_indiv;
-insert_test.sql
插入到测试中
cmte_id,
美国工业部,
rpt_tp,
交易记录,
图像_num,
交易记录,
实体,
名称
城市
状态
邮政编码,
雇用者
工作
交易日,
交易金额,
其他身份证,
tran_id,
文件编号,
备忘录(光碟),
备忘录文本,
子单元id
价值观
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?
;
在处理大于30 GB的数据时遇到了完全相同的问题。下面是我如何解决这个问题的: 而不是使用read_sql的块特性。我决定创建一个手动块循环器,如下所示:
chunksize=chunk_size
offset=0
for _ in range(0, a_big_number):
query = "SELECT * FROM the_table %s offset %s" %(chunksize, offset)
df = pd.read_sql(query, conn)
if len(df)!=0:
....
else:
break
是否只想重命名SQLite表中的列?@MaxU否,重命名函数只是一个示例修改。我想跨多个列执行一些复杂的操作,这些操作在Pandas中比SQL更容易执行=None@MaxU,太好了,这是第一次工作,并产生了预期的结果!我确实注意到,尽管最初失败的代码几乎会在瞬间运行
在第二次尝试中,使用您的解决方案,代码几乎有一个延迟,好像每个块都有一个时间。sleep8。有没有办法加快这一速度,或者我应该在计算机内存允许的情况下增加数据块大小?上面的一个警告是,数据块中额外插入的现象实际上没有得到解决,但如果执行的create sql脚本有一条创建唯一索引的语句,则最终表中的行总数是相同的。如果没有唯一索引,则代码有问题。