python在sqlite3 db中插入大元素 - 内存错误

时间:2011-01-07 09:44:45

标签: python memory sqlite

我在python中进行数值模拟,导致相当大的数据对象(大约200 MB)。我把它们写入sqlite3 db。在将分辨率(以及数据大小)提高约20%后,我在尝试插入数据库时​​出现内存错误。以前使用较小的分辨率工作得很好。这是一段代码:

def write_to_db(self, filename, dataObject, name) :
    connection  = sqlite.connect(filename)
    cursor      = connection.cursor()
    cursor.execute("CREATE TABLE pulses (ID INTEGER PRIMARY KEY, name STRING, data BLOB)")
    cursor.execute("INSERT INTO pulses(name, data) VALUES (?, ?)", (dataObjectName, sqlite.Binary(pickle.dumps(dataObject))))
    connection.commit()
    connection.close()

我正在使用winXP,1GB内存,3GB交换(并且没有收到需要扩展交换的Windows通知),Python 2.6。

提前感谢您的帮助。 添

2 个答案:

答案 0 :(得分:1)

请注意,XP只会以较小的增量增加交换。如果您的程序突然尝试使用更多内存并且没有足够的交换,那么您将收到内存错误。

SQLite可以很好地使用大小达1GB的blob,你通常可以使用2GB。但是,您将在32位进程中耗尽地址空间。

对于较大的项目,通常建议您将大数据存储在一个文件中,然后将文件名存储在数据库中,但这对您来说更有用。

您可以通过执行以下操作来解决您的紧急问题:

  • 切换到使用64位。微软出售Windows 7家庭套装,其中包括3个XP / Vista实例的升级,价格为150美元(街头售价130美元),因此您可以升级多台机器。您可以通过这种方式从32位XP切换到64位Win 7。即使你没有改变RAM的数量,这样做也会立即解决你的问题。

  • 向pickle调用添加-1,告诉它使用最新的pickle协议,该协议使用二进制而不是ascii默认编码。结果会得到更少的数据。阅读文档以获取有关协议版本以及哪些Python版本支持它们的更多信息。

  • 同时压缩pickle数据 - 例如bz2.compress(pickle.dumps(obj,-1)

此处出现问题的最可能原因是地址空间不足。 32位进程通常只能同时处理2GB数据,并且还从该空间中减去各个可执行文件和共享库,每个线程的堆栈,SQLite缓存等。您需要特别注意所有各种数据项以及它们何时存活。主动完成调用del和gc.collect()将有助于减少正在使用的并发数据量。

答案 1 :(得分:0)

您在评论中询问可能的替代存储机制。如果您存储的数据是可用RAM的五分之一,我会说您需要非常小心地管理内存,因为在RAM耗尽之前您无法复制数据;无论如何,你将会杀死表演。您可以通过BLOB获得sqlite为您做正确的事情,因为它们可能会很大。

看起来您正在使用sqlite作为简单的键/值存储。你考虑过使用平面文件吗?如果您需要ATOMicity,您仍然可以使用sqlite数据库来定义平面文件存储中的哪些文件是有效的。您可以通过在完全写入所有平面文件之后提交到​​数据库并在仅在数据库中提交相应的删除后删除平面文件来安全地执行此操作。

为了使这项工作,您需要一些机制来将您的dataObject序列化为Python中的文件类型对象。如果你传递一个文件类型的对象,Pickle可以为你做这件事,但我怀疑它仍然是非常低效的。

你说你在进行数值模拟;你知道numpy吗? numpy数组支持tofile函数,它比pickling更有效,如果你没有使用它,你可能会在模拟中获得显着的性能提升。