当前位置:  开发笔记 > 编程语言 > 正文

我是否需要多个游标对象来循环记录集并同时更新?

如何解决《我是否需要多个游标对象来循环记录集并同时更新?》经验,为你挑选了0个好方法。

所以我有一个大型数据库,我无法立即在内存中保存.我必须遍历表中的每个项目,处理它,并将处理后的数据放入表中的另一列.

当我循环我的光标时,如果我尝试运行更新语句,它会截断记录集(我相信因为它重新定位了游标对象).

问题:

创建第二个游标对象以运行更新语句是否允许我继续循环原始的select语句?

我是否需要与数据库建立第二个连接才能拥有第二个游标对象,这样我才能这样做?

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粘贴processed_content,这样我每个数据库都有一个连接/游标对象,并且可以继续循环选定的记录集,同时定期插入临时数据库.一旦我到达所选记录集的末尾,我将临时数据库中的数据传回原始数据库.

如果有人确切知道连接/光标对象,请在评论中告诉我.

推荐阅读
sx-March23
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有