モバイル開発におけるSQLite:概要と動作原理

著者: IT Sectr 公開日: 2026-03-11 読了時間: 10 分

SQLiteは、個別のサーバープロセスを必要とせず、デバイス上の単一ファイルにデータベース全体を保存する組み込みリレーショナルデータベースです。ゼロコンフィギュレーション、小さなライブラリサイズ、完全なSQLサポートにより、SQLiteはモバイルアプリケーションにおけるローカルデータストレージの標準となっています。SQLiteコンソーシアム(2025年)によると、このDBMSはiOSおよびAndroidのすべてのスマートフォンを含む40億以上のデバイスで使用されています。

重要なポイント

  • SQLiteは、ゼロコンフィギュレーションで単一ファイルにデータを保存する組み込みリレーショナルDBMSです。
  • ACIDトランザクションは、停電やアプリクラッシュ時でもデータの整合性を保証します。
  • データ型付けは動的です。SQLiteはテーブル作成時にカラム型の厳密な指定を必要としません。
  • Roomは、DAOとアノテーションを通じてSQLiteの操作を簡素化するAndroid ORMライブラリです。
  • CoreDataはiOSでPersistent StoreとしてSQLiteを使用できますが、オブジェクト管理レイヤーを追加します。

SQLiteとは?

SQLiteは、専用サーバーを必要としないリレーショナルDBMSを実装するC言語ライブラリです。アプリケーションに直接組み込まれ、デバイスのファイルシステム上の通常のファイルに対してデータの読み書きを行います。ライブラリサイズは約600KBで、SQLiteは最も軽量なフル機能SQLデータベースです。

SQLiteはSQL:1999標準の大部分をサポートしており、JOIN、サブクエリ、トリガー、ビュー、インデックス、ウィンドウ関数を含みます。制限はALTER TABLE(限定的なサポート)と完全なRIGHT/FULL OUTER JOINに関するものです。それでも、モバイルアプリケーションの場合、SQLiteの機能はローカルストレージの99%のケースで十分です。

Stack Overflowの開発者調査(2025年)によると、SQLiteは組み込みソリューションで最も人気のあるデータベースであり、MySQL、PostgreSQLに次いで全DBMSの中で人気度第3位です。モバイル開発では、SQLiteはすべてのアプリケーションで直接またはラッパーを介して使用されています。

SQLiteの主な特性

ゼロコンフィギュレーション — SQLiteはインストール、権限設定、ユーザー作成、サービス起動を必要としません。ライブラリをプロジェクトにリンクし、1つの関数を呼び出すだけでデータベースが作成されます。これは、サーバーのインストール、ポート設定、ユーザー設定が必要なクライアント・サーバー型DBMSと比較して、展開を根本的に簡素化します。

SQLiteデータベースファイルは、コピー、分析、ネットワーク経由での送信、バックアップからの復元が可能な一般的なクロスプラットフォームファイルです。ファイル形式はAPIレベルで安定しており、2004年に作成されたSQLite 3ファイルは現在のバージョンのライブラリで開くことができ、長期的なデータ互換性を保証します。

SQLiteの仕組み:アーキテクチャとストレージ

SQLiteのアーキテクチャは、Tokenizer、Parser、Code Generator、VM、B-Tree、Pager、OS Interface、Utilitiesの8つの仮想マシンで構成されています。SQLクエリはTokenizer(トークンへの分割)、Parser(ASTの構築)、Code Generator(バイトコードへの変換)を経て、B-TreeとPagerを介してデータページを読み取る仮想マシン上で実行されます。

SQLiteはテーブルとインデックスの保存にB-Treeを使用します。各テーブルは個別のB-Treeとして保存され、リーフノードにデータ行が含まれます。インデックスもB-Treeとして保存されますが、リーフにキーが含まれます。Pagerはファイルからメモリへのページ(デフォルト4096バイト)の読み込みを管理し、ジャーナルまたはWALを介してACIDトランザクションを提供します。

ジャーナリングモード

WAL(Write-Ahead Logging)はモバイルアプリケーションに推奨されるモードです。変更は最初に別のWALファイルに書き込まれ、その後定期的にメインデータベースに転送されます。WALを使用すると、データベースからの読み取り(古いデータ)と書き込み(WAL経由)を同時に行うことができ、マルチスレッドアプリケーションのパフォーマンスが向上します。標準のジャーナル(ロールバックジャーナル)は書き込み中に読み取りをブロックします。

パラメータロールバックジャーナルWAL(Write-Ahead Logging)
書き込み中の読み取りブロックされる許可される(古いデータを読む)
書き込みパフォーマンス中程度高い(WALへの順次書き込み)
ディスク消費少ない(ロールバックジャーナルのみ)多い(WAL + メインデータベース)
クラッシュリカバリ最後のチェックポイントにロールバックWALからリカバリ(データ損失なし)
推奨シングルスレッドシナリオ向け一般的なモバイルアプリケーション向け

モードの切り替えは1つのSQLクエリで行われます:PRAGMA journal_mode=WAL。バックグラウンド同期とデータを同時に読み取るUIスレッドを持つモバイルアプリケーションの場合、WALはより良いパフォーマンスとインターフェースのロック防止を提供します。

モバイル開発におけるSQLite vs 他のデータベース

SQLiteはローカルデータストレージの唯一の選択肢ではありませんが、最も汎用性が高いものです。Realmはメモリ内のオブジェクトへの直接アクセスの高速性を提供しますが、独自のNoSQL形式を使用し、ライブラリサイズが大きくなります。iOSのCore DataはSQLite上のORMレイヤーであり、オブジェクトグラフ管理と操作の取り消しを追加します。

ほとんどのアプリケーションでは、予測可能なパフォーマンス、ベンダーロックインのなさ、実績のある安定性により、SQLiteが最適な選択肢であり続けています。RealmとCore Dataは、複雑なオブジェクトグラフ、リアクティブクエリ、またはデバイス間同期が必要なプロジェクトで正当化されます。

特性SQLiteRealmCore Data
データベースタイプリレーショナル(SQL)NoSQL(オブジェクトベース)ORM(SQLite上)
ライブラリサイズ~600KB~4MBApple SDKに組み込み
パフォーマンス中程度高い(インメモリオブジェクト)中程度(ORMオーバーヘッド)
プラットフォームiOS, Android, Web, デスクトップiOS, Android, Node.jsiOS, macOS
ベンダーロックインなし(オープンスタンダード)中程度(独自形式)高い(Appleのみ)

SQLite、Realm、Core Dataの選択は、プラットフォーム、オブジェクトモデルの要件、同期戦略によって異なります。クロスプラットフォームプロジェクト(KMP、Flutter)の場合、SQLiteはデータモデルを変更することなくすべてのターゲットプラットフォームで動作する唯一の汎用的な選択肢です。

AndroidのSQLite:RoomとSQLiteOpenHelper

RoomはAndroid Jetpackのライブラリで、SQLite上にORMレイヤーを提供します。Roomはアノテーション付きDAOインターフェースから自動的にSQLクエリを生成し、コンパイル時にクエリの正確性を検証し、スキーマ変更時にデータベースマイグレーションをサポートします。RoomはAndroidでSQLiteを扱う推奨方法です。

SQLiteOpenHelperは、ORMなしでSQLiteを直接管理するための低レベルAPIです。このクラスはデータベースの作成、開封、アップグレードを管理します。SQLiteOpenHelperは、シンプルなSQLクエリのプロジェクトや、Roomの抽象化なしにSQLロジックを完全に制御する必要がある場合に適しています。

RoomのエンティティとDAOの例

Roomではエンティティに@Entity、DAOに@Daoのアノテーションを付けます。Roomはアノテーション付きメソッドをSQLクエリに変換します。@InsertはINSERTを生成し、@Queryは指定されたSQLでSELECTを生成します。マイグレーションは、古いスキーマバージョンと新しいスキーマバージョンを指定してMigrationクラスを介して追加されます。Roomはコンパイル時にSQLを検証するため、本番環境での構文エラーを排除します。

kotlin
@Entity
data class User(
    @PrimaryKey val id: Long,
    val name: String,
    @ColumnInfo(name = "created_at")
    val createdAt: Long
)

@Dao
interface UserDao {
    @Query("SELECT * FROM user ORDER BY name ASC")
    suspend fun getAllUsers(): List<User>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertUser(user: User)

    @Query("DELETE FROM user WHERE id = :id")
    suspend fun deleteUser(id: Long)
}

Roomは自動的にUserDao_Impl実装を生成し、内部のRoomDatabaseを介してランタイムSQLiteクエリを含みます。コルーチン(suspend)により、DAOメソッドはUIをブロックせずにバックグラウンドスレッドで非同期に実行されます。@QueryのFlow戻り値タイプは、テーブルが変更されると自動的に結果を更新します。

iOSのSQLite:FMDBとGRDB

FMDBはSQLite C API上のObjective-Cラッパーで、歴史的にiOSで最初に普及したライブラリです。クエリの実行と結果の取得のためにFMDatabaseオブジェクトとFMResultSetオブジェクトを提供します。FMDBはシンプルでミニマルですが、Swift固有の構文(オプショナル、Codable、async/await)をサポートしていません。

GRDBはSQLiteを扱うためのモダンなSwiftライブラリです。タイプセーフなAPI、Codableサポート、Combine Publishers、async/await、マイグレーション、リアルタイム変更監視を提供します。GRDBはSwift Concurrencyとの完全な統合と優れたコード可読性により、新しいSwiftプロジェクトで推奨されます。

SwiftでのGRDBの例

GRDBは、FetchableRecordプロトコルとTableRecordプロトコルに準拠するRecordクラスを通じてテーブルを定義します。クエリは生のSQLではなく、タイプセーフな構文でSwiftで記述されます。GRDBはスキーマのバージョン管理とアプリバージョン間のマイグレーションのためのDatabaseMigratorもサポートしています。

swift
struct User: Codable, FetchableRecord, TableRecord {
    var id: Int64
    var name: String
    var createdAt: Date
}

let dbPool = try DatabasePool(path: dbPath)
var migrator = DatabaseMigrator()
migrator.registerMigration("v1") { db in
    try db.create(table: "user") { t in
        t.autoIncrementedPrimaryKey("id")
        t.column("name", .text).notNull()
        t.column("createdAt", .datetime).notNull()
    }
}

let users = try await dbPool.read { db in
    try User.order(Column("name")).fetchAll(db)
}

DatabasePoolは同時読み取りのためにSQLiteのWALモードを使用します。複数のリーダーが同時にデータベースにアクセスできる一方、単一のライターがWALを介してデータを更新します。GRDBは接続とトランザクションを自動的に管理し、手動同期なしで任意のスレッドからスレッドセーフなデータベースアクセスを提供します。

SQLiteパフォーマンス最適化

インデックスはSQLiteクエリを高速化する最も効果的な方法です。WHERE、JOIN、ORDER BYで使用されるカラムにインデックスが作成されます。100000レコードのテーブルの場合、インデックス付きカラムの検索は秒ではなくミリ秒で完了します。ただし、インデックスはINSERTとUPDATEを遅くするため、その数は書き込み頻度とバランスを取る必要があります。

単一トランザクション内でのバッチ挿入は、大量データの読み込みを根本的に高速化します。1000レコードを1つずつ挿入すると約1秒のオーバーヘッドが発生します。同じ1000レコードを1つのトランザクションで挿入すると約5〜10ミリ秒です。この違いは、個々のINSERTが同期ディスク書き込みで新しいトランザクションを作成することに起因します。

パフォーマンスPRAGMA

PRAGMAはライブラリの動作を設定するSQLiteコマンドです。主要な最適化プラグマ:PRAGMA synchronous=NORMAL(fsync頻度を低減)、PRAGMA cache_size=-8000(8MBのキャッシュを割り当て)、PRAGMA temp_store=MEMORY(メモリ内の一時テーブル)。大容量データを扱うモバイルアプリケーションの場合、これらのプラグマの組み合わせによりクエリが2〜3倍高速化します。

もう1つの重要な最適化は、SQLクエリのプリコンパイル(プリペアドステートメント)です。クエリが繰り返し実行される場合(例:10000行の挿入)、SQLを1回コンパイルしてステートメントを再利用すると、CPU負荷が30〜50%低減します。RoomとGRDBは自動的にプリペアドステートメントをキャッシュしますが、SQLite C APIを直接使用する場合は手動でコンパイルする必要があります。

kotlin
class UserRepository(private val db: RoomDatabase) {

    suspend fun insertBatch(users: List<User>) {
        db.withTransaction {
            users.chunked(500).forEach { batch ->
                batch.forEach { user ->
                    insertUser(user)
                }
            }
        }
    }
}

withTransactionを使用したバッチ挿入は、すべてのINSERT操作が単一のトランザクション内で実行されることを保証します。チャンク化(chunked)によるサブバッチへの分割は、1つのトランザクションが大きくなりすぎて他のスレッドを長時間ブロックするのを防ぎます。バックグラウンド同期の場合、500レコードのサブバッチサイズが速度とUI応答性の最適なバランスを提供します。

よくある質問

SQLiteは複数のスレッドで使用できますか?

はい、SQLiteはWALモードでマルチスレッドアクセスをサポートしています。複数のスレッドが同時にデータを読み取ることができますが、書き込みは1つのみです。RoomとGRDBは自動的に同期を管理します。ロールバックジャーナルモード(デフォルト)では、書き込み操作中はデータベース全体がロックされます。

モバイルデバイスでのSQLiteデータベースの最大サイズは?

SQLiteの制限は281TB(理論上の最大値)です。実際には、データベースサイズはデバイスの利用可能メモリによって制限されます。モバイルアプリケーションの場合、快適なサイズは1〜2GBまでです。2GBを超えるデータベースは、バックアップ、App Storeのアップデートを遅くし、RAM消費を増加させます。

SQLiteのデータは安全ですか?

SQLiteはデフォルトでデータを暗号化しません。ファイルにアクセスできるプロセスは誰でもデータを読むことができます。暗号化には、SQLCipher(AES-256拡張)、EncryptedDatabase(Android)を使用したRoom、またはiOSのEncrypted Core Dataを使用してください。暗号化により、データの読み取りおよび書き込み操作に5〜15%のオーバーヘッドが追加されます。

SQLiteとMySQLの違いは何ですか?

SQLiteはサーバープロセスを必要としない組み込みライブラリです。MySQLは独立したサーバー、ユーザー、アクセス権、ネットワークプロトコルを持つクライアント・サーバー型DBMSです。SQLiteはデータベースを単一ファイルに保存します。MySQLはサーバーが管理する複数のファイルに保存します。SQLiteはよりシンプルで軽量、MySQLはより強力でスケーラブルです。

データを失わずにSQLiteスキーマを更新するには?

SQLiteのマイグレーションには、ALTER TABLE(カラム追加)を使用するか、データ移行と古いテーブルの削除を伴う新しいテーブルを作成します。RoomはMigrationクラスを通じてこのプロセスを自動化します。startVersion、endVersion、およびスキーマ変更のSQLクエリを指定します。GRDBとFMDBも同様のDatabaseMigratorを提供しています。

まとめ

  • SQLiteはゼロコンフィギュレーションの組み込みリレーショナルDBMSであり、iOSおよびAndroidのすべてのモバイルアプリケーションでローカルデータストレージに使用されています。
  • ACIDトランザクションとWALモードは、データの整合性と複数のアプリケーションスレッドからの同時アクセスを保証します。
  • Room(Android)とGRDB(iOS)は、タイプセーフなAPIと自動マイグレーションを通じてデータベース操作を簡素化するSQLiteのモダンなラッパーです。
  • SQLiteのB-Treeアーキテクチャはインデックスによる効率的な検索を保証し、バッチトランザクションとプリペアドステートメントは高い書き込みパフォーマンスを提供します。
  • SQLiteは汎用性(すべてのプラットフォーム)、ライブラリサイズ、ベンダーロックインのなさでRealmやCore Dataを上回ります。
  • インデックス、WALモード、PRAGMA設定による最適化により、一般的なモバイルワークロードでクエリが2〜3倍高速化します。
  • 推奨 — AndroidではRoom、iOSではGRDBを介して、モバイルアプリケーションのプライマリローカルデータストレージとしてSQLiteを使用してください。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください