我试图遍历一个SQLite数据库(我将其称为数据库A),从其中的数据创建一些新变量,然后将这些新数据写入新的SQLite数据库(数据库B)。
数据库A由表组成,这些表由有关某个月特定术语的推文组成(每个推文及其元数据都是一行,并且包含每月的每一天)。每个表的大小约为0.5 GB。
因此,我要遍历这些表,创建一个变量,然后将此新数据写入/提交到数据库B。
问题是,经过几个表的迭代之后,我正在使用的服务器上的工作内存(我有16 GB的RAM)被完全耗尽(使用BASH中的keyword
命令),我可以看到大约一半的RAM被'buff / cache'使用)。这不会产生我在输出文件中看到的任何错误(通常会显示Python错误消息),但是脚本会停止运行。
我认为这是SQLite(https://www.sqlite.org/tempfiles.html)创建的临时文件的结果,该临时文件随着for循环的继续而继续增长。因此,我试图逐日遍历表中的行,并每天之后将新数据提交到数据库B,以便删除回滚日志(请参见上面的链接)-这些临时SQL文件之一-(从而释放内存)。但是,即使进行了这些更改,我仍然遇到相同的问题(脚本停止运行)。
我不确定这里有多少代码可以帮助您,但是这是我正在做的事情的基本概述:
free -m
当然,我想要的是脚本运行时不会暂停/崩溃!有什么方法可以清除SQLite内存缓存,以便在for循环继续时不会耗尽RAM?我以为commit()会释放一些内存,但是显然释放得不够。
提前谢谢!
答案 0 :(得分:1)
我会尝试直接在sqlite级别上做到这一点。
Sqlite可以将其他数据库附加到当前连接,从而可以轻松地在不同数据库之间复制表。由于您没有添加太多处理程序,因此熊猫是无用的,ATTACH DATABASE
应该足够了:
import sqlite3
#this defines the SQL query; [long list of columns] is just comma separated column names: id, date, time, etc.
sql_query = ("SELECT DISTINCT [long list of columns] "
"FROM term "
"WHERE date = 'day';")
#open the databases
connection = sqlite3.connect("../SQL_database/Database_A.db3")
connection.execute("ATTACH DATABASE '../SQL_database/Database_B.db3' as db_B")
### HERE I GET ALL TABLES IN DATABASE A ###
#go through all the tables in Database A
for t in tables:
term = t
### HERE I GET THE DAYS IN THE CURRENT TABLE ###
#go through each day in the current table in Database A
for day in days:
#change SQL query to match current day and term
# but don't change original query because we'll need it on next iteration
sql_query2 = sql_query.replace('day', day)
sql_query2 = sql_query2.replace('term', term)
# print(sql_query2, end=' ') # uncomment to make sure of what happens
# copy table values
try:
connection.execute("INSERT INTO db_B.{} ".format(term) + sql_query2)
# print('inserted') # uncomment for traces
except sqlite3.OperationalError: # table does not exists
connection.rollback()
connection.execute("CREATE TABLE db_B.{} AS ".format(term) + sql_query2)
# print('created') # uncomment for traces
connection.commit()
connection.close()
这里唯一可能的资源消耗操作是SELECT DISTINCT
,它需要扫描整个表以在给定的一天中仅保留不同的行,但是应该在每次提交时释放资源。可能要花一些时间,具体取决于表的数量和大小,但这不会崩溃。
除了这个答案之外,我刚刚意识到有很多使用DISTINCT
关键字和WHERE date =
的请求。索引可以大大提高数据库性能。在提取信息之前添加索引将对时间和内存产生重大影响:
...
for t in tables:
term = t
connection.execute("CREATE INDEX IF NOT EXISTS I{0} ON {0}(date)"
.format(term))
### HERE I GET THE DAYS IN THE CURRENT TABLE ###
...