SQLite と MySQL は形がまったく違うデータベース
SQLite と MySQL はどちらも SQL を話し、テーブルに行を格納するという点では同じですが、システムへの組み込まれ方がまったく違います。SQLite は ライブラリ で、アプリケーションにリンクしてディスク上のファイルを直接読み書きします。一方の MySQL は サーバー で、ソケットやネットワーク経由で接続する独立したプロセスです。
この一点の違いが、インストール方法、同時に書き込めるユーザー数、バックアップの取り方、デプロイの仕方まで、ほぼすべての挙動を決めています。「SQLite と MySQL の違いは?」という質問の大半は、実は「組み込み型(embedded)とクライアント・サーバー型の違いは?」という問いと同じなのです。
-- SQLite: ファイルを開けば、それがデータベースになる。
sqlite3 app.db
-- MySQL: 実行中のサーバーに接続する。
mysql -h localhost -u root -p
SQLite のコマンドはファイルを開く(あるいは作成する)だけです。一方の MySQL コマンドは、すでに起動済みで設定もログイン受付も整っているプロセスへ接続を張りに行きます。
アーキテクチャの違い:組み込み型 vs クライアント・サーバー型
SQLite を使うアプリでは、データベースエンジンがアプリ自身の 内部 で動きます。ポートもデーモンも不要で、systemctl start も要りません。sqlite3 ライブラリの呼び出しが、ディスク上のファイルからページを直接読み書きしているだけです。
MySQL はその真逆です。データを保持するのは mysqld サーバーで、接続管理、権限制御、クエリプランナの実行、ロックの処理まで全部こいつが面倒を見ます。アプリ側はあくまでクライアントとして、SQL 文字列をネットワーク越しに送り、結果の行を受け取る役回りです。
これが実務にどう効いてくるかというと:
- デプロイ。 SQLite はアプリと一緒にそのまま配布できます。バイナリ 1 つ、ファイル 1 つで済む話です。MySQL は別途サーバーをインストールし、セキュリティを固め、監視し、バックアップを取る必要があります。
- ネットワーク越しのアクセス。 MySQL はポートを公開するので、複数のアプリケーションサーバーから同じデータベースに接続できます。SQLite は基本的に同一マシン上の 1 プロセス(あるいは協調動作する数プロセス)を前提にしています。
- 権限管理。 MySQL にはユーザー、ロール、
GRANT文といった仕組みがあります。SQLite の権限管理は、データベースファイルに対する OS のファイルパーミッションだけです。
どちらが「優れている」という話ではありません。解決したい問題が違うだけです。
同時実行と書き込み
ここが両者の最も大きな分かれ道です。MySQL の InnoDB エンジンは行単位のロックを使うので、たくさんのコネクションがそれぞれ別の行に対して同時に書き込んでも、互いをブロックしません。
SQLite は書き込みを データベース 単位で直列化します。書き手は同時にひとりだけ、これは絶対です。読み手は書き手と並行して動けますが(特に WAL モードでは顕著)、2 人目の書き手は順番待ちになります。
-- SQLite: 多数の読み取り側に対応、書き込みは一度に1つだけ。
PRAGMA journal_mode = WAL;
-- MySQL: 多数の書き込み側に対応、きめ細かいロック。
-- (特別な設定は不要 — InnoDB がデフォルトで行う。)
プロセスが1〜2個で書き込み量もそこそこのアプリ——デスクトップツール、モバイルアプリ、小規模なCMSなど——であれば、SQLiteの直列化された書き込みでも十分速く、ボトルネックを感じることはまずありません。一方で、何百ものコネクションが注文をINSERTしたりセッションをUPDATEしたりするような忙しいWebサービスでは、MySQLの行レベルロックがあるかどうかで「快適に動く」か「全部が1つのロック待ちで詰まる」かの差になります。
データ型の違い
MySQLは型がかなり厳密で、種類も豊富です。TINYINT、INT、BIGINT、VARCHAR(n)、DATETIME、DECIMAL(p,s)、BLOB、JSONなど、たくさんあります。カラムをINTで宣言すれば、文字列を入れようとしても弾かれます。
これに対してSQLiteは 型親和性(type affinity) という仕組みを採用しています。カラムの型はあくまでヒントであって、強制ではありません。INTEGERカラムに文字列を入れてもSQLiteはそのまま受け入れて保存します(バージョン3.37で追加されたSTRICTテーブルを明示的に使えば話は別です)。
どちらの行も問題なく挿入できてしまいます。プロトタイピング中はこの柔軟さが便利ですが、データベース側で型をきっちり守ってくれると思っていると面食らうかもしれません。MySQL のように厳密な型チェックを効かせたいときは、SQLite でも STRICT テーブルを使いましょう。
実際にハマりやすい SQLite と MySQL の構文の違い
SELECT、JOIN、WHERE、GROUP BY といった基本的な SQL はほぼ同じです。違いが出てくるのは、だいたい以下のポイントに集中しています。
- オートインクリメントの主キー。 SQLite では
INTEGER PRIMARY KEYを使います(これだけでデフォルトで自動採番されます)。MySQL はINT AUTO_INCREMENT PRIMARY KEYです。 - 文字列とクォート。 MySQL は識別子をバッククォートで囲めます(
`table`)。SQLite は SQL 標準に従って二重引用符("table")を使います。 - 日付関数。 MySQL には
NOW()、CURDATE()、DATE_ADD()がありますが、SQLite ではdatetime('now')、date('now')、datetime('now', '+1 day')のように書きます。 LIMITの書き方。 どちらもLIMIT n OFFSET mをサポートしているので、ここは互換性ありです。- 真偽値(Boolean)。 MySQL には
BOOLEANがありますが、これはTINYINT(1)の別名にすぎません。SQLite ではINTEGERカラムに0と1を入れて表現します。
-- MySQL
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
created_at DATETIME DEFAULT NOW()
);
-- SQLite
CREATE TABLE users (
id INTEGER PRIMARY KEY,
created_at TEXT DEFAULT (datetime('now'))
);
同じ発想でも、キーワードが違えば書き方も少し変わります。考え方そのものは流用できますが、構文は微調整が必要です。
SQLite と MySQL のパフォーマンス比較
「SQLite と MySQL ってどっちが速いの?」という質問に、一言で答えるのは難しいです。
ローカルで読み書きする単一プロセスなら、SQLite の方が速いことが多いです。ネットワーク越しの通信もなければ、プロセス間通信もなく、クエリパーサーが別のアドレス空間で動くわけでもありません。SQLite の SELECT は、ほぼ関数呼び出しのようなものです。
一方、同じデータベースに対して大量のコネクションが同時に書き込むようなケースでは、行レベルロックを持つ MySQL に軍配が上がります。SQLite はライターが 1 つしか動けないモデルなので、こうしたワークロードではすぐに競合が顕在化します。
ただし、WAL モードを有効にした読み取り中心のワークロードでは、SQLite は意外なほどよくスケールします。リーダー同士はもちろん、唯一のライターをもブロックしません。実際、SQLite で本番環境のトラフィックをさばいているサイトは少なくありません。
ネット上のベンチマークだけで決めないこと。判断材料は、自分のアプリの実際のアクセスパターンです。
SQLite と MySQL の使い分け
SQLite が向いているのは、こんなとき:
- データベースが 1 つのアプリと一緒に動く(モバイルアプリ、デスクトップツール、CLI、小規模サイトなど)。
- 設定ゼロでデプロイしたい。ファイルを配るだけで済ませたい。
- 書き込みより読み込みが圧倒的に多い、あるいは書き込みは稀。
- 本番と同じ SQL が動く、組み込みのテスト用 DB が欲しい。
- プロトタイピング中で、サーバーのことはまだ考えたくない。
MySQL が向いているのは、こんなとき:
- 複数のアプリケーションサーバーが 1 つのデータベースを共有する必要がある。
- 同時に書き込むクライアントが多い。
- 細かいユーザー権限やロール管理が必要。
- LAMP やマネージドクラウドなど、MySQL を前提としたスタックの上に作っている。
- レプリケーション、ポイントインタイムリカバリ、モニタリングといった運用ツールが必須要件。
ざっくりした目安として、ストレージの要件が「1 アプリ、1 ディスク」で表現できるなら SQLite で十分なはず。「サービスがあって、運用担当者がいる」と言えるなら MySQL(または PostgreSQL)を選びましょう。
SQLite から MySQL への移行
最初は SQLite で始めて、あとから MySQL に移行するのは、よく踏まれている王道ルートです。これは無理のない計画で、スキーマは小さな修正で済みますし、データも SQLite CLI の .dump できれいにエクスポートできます。直すのは主に、オートインクリメントの構文、日付関数、それに MySQL に直接対応するものがない SQLite 固有の機能(変則的な部分インデックス、WITHOUT ROWID、STRICT テーブルなど)くらいです。
逆方向、つまり MySQL から SQLite への移行は珍しいですが、こちらも可能です。オフライン分析、データの一部を組み込み用にコピーする、テスト用フィクスチャを作る、といった用途で使われます。
要するに、今 SQLite を選んでも将来の選択肢を縛ることにはなりません。書いた SQL も、身につけた知識も、そのまま次に持っていけます。
次は: SQLite と PostgreSQL の比較
比較対象として一番よく挙がるのは MySQL ですが、もう一つよく並べて語られるのが PostgreSQL です。違いの種類はまた別物になってきます。次のページで見ていきましょう。
よくある質問
SQLiteとMySQLの一番大きな違いは何ですか?
SQLiteは「組み込み型」のデータベースで、アプリが1つのファイルを直接読み書きします。サーバープロセスは存在しません。一方MySQLは「クライアント・サーバー型」で、mysqldという別プロセスがポートで待ち受け、アプリはネットワーク越しにやり取りします。このアーキテクチャの違いが、結局のところ他のすべてのトレードオフに直結しています。
SQLiteのほうがMySQLより速いですか?
単一プロセスで読み込みや小さな書き込みを行うだけなら、SQLiteのほうが速いことが多いです。ネットワーク往復もプロセス間通信のオーバーヘッドもないからですね。ただし複数の書き込みが同時に走るワークロードでは、SQLiteは書き込みをDB全体でシリアライズするためMySQLが圧勝します。要は「どちらが速いか」ではなく「どんな使い方をするか」次第です。
MySQLではなくSQLiteを使うべきなのはどんなときですか?
組み込みアプリ、モバイル、デスクトップツール、CLIユーティリティ、ローカルキャッシュ、テスト、それからアプリサーバーが1台で済む小〜中規模サイトならSQLiteが向いています。逆に、複数のアプリサーバーから1つのDBを叩く構成、細かいユーザー権限管理、行単位ロックが効いてくるほど書き込みが多いケースではMySQLを選ぶべきです。
あとからSQLiteをMySQLに移行できますか?
可能ですし、よくある移行パターンです。CREATE TABLE、INSERT、SELECTあたりはSQL方言がほぼ共通なのでそのまま動きますが、型定義(INTEGER PRIMARY KEYはINT AUTO_INCREMENTになります)、日付関数、WITHOUT ROWIDや部分ユニークインデックスなどSQLite固有の機能は書き換えが必要です。pgloaderやダンプスクリプトを使えば作業のほとんどは自動化できます。