簡體   English   中英

如何將現有的 db 文件加載到 Python sqlite3 中的內存中?

[英]How to load existing db file to memory in Python sqlite3?

我有一個現有的sqlite3 db 文件,我需要對其進行一些廣泛的計算。 從文件中進行計算非常緩慢,而且由於文件不大(~ 10 MB ),因此將其加載到內存中應該沒有問題。

是否有一種 Pythonic 方式將現有文件加載到內存中以加快計算速度?

這是我為我的燒瓶應用程序編寫的代碼片段:

import sqlite3
from io import StringIO

def init_sqlite_db(app):
    # Read database to tempfile
    con = sqlite3.connect(app.config['SQLITE_DATABASE'])
    tempfile = StringIO()
    for line in con.iterdump():
        tempfile.write('%s\n' % line)
    con.close()
    tempfile.seek(0)

    # Create a database in memory and import from tempfile
    app.sqlite = sqlite3.connect(":memory:")
    app.sqlite.cursor().executescript(tempfile.read())
    app.sqlite.commit()
    app.sqlite.row_factory = sqlite3.Row

sqlite3.Connection.backup(...)呢? “這種方法可以備份 SQLite 數據庫,即使它正在被其他客戶端訪問,或者由同一連接同時訪問。” 可用性:SQLite 3.6.11 或更高版本。 3.7 版中的新功能。

import sqlite3

source = sqlite3.connect('existing_db.db')
dest = sqlite3.connect(':memory:')
source.backup(dest)

sqlite3.Connection.iterdump "[r] 返回一個迭代器,以 SQL 文本格式轉儲數據庫。在保存內存數據庫以供以后恢復時很有用。此函數提供與 sqlite3 shell 中的.dump命令相同的功能。 ”

獲得這樣的迭代器並將基於磁盤的數據庫轉儲到基於內存的數據庫中,然后您就可以開始計算了。 計算完成后,只需將其他方式轉儲回磁盤。

首先,您應該嘗試找出導致您觀察到的緩慢的原因。 你在寫表嗎? 您的寫入是否在足夠大的事務中,以便您不會將不必要的臨時結果保存到磁盤? 您可以更改寫入以轉到臨時表(使用pragma temp_store=memory )嗎? 你能接受pragma synchronous=off嗎?

我不認為這個功能在 Python 模塊中公開,但 sqlite 有一個備份 API ,聽起來正是你所要求的:一種從一個數據庫復制到另一個數據庫的方法(其中一個可能是內存中的數據庫)幾乎可以自動工作,無需任何用戶可見的表枚舉。 (也許APSW暴露了這一點?)

另一種選擇是創建一個 ram 磁盤(如果您對環境有足夠的控制權)並將文件復制到那里。

如果我們必須使用 python 包裝器,那么沒有比兩遍讀取和寫入解決方案更好的解決方案。 但是從 3.7.17 版本開始,SQLite 可以選擇使用內存映射 I/O 直接訪問磁盤內容。 sqlite mmap

如果你想使用 mmap,你必須使用 C 接口,因為沒有包裝器提供它。

還有另一種硬件解決方案,內存盤。那么你有方便的文件IO和內存速度。

這是一種將 SQLite 數據庫讀入內存的相對簡單的方法。 根據您在操作數據方面的偏好,您可以使用 Pandas 數據框或將表寫入內存中的 sqlite3 數據庫。 同樣,在操作數據后,您使用相同的 df.to_sqlite 方法將結果存儲回 db 表。

import sqlite3 as lite
from pandas.io.sql import read_sql
from sqlalchemy import create_engine

engine = create_engine('sqlite://')
c = engine.connect()
conmem = c.connection
con = lite.connect('ait.sqlite', isolation_level=None) #Here is the connection to <ait.sqlite> residing on disk
cur = con.cursor()
sqlx = 'SELECT * FROM Table'
df = read_sql(sqlx, con, coerce_float=True, params=None) 

#Read SQLite table into a panda dataframe
df.to_sql(con=conmem, name='Table', if_exists='replace', flavor='sqlite')

之前已經回答過這個問題,包括在 Python 中的代碼示例,如何在連接之前將 sqlite db 完全加載到內存中?

你沒有提到操作系統,但 Windows XP 的一個問題是它默認為 10MB 的文件緩存,無論你有多少內存。 (這在系統帶有 64MB 等的時代是有意義的)。 此消息有幾個鏈接:

http://marc.info/?l=sqlite-users&m=116743785223905&w=2

sqlite 支持內存數據庫。

在 python 中,您將使用:memory:數據庫名稱。

也許您可以打開兩個數據庫(一個來自文件,一個在內存中),將文件數據庫中的所有內容遷移到內存中,然后進一步使用內存數據庫進行計算。

使用Cenk Alti的解決方案,我用Python 3.7總是出現MemoryError,當進程達到500MB時。 只有使用 sqlite3 的備份功能(thinwybk 提到),我才能加載和保存更大的 SQLite 數據庫。 你也可以用 3 行代碼來做同樣的事情,兩種方式。

@thinwybkCrooner的回答都很棒。

當您有多個連接到:memory: sqlite 數據庫時,例如將 SQLAlchemy 與source.backup(dest)函數一起使用時,您最終可能不會將備份放入“正確”的內存數據庫中。

這可以使用正確的連接字符串來修復: https : //stackoverflow.com/a/65429612/1617295並且不涉及任何黑客而不是使用未記錄的功能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM