【发布时间】:2019-06-04 16:24:30
【问题描述】:
我正在尝试遍历一个 SQLite 数据库(我将其称为数据库 A),从其中的数据创建一些新变量,然后将这些新数据写入新的 SQLite 数据库(数据库 B)。
数据库 A 由表组成,这些表由有关特定月份的特定术语的推文组成(每条推文及其元数据都是一行,包括该月的每一天)。每个表的大小大约为 0.5 GB。
所以,我正在遍历这些表,创建一个变量,然后将这些新数据写入/提交到数据库 B。
问题是,在遍历几个表之后,我正在使用的服务器上的工作内存(我有 16 GB 的 RAM)完全用完了(使用 BASH 中的free -m 命令,我可以看到大约一半'buff / cache'正在使用RAM)。这不会产生任何我可以在输出文件中看到的错误(通常显示 Python 错误消息),但脚本会停止运行。
我认为这是由 SQLite (https://www.sqlite.org/tempfiles.html) 创建的临时文件的结果,随着 for 循环的继续,这些临时文件会继续增长。因此,我尝试逐日迭代表中的行,并在每天之后将新数据提交到数据库 B,以便删除回滚日志(见上面的链接)——这些临时 SQL 文件之一——被删除(从而释放内存)。但是,即使进行了这些更改,我也遇到了同样的问题(脚本停止)。
我不确定这里有多少代码会有所帮助,但这里是我正在做的事情的基本概述:
import sqlite3
import pandas
#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';")
### 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:
#open the databases
connection = sqlite3.connect("../SQL_database/Database_A.db3")
lite_cursor = connection.cursor()
connection_new = sqlite3.connect("../SQL_database/Database_B.db3")
lite_cursor_new = connection_new.cursor()
#change SQL query to match current day and term
sql_query = sql_query.replace('day', day)
#extract the data from the database and put it in the new database
for chunk in pandas.read_sql_query(sql_query, connection, chunksize = 10000):
### HERE I PROCESS THE DATA ###
#add the current data set to Database B
new_table = term
chunk.to_sql(new_table, connection_new, if_exists='append', index=True)
#redefine 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';")
#commit the changes
connection_new.commit()
#close the databases
connection.close()
connection_new.close()
当然,我想要的是让脚本运行时不会暂停/崩溃!有什么方法可以清除 SQLite 内存缓存,以便在 for 循环继续时 RAM 不会被吃掉?我以为 commit() 会释放一些内存,但显然它释放的不够。
提前谢谢你!
【问题讨论】:
-
我对 SQLite 比 Pandas 更有信心节省内存。我有很多次成功处理的表比我的可用内存大,但我当然没有尝试同时将所有内容加载到内存中(熊猫所做的)。
-
您好,感谢您的参与。我也想过同样的事情,这就是为什么我使用
pandas.read_sql_query()在表格中按天查询的原因,但也许即使这样仍然会读取整个表格(由一个月中的所有天组成)。尽管如此,奇怪的是脚本在遍历几个表后失败(不是在第一个表之后),这表明问题不是用 pandas 读取表,而是一些缓存系统继续增长尺寸。不过,也许我错过了什么! -
我看到您没有关闭光标。他们有单独的资源分配。也许连接没有跟踪它的游标,因此无法清理它们。所以尝试关闭它们。看看这是否有什么不同。
-
我刚刚再次查看了您的代码。有些事情让我担心:您反复关闭并重新打开数据库连接。 AFAIK,如果在数据库完全释放所有内容之前关闭返回,它无用甚至可能有害,因为它可能在下次打开时出现问题。这可能是发生的事情,因为我无法想象你的代码中的什么会吃掉这么多内存。
-
buff/缓存?别担心。它实际上与空闲内存相同。操作系统尝试使用任何可用内存来缓存文件系统以提高性能。也就是说,从内存缓存读取比从磁盘读取要快。如果任何进程需要比“空闲”更多的内存,则释放缓冲区/缓存中的内存以为进程让路。 buff/cache 使用大量内存仅意味着您在许多或大文件上执行大量 I/O —— 您就是这样。