1. ホーム
  2. データベース
  3. エスキューエルライト

SQLiteパフォーマンス最適化例共有

2022-01-09 01:12:48

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、ハードディスクが異なるため、同じ問題が再現されないことがあり、性能テストは実機で行うのがベストです。エミュレータでは、ハードディスクの読み書きの速度が実機より速いため、多くの問題が回避され、テスト中に発見されることはありませんでした。