はじめに

SQLite、気になりますよね?

大昔から利用されているRDBMSではありますが、時代がSQLiteに追いついた...と言っても過言じゃない。 すごい ソフトウェアだと私は思っています。

なんせ、公式のドキュメントからして、サーバーレス のDBであると語っています。これは昨今流行っている個人開発や、Vercelなどのフロントエンドを土台としたWeb開発の時代にぴったり適合したキーワードではない でしょうか?

おまけに、軽量で、スマホアプリでの利用も含めて実績は十分...ですが、こなれているがためどうしても目立ちにくいという技術ではあるのです。

このSQLiteですが、他の技術と同じく、使い方を間違えるとえらい目にあうケースは残念ながら存在すると思います。本記事では、SQLiteの強みと弱みを、公式ドキュメントの各ページを見ながら整理・ご紹介 していきます。

SQLiteの癖、注意点、落とし穴

まずは、他のRDBMS と異なるSQLite特有のポイントを抑えたいと思い、SQLiteの癖、注意点、落とし穴

を見ていきました。

SQLite はクライアント/サーバ型ではなく埋め込み型

まず、ドキュメントの他でも多々紹介されていますが、OracleやMySQL,PostgreSQLに代表される、クライアント/サーバ型ではなく、埋め込み型のデータベースとなるので、プロセスで受け付けるものではないところに注意するようにと口酸っぱく?書かれていますね。

まあ、この辺りはSQLiteを使う人なら技術検討を行う時点で想像がつくところかと思います。

型指定が柔軟

Integer型(数字)のカラムに、文字列を入れてもそのままエラーを返さず入れてしまうとあります。これはバグではなく機能であると書かれています。

SQLiteから他のDB、たとえばPostgreSQLに移行する際に問題になってくることがある、と書かれていますね。運営しているWebサービスが、万一同時接続がとても大きいサービスに成長した場合は、移行に問題がある可能性があると言っているも 同然でここはバリデーションなどアプリケーション側のエラーハンドリングをしっかりできるかどうかが試されていると思います。

そんな大変な目に遭いたくない〜という場合は、最初からMySQLなどのクライアント/サーバ型のDB利用を検討した方がいいでしょうね😅

booleanやDatetime型はない

それぞれintやtextとして置き換えられます。Firebaseなどの NoSQLでも同じように運用しているケースはよく見ますので、特にJS系のフロントエンドフレームワークからは あまり意識されないところかと思っています。

auto_incrementはMySQLと違う動作をする

このページに記載があり、かつ SQLiteのオートインクリメントにまとまっていて驚いた のですが、SQLiteではオートインクリメントは利用を避けなさい(The AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and disk I/O overhead and should be avoided if not strictly needed. It is usually not needed.) と書かれており、INTEGER PRIMARY KEYを指定されている行は、

明示的に値が指定されていない場合、未使用の整数が自動的に埋められる。

とのことでした。MySQLだとauto_incrementが指定されていないプライマリーキーのカラムを空白にしてinsertをするとエラーが出ると思うので、結構大きな違いですね。

利用時には注意したいところです。

ページのまとめ

他の項目はユースケースが限られる癖だと私は思いましたので、利用するにあたって問題が見つかれば随時このページを参照し、追記したいと思います。

SQLiteの適切な使用法

次にSQLiteの適切な使用法

を見ていきます。

SQLiteをクライアント/サーバ型のDBと、直接比較できない

SQLを利用できるデータベースシステムというところに共通点はありますが、そもそも仕組みが違うので比較しないでくれと 読者に先制パンチを与えております笑

SQLite はクライアント/サーバー データベースと競合しません。SQLite はfopen()と競合します。

面白いこと言ってますね。 ようするに、SQLiteはファイルシステムの進化系と考えてくれ。という訳です。 結構野心的な主張かなと思いますし、個人的には好きです笑

昨今のフロントエンドフレームワークから直参照みたいな流れが増えていることから考えるfopen の延長という主張は時代が追いついてきたな、と個人的に思う次第です。

SQLiteが適した状況は?

組み込みデバイス。モノのインターネット。

家電や携帯電話からなんと飛行機(!)などに適しているとのことです。確かにユーザーが1名しかおらず(SQLiteは同時多発的な書き込みに弱い)かつ、組み込みなどに際してファイル1つでDBを実現できる。Readがほとんど。というユースケースには最高にSQLiteは適していそうですね。

個人的にもユースケースを考えましたがエレベーターとかもいけそうですね。あとスマートキーとかにもあってそうです。

アプリケーション+ファイル形式のソフトウェア

会計システムみたいなユーザーがやはり1名で、ひと作業終えたら保存するようなシステムにも向いているとのことでした。たしかにこれもPCへの当該ソフト(MySQL/PostgreSQLなど)の同時インストールが不要になったりするので、ユーザーにもメリットがあって良さそうです。

低トラフィックのWebサイト

any site that gets fewer than 100K hits/day should work fine with SQLite 10万PV/日 以下のサイトがSQLiteに適している

とのことですが、これは保守的な推計値であり、10倍のトラフィックでも動作することが保証されている、とのこと。ニュースサイトなどのRead中心のサイトでは実績も十分あるということだと思いました。

データ分析

SQLiteをデータ分析に利用しているというTwitterのポストを以前に見かけました。

(圧縮したSQLiteのファイルをS3にいれて、Lambdaで検索してPostgresに返してアグリゲートすると安くて速いデータウェアハウスが作れる、という話。)[https://twitter.com/niw/status/1529274344253206528]

確かに、これはめちゃ良さそうなユースケースですね。

S3に置くだけでなくて、本文中にあるようなUSBメモリ...はちょっと古臭いですが、さまざまなルートで分析用のプラットフォームを作ることができそうです。私も余裕がある時に考えてみたいと思いました。

キャッシュサーバとして

RDBMSの前段のキャッシュサーバとしてSQLiteを使うケース。うーん、これは微妙かなあ。事例として書かれているような企業データのReadだけの用途であればSQLiteを入れるほどではないですし。

ただ、ネットワーク停止中にキャッシュデータを表示する というユースケースはかなりアリ。ですね。ファイルとして同一サーバに置かれている可能性が高いSQLiteのメリットをいかせている使い方じゃないかと思いました。

圧縮されていることを活かし、ZIPの代わりとして

**これは面白い使い方ですね! **

An archive of files stored in SQLite is only very slightly larger, and in some cases actually smaller, than the equivalent ZIP archive. SQLiteはZIPよりちょっと大きいだけか、場合によりZIPより小さい

とのことで、圧縮しつつDBとしても利用できるということで何か小さくしなければいけないケースには有効そうです。(具体的には思いつかないが...)

ドキュメントでは、アップデートファイルをカーナビに送信する際に小さい容量で送れる、とのこと。組み込み型でソフトウェアを事後的に更新しなければいけない製品では、覚えておいて損はないユースケースですかね。

というか、以前にスマホアプリにSQLiteでDB実装を行おうとする際にデカいイメージがあったんですが、ZIPより小さくなることあるんですね... 勉強になりました。

クライアント/サーバ型がもっと適した状況は?

ドキュメントページの下の方で、SQLiteよりクライアント/サーバがの方が適している状況を例示していますので 整理してご紹介します。

同時にユーザーが多数アクセスしてくる状況

Unix・Windowsともに ファイルロックの機構にバグがあり、SQLiteのDBファイルを適切ロックできずに同時書き込みに行ってしまうケースがある = これはデータ破損を起こす可能性がある。SQLiteが悪いわけではないが、防ぐ方法がないとのことでした。

データが巨大になりうる状況

SQLiteは1つのデータファイルにデータを格納し、多くのファイルシステムでは、SQLiteの上限である281テラバイトよりも小さい値が上限となるとのこと。よってデータが巨大な場合は通常のRDBMSなどシャーディングやDB分割が行えるRDBMSの方が向いているようです。

オンライン・ソーシャルゲームなど多数のアクセス・ログデータが存在するシステムはすぐにデータ量が膨大なものになりそうですのでSQLiteは向いてなさそうですね。(そもそも、上記の「同時にユーザーが多数アクセスしてくる」に一致しますけどね)

瞬時に書き込みが必要な状況

通常SQLiteではファイルロックにより待ち行列が作られるのですが、数十msで解決されるのでパフォーマンスに体感上の問題はない、と。それ以下のパフォーマンスを求められる場合は通常のRDBMSを使って欲しいとのことです。

ネットワークを介してアプリケーションとデータベースが隔絶されている状況

一般論ですが、リレーショナルデータベースとは、データを丸ごと返さず、SQLにより必要により絞られたデータだけ 返されるシステムです。

SQLiteは通常アプリケーションと同じサーバでの利用を想定している。 ネットワークを介して別サーバにSQLiteのデータファイルを置いた場合その利点が 全く活かせない (なぜなら、データを丸ごと取ってくることになるから)ので、別サーバに置かなければいけない場合はクライアント/サーバ型のRDBMSを勧めますとのことでした。

これは説明通りの理解ですね。例えばAWS S3にSQLiteのdbファイル(.sqlite)を置いたとしても他のRDBMSと違ってSQLを投げつければ欲しい結果だけ返してくれるわけではないので。

ページのまとめ

個人的には圧縮率が高いというのは意外でした〜 そこまで小さくなるのであれば、状況(特に案件の性質)によりますがデータを丸ごとマウントするようなユースケースもデータベース設計上考えられるのかな?と思ったりしました。

SQLiteはサーバーレスである

最後に、SQLiteはサーバーレスである

を見ていきます。

サーバレスということは、バグからの保護もないことをさす

MySQLなどのクライアント/サーバ型RDBMSではSQLにエラーがある場合は、アプリだけでなくMySQLからもエラーを返してくれる、というメリットがあります。残念ながらファイル型のSQLiteではそれがありません。 きめ細やかなロック(行ロック・テーブルロック)もないですし、前述の通り複数の同時書き込みを捌くこともできません。

クラシックなサーバレスとネオ・サーバレスは違う

2018年4月2日に追加された項目とのこと。

クラシックなサーバレス...本当にサーバレス。アプリケーションがファイルとしてDBを同じプロセスの中で取り扱う。ネオ・サーバレス...ファイルシステムのように見せるが、裏側ではクライアント/サーバ型のデータベースが別サーバで動いており、サーバレスの「ように」扱える。

SQLiteはクラシックなサーバレスであるということです。確かに、昨今の文脈だと「サーバレス」はほぼ100%「ネオ・サーバレス」を指しているように思えますね。

ページのまとめ

個人的にはネオ・サーバレスは、オールマネージドで利便性がとても高いが、結局それを保守する企業(クラウドプラットフォームを運営する企業)に多額の費用を払っている。と考えられると思います。(AWS S3は安いが) 例えば、NoSQL系のデータベースは無料枠を超えると従量課金でトラフィック・使用データ量の双方に料金がかかってきます。(Firebase/DynamoDB/Supabase/PlanetScale)

それが為、単なるファイルとも考えられる、クラシックサーバレスのSQLiteが個人開発や中小企業のオウンドWebなどのごく小規模なユースケース(数の上では一番多い)で見直されるのではないかと改めて感じました。

まとめ

いかがでしたでしょうか。個人的には、可搬性の高いDBってすごく好きですし、ユースケースをデータベースエンジニアがしっかりと考えた上で利用すれば、十分実用性があり、再度ホットになる可能性がとても高い技術だと私は思っています。

引き続き本ブログではSQLite関連の技術についてキャッチアップを行ってまいりますので、よろしければご注目ください。


この記事が何かのお役に立てれば幸いです。
最後までお読みいただきありがとうございました!