SQLiteパフォーマンス最適化例共有
iOSの開発で初めて知ったキャッシュデータベースがSQLiteで、そのSQLiteをバックボーンに仕事をしてきました。これまで大量のデータの読み書きに触れることがなかったので、パフォーマンスの最適化にはあまり関心がなかったのですが、今回、大量のデータを一括して読み書きをするという特定のシナリオのためにパフォーマンスの最適化を行ったところ、10分の1にパフォーマンスが改善されました。
一般的なアプリケーションのシナリオはこうです。
アプリケーションが起動するたびに、サーバーから何らかのデータを取り出し、ローカルデータベースの2つのテーブルを同期させ、存在しない場合は書き込み、存在する場合はフィールドを更新しています。データは、あるときは数十個、あるときは数千個です。
キャッシュされたデータは非同期で同時に読み書きできるので、キャッシュされたデータベース操作をすべて実行するバックグラウンドの同期キューを作り、データベースを書き込むキーコードの実行時間を監視していました。この消費量はバックグラウンドでも耐えられない。
コアとなるデータベース操作は次のようなものです。
for 1000 : {
Select -> Update Or Insert
Select -> Update Or Insert
}
2つのテーブルが絡むので2回になるのですが、テストした結果、Selectは1回でほとんどメッセージが出ないが、UpdateやInsert( [FMDatabaseQueue executeUpdate:] )はディスクに書き込むのでかなり消費する、そして全てのSQL文がつなぎ合わせられるかどうか考えて、最終的に1回だけ考える そこでSQLiteにトランザクションがあると思い、FMDBのトランザクションを使ってループ開始前に [db beginTransaction] ループ終了前に [db commit] してラップすれば良いとやってみたところ、1回で終わりました。
トランザクションを追加した後のおおよそのロジックです。
beginTransaction
for 1000 : {
Select -> Update Or Insert
Select -> Update Or Insert
}
commit
このテストは非常にうまくいき、2行のコードを追加しただけで、全体が30秒から約2.8秒に短縮されました。
まとめると
踏み込んだ甌穴と歩いたハードルは未来への教訓
トランザクションのトリックを使ってパフォーマンスを向上させる一方で、本当に安全なのか、所属するシナリオではこの部分のデータにはあまり絶対的な一貫性が必要ないことを知っておくとよいでしょう。
シミュレータと実機でのテストでは、所属するアーキテクチャ、CPU、ハードディスクが異なるため、同じ問題が再現されないことがあり、性能テストは実機で行うのがベストです。エミュレータでは、ハードディスクの読み書きの速度が実機より速いため、多くの問題が回避され、テスト中に発見されることはありませんでした。
関連
-
SQLite3のバインディング関数ファミリーの使い方とその注意点解説
-
SQLiteの便利なコマンドのまとめ
-
ubuntuでSQLite3を使うための基本コマンド
-
SQLiteデータベースのインストールと基本操作ガイド
-
SQLite3における日付と時刻の関数のまとめ
-
SQLite3 コマンドライン操作ガイド
-
SQLiteインメモリデータベース学習マニュアル
-
SQLiteデータベースの共通文とMACでのSQLite用可視化ツール「MeasSQLlite」の利用について
-
SQLiteチュートリアル(VIII)。コマンドラインツールの紹介
-
SQLiteチュートリアル(V): インデックス作成とデータ解析・クリーニング
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン