因此,我有一个无法立即保存在内存中的大型数据库。我必须遍历表中的每个项目,对其进行处理,然后将处理后的数据放入表中的另一列。
当我在游标上循环时,如果我尝试运行更新语句,它会截断记录集(我相信是因为它重新利用了游标对象)。
问题:
创建第二个游标对象来运行更新语句是否允许我继续循环原始选择语句?
我是否需要第二个与数据库的连接才能拥有第二个游标对象,这将允许我这样做吗?
sqlite 将如何响应与数据库的两个连接,一个从表中读取,另一个向它写入?
我的代码(简化):
import sqlite3
class DataManager():
""" Manages database (used below).
I cut this class way down to avoid confusion in the question.
"""
def __init__(self, db_path):
self.connection = sqlite3.connect(db_path)
self.connection.text_factory = str
self.cursor = self.connection.cursor()
def genRecordset(self, str_sql, subs=tuple()):
""" Generate records as tuples, for str_sql.
"""
self.cursor.execute(str_sql, subs)
for row in self.cursor:
yield row
select = """
SELECT id, unprocessed_content
FROM data_table
WHERE processed_content IS NULL
"""
update = """
UPDATE data_table
SET processed_content = ?
WHERE id = ?
"""
data_manager = DataManager(r'C:\myDatabase.db')
subs = []
for row in data_manager.genRecordset(str_sql):
id, unprocessed_content = row
processed_content = processContent(unprocessed_content)
subs.append((processed_content, id))
#every n records update the database (whenever I run out of memory)
if len(subs) >= 1000:
data_manager.cursor.executemany(update, subs)
data_manager.connection.commit()
subs = []
#update remaining records
if subs:
data_manager.cursor.executemany(update, subs)
data_manager.connection.commit()
我尝试的另一种方法是将我的 select 语句修改为:
select = """
SELECT id, unprocessed_content
FROM data_table
WHERE processed_content IS NULL
LIMIT 1000
"""
然后我会这样做:
recordset = data_manager.cursor.execute(select)
while recordset:
#do update stuff...
recordset = data_manager.cursor.execute(select)
我遇到的问题是我真正的select 语句中有一个 JOIN 并且需要一段时间,因此多次执行 JOIN 非常耗时。我试图通过只做一次选择来加快这个过程,然后使用一个生成器,这样我就不必把它全部保存在内存中。
解决方案:
好的,所以我的前两个问题的答案是“否”。对于我的第三个问题,一旦与数据库建立连接,它就会锁定整个数据库,因此在第一个连接关闭之前,另一个连接将无法执行任何操作。
我找不到它的源代码,但从经验证据来看,我相信连接一次只能使用一个游标对象,并且最后一次运行查询优先。这意味着,当我循环选择的记录集一次产生一行时,一旦我运行我的第一个更新语句,我的生成器就会停止产生行。
我的解决方案是创建一个临时数据库,我将已处理的内容与 id 一起插入,以便每个数据库都有一个连接/光标对象,并且可以继续循环遍历选定的记录集,同时定期插入临时数据库。一旦我到达我选择的记录集的末尾,我就会将临时数据库中的数据传输回原始数据库。
如果有人确切知道连接/光标对象,请在评论中告诉我。