モバイルデバイスでSQLiteを使用するためのベストプラクティス

ブルジョアには、BlackBerryプラットフォームでのSQLite最適化に関する興味深いドキュメントがあります。 ただし、一般的に言えば、そこに含まれるアイデアはあらゆるモバイルプラットフォームに適用されます。 このリストを作成し、モバイルデバイスでSQLiteをプログラミングするための便利で入門的なヒントを含むRuNetで一種の参照テキストを作成することにしました。 コメントでの提案を受け入れます。







常にUTF-8エンコードを使用する


これは、速度とメモリサイズの最適なオプションです(SQLiteは、このエンコード専用のパーサーを内蔵しているため、すべてのクエリを内部的にUTF-8に変換します)。



データベースにできるだけ少ないデータを保持する


このアドバイスはキャプテンエビデンスからのものではありません。 「ファッショナブルな」という理由だけでSQLiteを使用しないでください。 代替案を考えてみましょう:例えばXML。 SQLiteはリソースの無駄です。



トランザクションを常に明示的に管理する


それ以外の場合は、個別の暗黙的なトランザクションが作成され、各SQLコマンドにコミットされます。 グループデータの変更。



インデックスの作成について慎重に検討する


インデックスはサンプリングを高速化しますが、データ変更を遅くします。 データフィールドがインデックス定義に含まれる場合、カバーインデックスを使用すると便利な場合があります。



CREATE INDEX idx ON tab(key1, key2, data1, data2, data3);
      
      





ここで、(key1とkey2の条件によって)列data1、data2、data2のデータを選択すると、SQLiteはインデックス自体から値を取得できます(テーブルからデータをさらに読み込む必要はありません)。 しかし、そのようなインデックスはより多くのスペースを占有します。 したがって、次のアドバイス:



何かをテストする最良の方法:特定のデバイスでテストする


そして、もちろん、空のベースではありません。 適切でない場合は、ランダムデータを入力します。 そうしないと、実際のシナリオでのパフォーマンスが不快になります。



BLOBの保存方法を検討する


公式Webサイトでは、 BLOBを使用するときに次のことを行う必要があることを示すテストを提供しています。

-より大きなページサイズ(8192または16384)を配置します。

-別々のファイルに保存する大きな塊。

データベースにBLOBを保存する場合は、BLOB用に別のテーブルを作成します。



 CREATE blobs(blobid INTEGER PRIMARY KEY, data BLOB)
      
      





そして、データのあるテーブルに、このテーブルのレコードへのリンクを持つフィールドを配置します。 これは、SQLite開発者自身からのアドバイスです。



一時テーブルを使用する


テーブルの作成時に「TEMP」を指定した場合



 CREATE TEMP TABLE tab(...)
      
      





データベースが閉じられると、作成されたテーブルは自動的に破棄されます。



パラメーター化されたクエリを使用する


つまり、SQLクエリに値を渡すには、SQL内のリテラルとしてではなく、パラメーターにバインドします。 これにより、SQLインジェクション攻撃からコードが保護され、パフォーマンスが向上します。



AUTOINCREMENTをPRIMARY KEY定義に追加します


コラム



 id INTEGER PRIMARY KEY
      
      





ROWIDフィールド(一意のレコード識別子)と同義です。 秘Theは、SQLiteは、レコードが以前にテーブルから削除された場合、新しい行が新しいキーを受け取ることを保証しないことです。 識別子の「真の一意性」が必要な場合は、AUTOINCREMENT定義に追加します。



 id INTEGER PRIMARY KEY AUTOINCREMENT
      
      





これで、どのような状況でも、新しい行は一意のid(およびrowid)値を受け取ります(まあ、または8バイトのカウンターがなくなるでしょう)。



外部キー(FOREIGN KEY)は、本当に必要な場合にのみ使用してください


SQLiteには、外部キーをサポートするためのかなり高度なメカニズムがあります。 デフォルトでは、無効になっています(互換性のため)。 一方では、外部キーは整合性を保証します。 一方、リソースが必要です。 それらを使用することに決めた場合、...



各外部キーフィールドに対して、インデックスを作成します


いくつかのテーブルがあるとしましょう:



 CREATE TABLE master(mid INTEGER PRIMARY KEY ...); CREATE TABLE detail(fk_master REFERENCES master(mid) ON DELETE CASCADE ...);
      
      





マスターテーブルからレコードを削除するとき、SQLiteは詳細テーブルのレコードがそれを参照しているかどうかを確認し、追加の選択を行う必要があります。



 SELECT rowid FROM detail WHERE fk_master = ?
      
      





原則として、開発者はFKキーを使用してインデックスを作成することを忘れており、この選択は非常に長い間機能します。



データベースからデータを削除しても、ファイルのサイズは小さくなりません


データベースファイルを圧縮するには、次を実行します



 VACUUM
      
      





この操作には時間がかかります。



さて、最も重要なアドバイス。



データベーススキーマについて慎重に検討する


通常、最初にデータは最大限に正規化され、次に最適化のために非正規化されます。 たとえば、ユーザーが自分の部署の名前を頻繁に尋ねられる場合、この名前は別のフィールドのユーザーテーブルに複製できます。 データベース内で最も集中的に変化しているデータを考えてください。おそらく、別のテーブルで強調表示する必要があります。



補足



複数のSQLステートメントを一度に実行する方法は?


それらを「;」で1行に結合します。



大量のレコードをすばやく追加する方法(一括挿入)


多数のレコードを挿入する前に、



  PRAGMA synchronous = OFF; PRAGMA journal_mode = OFF; BEGIN;
      
      





メモを挿入します。 パラメータを使用して準備文をコンパイルし、必要な値で繰り返し実行することで、最高のパフォーマンスを実現できます。 挿入後、設定を復元します(デフォルト設定が指定されています)。



  COMMIT; PRAGMA synchronous = NORMAL; PRAGMA journal_mode = DELETE;
      
      





テーブルにインデックスを作成するのは、挿入する前ではなく挿入した後に行うのが最適です。 ログが無効になっている場合、挿入プロセス中にアプリケーションがクラッシュすると、データベースが破損する可能性があることに注意してください。



PS。 最新のマネージャーを使用して、SQLiteデータベースを管理します。



All Articles