Python 从一个SQL数据库创建另一个SQL数据库时内存使用过度
我试图遍历一个SQLite数据库(我称之为数据库A),从其中的数据创建一些新变量,然后将这些新数据写入一个新的SQLite数据库(数据库B) 数据库A由表组成,这些表由关于特定月份特定术语的tweet组成(每个tweet及其元数据是一行,并且包括该月的每一天)。每个表的大小大约为0.5 GB 因此,我迭代这些表,创建一个变量,然后将这些新数据写入/提交到数据库B 问题是,在遍历几个表之后,我正在使用的服务器上的工作内存(我有16 GB的RAM)完全用完了(使用BASH中的Python 从一个SQL数据库创建另一个SQL数据库时内存使用过度,python,pandas,sqlite,Python,Pandas,Sqlite,我试图遍历一个SQLite数据库(我称之为数据库A),从其中的数据创建一些新变量,然后将这些新数据写入一个新的SQLite数据库(数据库B) 数据库A由表组成,这些表由关于特定月份特定术语的tweet组成(每个tweet及其元数据是一行,并且包括该月的每一天)。每个表的大小大约为0.5 GB 因此,我迭代这些表,创建一个变量,然后将这些新数据写入/提交到数据库B 问题是,在遍历几个表之后,我正在使用的服务器上的工作内存(我有16 GB的RAM)完全用完了(使用BASH中的free-m命令,我可以
free-m
命令,我可以看到大约一半的RAM被“buff/cache”使用)。这不会生成我在输出文件(通常显示Python错误消息)中看到的任何错误,但脚本停止运行
我认为这是SQLite()创建的临时文件的结果,随着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级别上这样做 Sqlite能够向当前连接附加一个额外的数据库,这允许在不同的数据库之间轻松复制表。由于您没有添加太多处理,pandas是相当无用的,
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()
这里唯一可能消耗资源的操作是selectdistinct
,它需要扫描整个表,以便在给定的一天只保留不同的行,但每次提交时都应该释放资源。这可能需要一些时间,具体取决于表的数量和大小,但不会崩溃
这个答案添加得太晚了,但我刚刚意识到有很多请求使用了
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 ###
...
我相信SQLite比熊猫更能节省内存。我多次成功地处理了大于可用内存的表,但当然我没有尝试同时加载内存中的所有内容(熊猫就是这么做的)。嗨,谢谢参与。我也有同样的想法,这就是为什么我在表中使用
pandas.read\u sql\u query()
按天查询,但即使这样,也可能读取整个表(由一个月中的所有天组成)。不过,奇怪的是,脚本在遍历了几个表之后失败了(不是在第一个表之后),这对我来说表明,问题不是读取带有熊猫的表,而是一些缓存系统的大小继续增长。不过,也许我错过了什么!我看到你没有关闭你的光标。它们有单独的资源分配。可能连接没有跟踪其游标,因此无法清理它们。所以也试着关闭它们。看看这是否有什么不同。我刚刚又看了一遍你的代码。有件事让我担心:您反复关闭并重新打开数据库连接。顺便说一句,如果关闭在数据库完全释放所有内容之前返回,那么它是无用的,甚至可能是有害的,因为它在下次打开时可能会出现问题。这可能就是发生的情况,因为我无法想象代码中有什么东西会占用这么多内存。buff/cache?别担心。它实际上与空闲内存相同。操作系统尝试使用任何可用内存缓存文件系统以提高性能。也就是说,从内存缓存中读取要比从磁盘中读取快。如果任何进程需要比“空闲”中更多的内存,那么buff/缓存中的内存将被释放,以便为进程让路。buff/cache占用了大量内存,这意味着您对许多或大型文件进行了大量的I/O操作——您就是这样。再次感谢您在这方面提供的帮助!我开始监控正在使用的内存,并在提取之前添加索引,从而大大减少了内存使用。