web-dev-qa-db-ja.com

非常に大きなデータベースファイルを使用したsqliteのパフォーマンス特性は何ですか?

Sqliteは、サポートされている場合でも非常に大きなデータベースファイルではうまく機能しないことを知っています(sqlite Webサイトで、1GBを超えるファイルサイズが必要な場合は、エンタープライズRDBMSの使用を検討する必要があるというコメントがありました)もはや見つかりません。古いバージョンのsqliteに関連している可能性があります)。

しかし、私の目的のために、他の解決策を検討する前に、それがどれほど悪いのかを知りたいと思います。

私は2ギガバイトから数ギガバイトの範囲のsqliteデータファイルについて話している。誰もこれで経験がありますか?ヒント/アイデアはありますか?

310
Snazzer

そのため、非常に大きなファイルに対してsqliteでいくつかのテストを行い、いくつかの結論に達しました(少なくとも特定のアプリケーションについて)。

テストには、単一のテーブルまたは複数のテーブルのいずれかを持つ単一のsqliteファイルが含まれます。各テーブルには、約8列、ほぼすべての整数、および4つのインデックスがありました。

アイデアは、sqliteファイルが約50GBになるまで十分なデータを挿入することでした。

単一テーブル

1つのテーブルだけで、複数の行をsqliteファイルに挿入しようとしました。ファイルが約7GBだったとき(行数について詳しくは言えませんが)、挿入に時間がかかりすぎていました。すべてのデータを挿入するテストには24時間程度かかると推定していましたが、48時間後でも完了しませんでした。

これにより、単一の非常に大きなsqliteテーブルには挿入に関する問題があり、おそらく他の操作にも問題があると結論付けられます。

テーブルが大きくなり、すべてのインデックスの挿入と更新に時間がかかるため、これは驚くことではないと思います。

複数のテーブル

次に、データを時間ごとに複数のテーブルに分割してみました(1日に1つのテーブル)。元の1つのテーブルのデータは、約700のテーブルに分割されました。

この設定では挿入に問題はなく、毎日新しいテーブルが作成されるため、時間が経過しても長くはかかりませんでした。

真空の問題

I_like_caffeineが指摘したように、VACUUMコマンドは、sqliteファイルが大きくなると問題になります。より多くの挿入/削除が行われると、ディスク上のファイルの断片化が悪化するため、目標は定期的にVACUUMを実行してファイルを最適化し、ファイル領域を回復することです。

ただし、 documentation で指摘されているように、データベースの完全なコピーが作成されてバキュームが行われ、完了するまでに非常に長い時間がかかります。そのため、データベースが小さいほど、この操作は速く終了します。

結論

私の特定のアプリケーションでは、バキュームパフォーマンスと挿入/削除速度の両方を最大限に活用するために、おそらく1日に1つのデータを複数のdbファイルに分割します。

これはクエリを複雑にしますが、私にとっては、これだけのデータにインデックスを付けることができるのは価値のあるトレードオフです。追加の利点は、dbファイル全体を削除するだけで1日分のデータを削除できることです(アプリケーションの一般的な操作)。

速度が問題になる時期を確認するには、ファイルごとのテーブルサイズも監視する必要があります。

自動バキューム 以外のインクリメンタルバキュームメソッドがないように見えるのは残念です。バキュームの目的はファイルを最適化することなので(ファイルスペースは大したことではありません)、自動バキュームは行いません。実際、文書化は断片化を悪化させる可能性があると述べているため、定期的にファイルを完全に削除する必要があります。

231
Snazzer

プラットフォームで50 GB以上のDBSを使用しています。申し分なく機能しません。すべてを正しく行っていることを確認してください!事前定義されたステートメントを使用していますか? * SQLITE 3.7.3

  1. 取引
  2. 事前に作成された声明
  3. これらの設定を適用します(DBを作成した直後)

    PRAGMA main.page_size = 4096;
    PRAGMA main.cache_size=10000;
    PRAGMA main.locking_mode=EXCLUSIVE;
    PRAGMA main.synchronous=NORMAL;
    PRAGMA main.journal_mode=WAL;
    PRAGMA main.cache_size=5000;
    

これが他の人を助け、ここでうまくいくことを願っています

155
Alex

顕著なパフォーマンスの問題なしに、最大3.5GBのサイズのSQLiteデータベースを作成しました。正しく覚えていれば、SQLite2にはいくつかの下限があったと思いますが、SQLite3にそのような問題があるとは思いません。

SQLite Limits ページによると、各データベースページの最大サイズは32Kです。また、データベースの最大ページは1024 ^ 3です。したがって、私の計算では、最大サイズとして32テラバイトになります。 SQLiteの制限を超える前に、ファイルシステムの制限に達すると思います。

62
Paul Lefebvre

挿入に48時間以上かかった理由の多くは、インデックスが原因です。信じられないほど高速です:

1-すべてのインデックスを削除2-すべての挿入を実行3-インデックスを再度作成

50
user352992

通常の推奨に加えて:

  1. 一括挿入のインデックスを削除します。
  2. 大規模なトランザクションでのバッチの挿入/更新。
  3. バッファキャッシュを調整するか、ジャーナル/ w PRAGMAを無効にします。
  4. 64ビットマシンを使用します(多くのcache™を使用できるようにするため)。
  5. [2014年7月追加]複数のSQLクエリを実行する代わりに、 共通テーブル式(CTE) を使用してください。 SQLiteリリース3.8.3が必要です。

SQLite3の経験から次のことを学びました。

  1. 挿入速度を最大にするには、列制約のあるスキーマを使用しないでください。 (必要に応じて後でテーブルを変更する ALTER TABLEでは制約を追加できません)。
  2. スキーマを最適化して、必要なものを保存します。これは、テーブルを分割したり、データベースに挿入する前にデータを圧縮/変換したりすることを意味する場合があります。良い例は、IPアドレスを(長い)整数として保存することです。
  3. Dbファイルごとに1つのテーブル-ロックの競合を最小限に抑えます。 (単一の接続オブジェクトが必要な場合は、ATTACH DATABASEを使用します。
  4. SQLiteは、異なる列のデータを同じ列に格納することができ(動的型付け)、それを使用して有利に使用できます。

質問/コメントを歓迎します。 ;-)

30
Lester Cheung

7GBのSQLiteデータベースがあります。内部結合で特定のクエリを実行するには2.6秒かかります。これを高速化するために、インデックスを追加してみました。追加したインデックスに応じて、クエリが0.1秒に下がったり、最大で7秒になったりすることがありました。私の場合の問題は、列が非常に重複している場合、インデックスを追加するとパフォーマンスが低下することだと思います:(

8
Mike Oxynormas

Sqliteスケーリングに関する主な不満は次のとおりです。

  1. 単一プロセス書き込み。
  2. ミラーリングなし。
  3. レプリケーションなし。
8
Unknown

Vacuumコマンドを使用すると、大きなsqliteファイルで問題が発生しました。

Auto_vacuum機能はまだ試していません。頻繁にデータを更新および削除することが予想される場合、これは一見の価値があります。

6
eodonohoe