从另一个数据库创建一个SQL数据库时,内存使用过多

时间:2019-06-04 16:24:30

标签: python pandas sqlite

我试图遍历一个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()会释放一些内存,但是显然释放得不够。

提前谢谢!

1 个答案:

答案 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 ###
...