web-dev-qa-db-ja.com

既存のdbファイルをメモリにPython sqlite3?

既存のsqlite3 dbファイルがあり、その上で大規模な計算を行う必要があります。ファイルから計算を行うのは非常に遅く、ファイルが大きくないため(〜10 MB)、メモリにロードしても問題はありません。

計算を高速化するために、既存のファイルをメモリにロードするPython的な方法はありますか?

56
Adam Matan

flaskアプリケーション用に作成したスニペットは次のとおりです。

import sqlite3
from StringIO 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
108
Cenk Alti

sqlite3.Connection.iterdump "[r]イテレータを返してデータベースをSQLテキスト形式でダンプします。後で復元するためにメモリ内データベースを保存する場合に便利です。この関数はsqlite3の.dumpコマンドと同じ機能を提供しますシェル。"

そのようなイテレータを取得し、ディスクベースのデータベースをメモリベースのデータベースにダンプすれば、計算の準備が整います。計算が完了したら、逆方向にダンプしてディスクに戻します。

16
Fred Foo

まず、観察している速度低下の原因を調べてみてください。テーブルに書いていますか?書き込みは十分な大きさ transactions 内にあるので、不必要な一時結果をディスクに保存しませんか?書き込みを変更して一時テーブルに移動できますか( pragma temp_store=memory )? pragma synchronous=off

この機能はPythonモジュールで公開されているとは思いませんが、sqliteには backup API があります。あるデータベースから別のデータベース(メモリ内データベースのいずれか)に移動し、ユーザーに表示されるテーブルの列挙なしでほぼ​​自動的に動作します(多分 [〜#〜] apsw [〜#〜] これを公開しますか?)

別のオプションは、RAMディスクを作成し(環境を十分に制御できる場合)、そこにファイルをコピーすることです。

8

pythonラッパーを使用する必要がある場合、読み取りと書き込みの2つのパスよりも優れたソリューションはありません。しかし、バージョン3.7.17以降、SQLiteにはディスクコンテンツに直接アクセスするオプションがあります。メモリマップドI/Oを使用します。 sqlite mmap

mmapを使用する場合は、ラッパーが提供しないため、Cインターフェイスを使用する必要があります。

また、別のハードウェアソリューション、メモリdisk.thenがあります。便利なファイルIOとメモリの速度があります。

5
obgnaw

Pythonでは、接続する前にsqlite dbをメモリに完全にロードするにはどうすればよいですか? のコード例を含め、これはすでに回答されています

オペレーティングシステムについては言及しませんが、Windowsの1つの落とし穴XPは、メモリの量に関係なく、デフォルトで10MBのファイルキャッシュになります。このメッセージにはいくつかのリンクがあります:

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

4
Roger Binns

SQLite dbをメモリに読み込む比較的簡単な方法を次に示します。データの操作に関する設定に応じて、Pandas dataframeを使用するか、テーブルをメモリ内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')
4
Crooner

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)
4
thinwybk

Cenk Altiのソリューションでは、プロセスが500MBに達したときに、常にPython 3.7でMemoryErrorが発生しました。より大きなSQLiteデータベースをロードして保存するためにも、3行のコードで同じことを両方の方法で行うことができます。

0
wenga

sqliteはインメモリデータベースをサポートします。

Pythonでは、そのために:memory:データベース名を使用します。

おそらく、2つのデータベース(ファイルから1つ、メモリ内の空のデータベース)を開き、ファイルデータベースからすべてをメモリに移行し、メモリ内データベースをさらに使用して計算を実行できます。

0
jedi_coder