SQLiteデータベースのチューニング:Androidアプリケーション開発者のためのTips集(21)(2/2 ページ)
Androidアプリ開発者のためのTips集。「データベース処理が重いと感じたら」――今回は、「SQLite」データベースの処理をより効率的に実行するための便利なTipsをいくつか紹介する。
データベース処理速度の向上(2):プリコンパイルステートメントの使用
連続したデータ操作を行いたい場合、先ほどのトランザクション程ではないが、プリコンパイルステートメントを使用することで、処理速度を向上させることができる。
プリコンパイルステートメントとは、同じSQLを何度も使う場合に、あらかじめSQLをコンパイルしておくことで処理を速くする機能のことだ。
先ほどと同様、1000件の名前データを挿入するサンプルに、プリコンパイルステートメントを適用すると以下のようになる。
// 名字20種 private static final String[] FAMILY_NAMES = new String[]{ "佐藤", "鈴木", "高橋", "田中" , "渡辺", "伊藤" , "山本", "中村", "小林", "斎藤", "加藤", "吉田", "山田", "佐々木", "山口", "松本" , "井上", "木村", "林" , "清水", }; // 名前20種 private static final String[] FIRST_NAMES = new String[]{ "太郎" , "次郎", "健太郎", "康平", "大介", "達也", "直人", "徹", "祐介", "和也", "さくら", "佳奈", "久美子", "結衣", "香織", "成美", "智美", "瞳", "麻美", "凜" , }; /** 大量のデータ挿入. */ private void insertManyDataWithPreCompile( SQLiteDatabase db ){ Random r = new Random( System.currentTimeMillis() ); // insertのSQLを先にコンパイルしておく SQLiteStatement stat = db.compileStatement( "insert into profile_table(name, age) values(?, ?)" ); // ランダムなエントリ1000件をデータベースにインサート for( int i = 0; i < 1000; i++ ){ // ランダムな名前と年齢で挿入 stat.bindString( 1, FAMILY_NAMES[r.nextInt(20)] + FIRST_NAMES[r.nextInt(20)] ); stat.bindLong ( 2, r.nextInt(50) ); stat.executeInsert(); } }
実行結果は以下の通りだ(画像3)。
プリコンパイルステートメントを使用しない場合と比べて0.5秒以上速い、約7.2秒で完了した。トランザクションと比較すると速度の向上は微々たるものだが、トランザクションとは別の原理での効率化であるため、併用して利用することができる。
プリコンパイルステートメントとトランザクションを併用すると、1000件の名前データ挿入のサンプルは、以下のようになる。
/** 大量のデータ挿入. */ private void insertManyDataWithPreCompileAndTransaction( SQLiteDatabase db ){ Random r = new Random( System.currentTimeMillis() ); // insert の SQL を先にコンパイルしておく SQLiteStatement stat = db.compileStatement( "insert into profile_table(name, age) values(?, ?)" ); // トランザクションを確実に終了するために、try{}〜finally{} にする try{ // トランザクション開始 db.beginTransaction(); // ランダムなエントリ1000件をデータベースにインサート for( int i = 0; i < 1000; i++ ){ // ランダムな名前と年齢で挿入 stat.bindString( 1, FAMILY_NAMES[r.nextInt(20)] + FIRST_NAMES[r.nextInt(20)] ); stat.bindLong ( 2, r.nextInt(50) ); stat.executeInsert(); } // 全件正常に挿入したら、トランザクション成功 db.setTransactionSuccessful(); } finally{ // トランザクションの終了 db.endTransaction(); } }
実行結果は以下の通りだ(画像4)。
約0.5秒とトランザクションのみを使用した場合と比べ、0.8秒も速い結果となった。
データベース処理速度の向上(3):オンメモリデータベースの使用
最後に、オンメモリのデータベースを使用する方法を紹介しよう。
SQLiteのデータベースは、基本的にファイル上にデータを保存するが、データを一切ファイルに保存せずに全てメモリ上に展開するような使い方もできる。
全てのデータがメモリ上にあるということは、時間のかかるファイルの読み書きが一切発生しないということなので、処理が非常に速い。特に、ファイル書き込みを行うようなデータ更新系の処理の場合、その効果が大いに期待できる。
欠点としては、大量のメモリを消費することと、ファイルへの書き込みを行わないため、アプリケーションの終了とともにデータベース上のデータも全て消えてしまう点が挙げられる。
このように一長一短があるため用途は限られるが、例えば、とにかく速度を重視したいような場合には、オンメモリデータベースの利用が有効だ。データベースをオンメモリで使用したい場合、SQLiteOpenHelperの初期化時に、ファイル名を“null”指定する。
前々回のTipsのサンプルコードで作成したSQLiteOpenHelperを、オンメモリにする場合は以下のようになる。
public class NameBookDBHelper extends SQLiteOpenHelper { // コンストラクタ public NameBookDBHelper( Context context ){ // データベースをオンメモリで使用する場合、 // 第2引数のファイル名に、nullを指定する super( context, null, null, 1 ); } (……以下、略……)
これでこのSQLiteOpenHelperを使って作成したデータベースは、オンメモリで動作する。その他の挿入・更新・削除・検索といったデータ操作の処理については、全く今まで通りの手順で実行できる。
オンメモリデータベースを使って、1000件のデータ挿入を行うと以下のような結果となる(画像5)。
ファイルを使用した通常のデータベースの場合、約8秒程度かかっていたので、その差は歴然だ。
さらに、オンメモリデータベースとプリコンパイルステートメントを組み合わせるとより一層の速度向上が見込める(画像6)。
一方、オンメモリデータベースとトランザクションの組み合わせは、それほど効果的ではない。ファイルへの書き込み回数が減ることで速度が向上するという理屈が同じためだろう(画像7)。
≫連載「Androidアプリケーション開発者のためのTips集」の目次
Copyright © ITmedia, Inc. All Rights Reserved.