Python 迭代大量sqlite3记录时临时存储已满

Python 迭代大量sqlite3记录时临时存储已满,python,python-3.x,sqlite,Python,Python 3.x,Sqlite,我有一个很大的SQLite数据库,在这里我将一个3.5M行的表连接到它自己。我使用SQLite,因为它是python3应用程序的序列化格式,而平面文件格式在我的工作流中很重要。当使用以下方法迭代此联接的行(约55M行)时: 解释查询计划给出以下内容: 0|0|0|SCAN TABLE proteins AS p USING INDEX pid_index (~1000000 rows) 0|1|1|SEARCH TABLE proteins AS pp USING INDEX pname_ind

我有一个很大的SQLite数据库,在这里我将一个3.5M行的表连接到它自己。我使用SQLite,因为它是python3应用程序的序列化格式,而平面文件格式在我的工作流中很重要。当使用以下方法迭代此联接的行(约55M行)时:

解释查询计划
给出以下内容:

0|0|0|SCAN TABLE proteins AS p USING INDEX pid_index (~1000000 rows)
0|1|1|SEARCH TABLE proteins AS pp USING INDEX pname_index (pname=?) (~10 rows)
0|0|0|USE TEMP B-TREE FOR DISTINCT
sqlite3错误,在1.000.000行之后出现“数据库或磁盘已满”,这似乎表示磁盘tempstore上的SQLite已满。因为我的当前盒上有足够的RAM,可以通过将tempstore设置为内存中来解决,但这是次优的,因为在这种情况下,所有RAM似乎都用完了,我倾向于并行运行4个左右的进程。我(可能不正确)的假设是迭代器是一个生成器,不会给内存带来很大的负载,不像fetchall那样会加载所有行。然而,我现在用完了磁盘空间(在一个小的SSD暂存盘上),并假设SQLite需要将结果存储在某个地方


解决这个问题的一种方法可能是运行
SELECT。。。限制x偏移量y
查询,但每次使用较大的
偏移量时,查询速度会变慢。还有别的办法吗?这些临时文件中存储了什么?它们似乎随着我迭代的深入而增长。

您试图用SQLite3做的是一个非常糟糕的主意,让我来解释一下原因

您可以在磁盘上找到适合的、可读的原始数据

您将在SQLite3内部生成一个结果,该结果将大大扩展

然后尝试通过sql连接器传输这个非常大的数据集

一般来说,关系数据库不适合这种操作。SQLite3也不例外。关系数据库是为小而快速的查询而建立的,这些查询只持续几秒钟,并返回几行

你最好使用另一种工具

我建议使用例如将整个数据集读入python。使用也是一个好主意

0|0|0|USE TEMP B-TREE FOR DISTINCT
这是磁盘的用途

为了支持
DISTINCT
,SQLite必须存储查询中已经出现的行。对于大量的结果,这个集合可能会变得巨大。因此,为了在RAM上保存,SQLite将在磁盘上临时存储不同的集合


删除
DISTINCT
子句是避免问题的简单方法,但它会改变查询的含义;现在可以获得重复的行。如果你不介意这一点,或者你有唯一的索引或其他确保你永远不会得到重复的方法,那就没关系了。

如果你只在循环中通过
是否也会发生这种情况?是的,即使只是迭代结果也能奏效。你在
pid
上有索引吗?你能发布
解释查询计划的输出吗?@collonelthirtytwo补充说,我还忘了一个
不同的
,表是在pname而不是pid上连接的,应该复制粘贴它而不是键入。pid和pname都被索引。看到输出,是否是DISTINCT生成了临时文件;SQLite需要将已经访问过的值集存储在某个地方,即
使用TEMP B-TREE作为DISTINCT
条目。SQLite会将它交换到磁盘,如果它变得太大。SQL一般不适合这种操作嗯,是的,它是;SQL是为有效处理大量表格数据和联接而设计的。我更新了我的答案,但我仍然认为你错了。SQL作为一种语言并没有考虑数据量。这只是一种抽象,“SQL作为一种语言”与您需要的数据量完全无关;您只需指定“我需要此数据,将其与此连接,并且仅当它符合这些条件时”。大多数数据库(包括SQLite)都有查询计划器来找出执行SQL查询的最佳方式;为什么要费心为几行使用查询计划器呢?此外,SQLite根据需要从磁盘读取数据;您将如何将一个数GB的数据集加载到内存中?”“SQL作为一种语言”与您需要的数据量完全无关“这基本上就是我所说的,所以我们同意。即使只想返回一行,也需要查询计划器。我认为在这种情况下,它们是最有效的。但所有查询计划器都是不同的。例如,Redshift有一个适合于大量数据的查询计划器,他们更改了PostgreSQLs查询计划器以更适合这个目的。最后,一个id和名称为3.5Mil的数据集甚至不是一个千兆字节。更像是几兆字节。但是在连接之后,它会变大。如果您只想支持在索引中查找几行,则不需要查询计划器。您确实需要一个连接来有效地支持复杂的连接,您的意思是不应该在SQL中完成。SQLite不会将整个结果保存在内存中;连接的行将根据需要获取,如果不需要,则将被丢弃。添加更多联接只会增加查询时间,而不是资源使用量。
0|0|0|USE TEMP B-TREE FOR DISTINCT