web-dev-qa-db-ja.com

SQLiteのメモリ消費を減らす方法は?

アプリケーションでSQLite3によるメモリ消費を削減する方法を探しています。

実行するたびに、次のスキーマでテーブルが作成されます。

(main TEXT NOT NULL PRIMARY KEY UNIQUE,count INTEGER DEFAULT 0)

その後、データベースは1秒あたり5万回の操作でいっぱいになります。書き込みのみ。

アイテムがすでに存在する場合、更新クエリを使用して「カウント」を更新します(これはUPSERTと呼ばれると思います)。これらは私の質問です:

INSERT OR IGNORE INTO table (main) VALUES (@SEQ);
UPDATE tables SET count=count+1 WHERE main = @SEQ;

このように、トランザクションごとに500万回の操作で、DBに非常に高速に書き込むことができます。

この問題のディスク容量はあまり気にしませんが、RAMの容量には非常に制約があります。したがって、メモリを浪費することはできません。

Sqlite3_user_memory()を使用すると、実行中にメモリ消費量がほぼ3GBに増加することが通知されます。 sqlite3_soft_heap_limit64()を使用して2GBに制限すると、2GBに達すると、データベース操作のパフォーマンスがほぼゼロに低下します。

望ましいパフォーマンスを実現するには、キャッシュサイズを1M(ページサイズがデフォルト)に増やす必要がありました。

メモリ消費を減らすために何ができますか?

15
Pedro Alves

私は...するだろう:

  • ステートメントを準備します(まだ行っていない場合)
  • トランザクションあたりのINSERTの量を減らします(10秒= 500,000が適切と思われます)
  • 可能であればPRAGMA locking_mode = EXCLUSIVE;を使用してください

また、(ご存知かどうかはわかりませんが)PRAGMA cache_sizeはMB単位ではなく、ページ単位です。ターゲットメモリをPRAGMA cache_size * PRAGMA page_sizeとして定義するか、SQLite> = 3.7.10でPRAGMA cache_size = -kibibytes;を実行することもできます。 1 M(illion)に設定すると、1GBまたは2GBになります。

cache_sizeがINSERTでどのように役立つのか興味があります...

PRAGMA temp_store = FILE;が違いを生む場合は、ベンチマークを試すこともできます。

そしてもちろん、データベースが書き込まれていないときはいつでも:

  • PRAGMA shrink_memory;
  • VACUUM;

データベースで何をしているかによっては、次のことも役立つ場合があります。

  • PRAGMA auto_vacuum = 1|2;
  • PRAGMA secure_delete = ON;

次のプラグマを使用していくつかのテストを実行しました。

busy_timeout=0;
cache_size=8192;
encoding="UTF-8";
foreign_keys=ON;
journal_mode=WAL;
legacy_file_format=OFF;
synchronous=NORMAL;
temp_store=MEMORY;

テスト#1:

INSERT OR IGNORE INTO test (time) VALUES (?);
UPDATE test SET count = count + 1 WHERE time = ?;

ピーク時の1秒あたりの更新数は約109kです。

テスト#2:

REPLACE INTO test (time, count) VALUES
(?, coalesce((SELECT count FROM test WHERE time = ? LIMIT 1) + 1, 1));

1秒あたり最大12万回の更新でピークに達しました。


また、PRAGMA temp_store = FILE;を試しましたが、更新は1秒あたり約1〜2k減少しました。


トランザクションでの7Mの更新の場合、journal_mode=WALは他のすべての更新よりも遅くなります。


データベースに35,839,987レコードを入力しましたが、セットアップには65521更新のバッチごとに約4秒かかりますが、16MBのメモリ消費にも達していません。


わかりました、ここにもう1つあります:

INTEGER PRIMARY KEY列のインデックス(実行しないでください)

INTEGER PRIMARY KEYを使用して列を作成すると、SQLiteはこの列をテーブル構造のキー(インデックス)として使用します。これは、この列の非表示のインデックスです(SQLite_Masterテーブルには表示されないため)。列に別のインデックスを追加する必要はなく、使用されることはありません。さらに、INSERT、DELETE、およびUPDATE操作の速度が低下します。

PKをNOTNULL + UNIQUEとして定義しているようです。 PKは暗黙的にUNIQUEです。

4
Alix Axel

メモリ消費量が多いのは、1つの大きなトランザクションに集中している操作が多すぎることが原因のようです。 100万回の操作のように、より小さなトランザクションをコミットしようとすると役立つ場合があります。トランザクションあたり500万回の操作は、多くのメモリを消費します。

ただし、操作速度とメモリ使用量のバランスを取ります。

小さいトランザクションは役に立たないので、_PRAGMA shrink_memory_が選択かもしれません。

sqlite3_status()と_SQLITE_STATUS_MEMORY_USED_を使用して、動的メモリ割り当てをトレースし、ポイントを特定します。

11
Peixu Zhu

1つのトランザクションのすべての操作がテーブル全体に分散されているため、テーブルのすべてのページにアクセスする必要があるとすると、ワーキングセットのサイズは次のようになります。

  • テーブルのデータ用に約1GB、さらに
  • main列のインデックスに約1GB、さらに
  • トランザクションで変更されたすべてのテーブルのページの元のデータ(おそらくすべて)の約1GB。

count列を別のテーブルに移動することで、操作ごとに変更されるデータの量を減らすことができます。

CREATE TABLE main_lookup(main TEXT NOT NULL UNIQUE, rowid INTEGER PRIMARY KEY);
CREATE TABLE counters(rowid INTEGER PRIMARY KEY, count INTEGER DEFAULT 0);

次に、各操作について:

SELECT rowid FROM main_lookup WHERE main = @SEQ;
if not exists:
    INSERT INTO main_lookup(main) VALUES(@SEQ);
    --read the inserted rowid
    INSERT INTO counters VALUES(@rowid, 0);
UPDATE counters SET count=count+1 WHERE rowid = @rowid;

Cでは、挿入されたrowidsqlite3_last_insert_rowid で読み取られます。

SELECTINSERTを別々に実行することは、INSERT OR IGNOREよりも遅くはありません。 SQLiteはどちらの場合も同じ作業を行います。

この最適化は、ほとんどの操作が既存のカウンターを更新する場合にのみ役立ちます。

4
CL.

ブレーンストーミングの精神で、私は答えを冒険します。私はこの仲間のようなテストをしていません:

SQLiteの1秒あたりのINSERTのパフォーマンスを向上させますか?

私の仮説は、テキストの主キーのインデックスは、2つの整数列のいくつかのインデックス(ハッシュテーブルをシミュレートするために必要なもの)よりもRAMを集中的に使用する可能性があるというものです。

編集:実際には、これには主キーさえ必要ありません:

      create table foo( slot integer, myval text, occurrences int);
      create index ix_foo on foo(slot);  // not a unique index

整数の主キー(またはスロットの一意でないインデックス)では、テキスト値がすでにファイルにあるかどうかをすばやく判断する方法がありません。したがって、その要件に対処するために、ハッシュキーをシミュレートして、別の投稿者に提案したものを実装してみてください。

数百万のエントリに対するSQLiteの最適化?

ハッシュキー関数を使用すると、テキスト値が存在する場合に格納される場所を決定できます。

http://www.cs.princeton.edu/courses/archive/fall08/cos521/hash.pdfhttp://www.fearme.com/misc/alg/node28。 htmlhttp://cs.mwsu.edu/~griffin/courses/2133/downloads/Spring11/p677-pearson.pdf

1
Tim