RDB がお好き? けっこう。ではこの話は終了になりますよ。

表計算ソフトが嫌になったあなたに、関係データベース (RDB) がおすすめですよというお話をします。 あと、一応私が軽率に使ってみてどんな感じになっているか軽く紹介します。 おすすめですよという話と例の紹介はしますが、具体的にこうすると良いですよという話はしません。 「RDB はいいぞおじさん」です。

軽率に RDB を使っていこうな。

この記事は rogy Advent Calendar 2019 の15日目の記事です。 前日の記事は『初めて電子工作した話』でした。

本題の前に

まず一言言わせてほしいんですけれども。

明日はらりおさんの「修論? まだ早い」です.明日のrogy Advent Calendar 2019もお楽しみに~.じゃあないんですよ。 これじゃあいかにも「まだ修論書き始めてない M2 がどうなるか眺めてようぜwww」みたいな感じじゃないですか[0]

私の Twitter アカウント、指導教員に監視されてるんですよ。 近隣ラボの学生とかにも滅茶苦茶煽られるんですよ。 顔を見るたび煽られるんですよ。

煽る気がないのは重々承知なんですが、ナイ〜ブな状態の M2 には効くやつなので勘弁してください。 私が12月の半ばにもなって「修論? まだ早い」とかほざいているなどという事実はありません[1]

それでは、以下本編です。


ご注文は表計算ソフトですか??

いいえ[2]

まあ愚痴ると色々あるんですが、端的に言えば以下の点において表計算ソフト (特に○クセル) には不満があります。

表示上のレイアウトとデータ構造が不可分である

表計算において、変数としてセルを用いますが、同時にセルは表示のためにも利用されます。 これが何を意味するかというと、「セルを計算に都合の良い位置ではなく表示したい位置に配置しなければならない」ということです。

計算用のセルと表示用のセルを別々に用意することもできますが、その場合一段階の余計な indirection が必要になり、また表示されている場所からデータを直接編集することはできなくなります。

互換性あるいはロックイン

今更○クセルが囲い込みをしているなどと言う気もありませんが[3]、では互換性が十分かといえば全然そんなことはありませんね。 データの編集ができてもレイアウトの再現や保存ができなくて却下されてしまうなどの事例があります。

事例がありますというか、私が勤務報告書のエクセルファイルを LibreOffice で編集できないため溜息を吐きながらインドッズを起動するのもそういうことです。 いや、厳密には編集はできるんですが、 LibreOffice で保存すると EXCEL から見たときのとある図 (方眼紙) 上の色情報が変わってしまうらしく、「次から EXCEL で編集してください」と言われてしまいました[4]。 これは先述の「表示上のレイアウトとデータ構造が不可分」とも繋がりますが、本質的に欲しいのがデータなのに表示用のレイアウトまで持ち回らないといけないというのは無駄が多くていけません。

柔軟かつ汎用の API の欠如

CSV で済む程度の情報は CSV にしたい、では何故したいのかといえば、バッチ処理 (複数データを一気に弄る処理) が楽だからというのがあります。 あるいは入力のみならず出力においても、一部のデータだけ流し読みしたいこともあれば、複数の情報を結合して扱いたいときもありましょう。 こういうとき、いちいちオフィススイートのようなクソデカ激重グラフィカルアプリを起動したいだろうかという話です。

また、データの一部を取り出して別のプログラムで処理したいというときも、いちいちアプリケーションを起動して範囲選択してファイルに貼り付けて、と手間が多くていけません。

構造の表現力が貧弱

これもレイアウトとデータ構造の不可分性に関わる話ですが、そもそも EXCEL で多少複雑なデータを置いておこうとすると、すぐに2次元の表の限界が来ます。 シートを分けたり行を離したりなどいろいろ工夫することはできるでしょうが、それらの間の関係は個々のセルの内容である計算式を見なければ判然としません。

大量のデータが保存されていたり見た目が整備されていればいるほど、たとえば時間が経って久々に開いたファイルの使い方や構造がよくわからなくなっていることでしょう。

スプレッドシートとしての RDB

さて本題ですが、私からの提案は表計算ソフトの代わりに関係データベース管理システム (RDBMS) を使うことです。 関係データベース (Relational DataBase, RDB) については後で簡単に紹介しますが、非常に多くのサービスの裏で使われている「いわゆるデータベース」です。

アホくさいですか? しかしこれが意外にイケるんです。

表示レイアウトとデータ構造が分離される

RDB では、データはデータとして格納され、これを閲覧するときは必要に応じて SELECT したり view を利用することになります。 つまり、内部のデータ表現ではなく欲しい形のデータを閲覧することが可能です。

また、更新や追加なども内部のデータ構造を前提に行うもので、表示でどう利用するかを意識せず操作できます。

互換性は高め

RDB の互換性が低いと思いますか? それは RDB の機能をフル活用すべく直接操作したり web アプリケーションを実装したりなどすると気になってくるでしょうね。

しかし! 趣味でデータを溜めておく程度のことであれば、有名どころの RDB はどれも問題なく同じように使えることでしょう。 SQL には (一応) 標準がありますし、機能面でも少なくとも通常のクエリはひととおり動きます。

実は MySQL / MariaDB, PostgreSQL, SQLite ともに再帰クエリ (WITH RECURSIVE) に対応しているため、 RDB は表だけでなくグラフや木構造も自然に扱えるようになっているんです。

保存するデータの型が明示的なのも魅力です。 数値を入力したら日付になっているなんて意味不明なことも、 RDB を普通に使っていればまず起きません[5]

柔軟かつ汎用の API

SQL の汎用性と柔軟性はあまりに魅力的です。 まあ実のところ若干方言っぽいのはあるんですが、基本的に様々な RDBMS 全部同時に使えないといけないとかでもなければ、自分が使っている構文だけ把握すればいいのでそんなに困りません。 そもそも何度も実行するものならスクリプト化なりメモからコピペ何なりして保存しておけば良いでしょう。

また、 SQL を触りたくなくとも、 Ruby や Python のような汎用のスクリプト言語からでも操作ができる (はず[6]) ので、ちょっと複雑なことをしたいというとき謎の BASIC 的言語を調べる必要もありません。 自分の使い慣れた言語でロジックを書けば良いのです。

構造の表現力が強力

RDB においては、テーブル (つまり表) とその関係という形でデータ構造が記述されます[7]。 つまり、ただ単にデータを散らして置いておくだけでなく、構造と関係性を定義して、後で関連するデータを繋げて引っ張ってくることができるということです。

また、この構造や関係性はセルの数式を覗き見ずともわかるものです。 「しばらくデータを使わないうちに、どこに何を追加すればいいのか忘れてしまった」などという悩みともおさらばです。 なにしろ RDB では表にも行にも名前が付いていて、参照関係まで明示されているのですから。

RDB とは何ぞや

さて話を進める前に、軽く RDB という概念について紹介しておきましょう。 ……といきたいところですが、この辺りは厳密な話をすると長くなるのでサラっと流します。

関係データベース (RDB) の定義については別の書籍やサイトに任せるとして、 RDB は以下のような特徴を持っています。

  • データベースはテーブル (表) の集合
  • テーブルには行と列がある
    • 行 (row) はひとかたまりのレコード (CSV での横列)
    • 列 (column) はレコード中のデータ項目 (CSV での縦列)
    • レコード (行データ) を集めたものがテーブルのデータ
  • テーブルは関係を持てる
    • たとえば「この列のデータは実は別のテーブルの行を参照するポインタ (みたいなもの) である」などが表現できる

なんとなくスプレッドシートっぽいような、そうでもないような、微妙な印象でしょうか。 まあ正直これでは何のことだかサッパリだと思うので、軽率な使い方の具体例を図とともに見ていきましょう。

カラオケで歌った歌を管理してみる

なんかもうハイという感じですが、やっていきましょう。

スプレッドシートでやるなら?

もしこれを表計算ソフトでやるなら、皆さんはどうデータを入力するでしょうか。 ありがちなのは以下のような感じ?

カラオケ活動履歴
日付 曲名 歌手 機種 メモ・感想
2019-01-01 ぽよぽよ The Various Artists D○M 最初の90秒しか覚えてなかった
2019-01-01 ほげほげ The Singer D○M 伴奏の再現度が低くて萎えた
2019-01-01 あぁ^〜 The Various Artists D○M
... ... ... ... ...
素朴な表で管理するカラオケ活動の例

さて実に素朴ではありますが、残念ながらこの構成にはいくらか問題がありそうです。

  • 曲名や歌手名の重複の扱い
    • 同名の曲や同じ名前で別実体のアーティストがあった場合、このデータでそれを判別することは困難です。 同名の曲で別名のアーティストであれば判別できるでしょうが、同名の別アーティストを判別可能にするためには何らかの妥協が必要そうです。

      重複はデータサイズにも影響します。 たとえば曲名が滅茶苦茶長い曲を100回歌えば、曲名の100倍のデータ量を保存することになります[8]

  • データの精度
    • 日付を使ってカラオケ活動を管理していますが、それ本当に大丈夫ですか? たとえば1日に2回別のカラオケに行くことがあったら、区別したくはありませんか? 今は良いかもしれませんが、後になって変更しようとすると面倒ですよ。

  • 単位が活動しかない
    • この表だと、1回の歌唱活動ごとにメモを付けられるようになっています。 でも、一回一回の歌唱ではなく、曲やアーティスト自体に対してコメントを付けたくなることは考えられませんか? あるいは、「JOYS○UND に入っている○○という曲」にだけコメントを付けたくなるかもしれません[9]

      別のシートを作ったり離れた場所に表を作って別個に管理しても良いでしょうが、今度は連携して検索したり修正したりなどが面倒になってしまいそうです。

……とまあこのように設計に悩みどころの見えるスプレッドシート管理ですが、では RDB を使うとどうなるか見てみましょう。

RDB でやるなら?

データ構造

以下は私が利用しているスキーマ (データ構造と関係) です。

phpMyAdmin で表示したカラオケ用データベースのスキーマ。
私が使っているスキーマ (2019-12-15 時点)
sessions: カラオケ入店
カラム 意味 コメント
session_id session の ID 整数 自動で付番される。
start_date 入店日 日付
date_index その日のうちの入店回数 整数 1回目なら0、2回目なら1、以後同様。
start_datetime 開始日時 日時 (省略可)
comment コメント 文字列 (省略可) 「大岡山の○○に行った」など。自由。
activities: 歌った一曲ごと
カラム 意味 コメント
activity_id activity の ID 整数 自動で付番される。
session_id session の ID 整数 sessions テーブルのカラムへの参照。
session_index session 内での順番 整数 1曲目は0、2曲目は1、以後同様。
model_song_id 歌った曲 整数 model_songs テーブルのカラムへの参照。
songs: 楽曲
カラム 意味 コメント
song_id song の ID 整数 自動で付番される。
title 曲名 文字列
description 曲の説明。 文字列 (省略可)
artist_id 歌手・アーティスト 整数 artists テーブルのカラムへの参照。
テーブルの定義の解説 (一部)。

見たままです。 これ以上解説しても同じような感じになってしまうので省略します。

閲覧の例

で、閲覧するときは、たとえばこう見えます。

view を使って活動履歴を閲覧できる。
SQL クエリや view 機能を使うことで、好きなようにデータを連結・加工して表示できる。 選曲はスルーしてね。

歌そのもの、機種、歌った出来事、アーティスト、日時などなど、管理するときは全て別々のテーブルでしたが、表示するときは SQL 文をひとつ書くだけで、こうしてまとめて合成することができます。 もちろん、これを CSV 出力するなども簡単です。

もうひとつ、別の例をお見せしましょう。 回数順で並べたリストです。

view を使って活動傾向を閲覧できる。
SQL クエリや view 機能を使うことで、好きなようにデータを連結・加工して表示できる。 選曲はスルーしてね。

このデータでは、 J○YSOUND で歌ったか D○M で歌ったかは気にせずカウントしています。 このように統計的な処理を施すことも、 RDB なら簡単です。 SQL を1行書くだけでできてしまいます。

RDB で何が嬉しいか

繰り返しになりますが、何が嬉しいのでしょうか。

まず、表示するときのことを考えず、データ本来の構造をそのまま反映させて管理できるようになりました。 表示するときも、欲しいデータを持つテーブルを JOIN してカラムを並べるような SELECT 文を書くだけです。 何度も同じ表示を使いそうなら、クエリを view として保存しておくこともできます。

互換性もそれなりに高いです。 SQL としてテーブル定義と内容データを吐き出し、定義の方をちょっと修正してやれば、たとえば SQLite にインポートすることもできます。 つまり (余程高レベルなことをしなければ) データベース管理ソフトはいつでも乗り替え可能ということです。

機能は柔軟で API も汎用のものが用意されています。 どのようなデータベースを弄るにしても、必要なのは RDB と SQL の基礎知識だけです。 スプレッドシートのように、ファイル毎に黒魔術のような謎の式を解読しないと弄るのが難しいなんてことはありません。

私は MariaDB を web インターフェース[10]経由で利用していますが、お好みのデスクトップクライアント、たとえば LibreOffice Base 経由で操作することもできます。 Android にも SQL クライアントがありますから、そちらを利用してデータベースにアクセスすることもできます。 あるいはお好みの言語でスクリプトを書いて操作したり、専用の操作画面を持つクライアントを自作することだってできます。

SQLite のデータであれば SQLite Studio などで編集できる。
SQLite Studio (PC のネイティブアプリ) で SQLite のデータベースを閲覧している例。 なおこれは実験用の旧データなので、本記事で紹介したものとは微妙に違う。

データの制約や関係についての表現力もあります。 たとえば存在しないアーティストを誤って参照したり、歌ったことのある歌データを誤って削除したりといったミスは、 RDBMS によって阻止されます。 あるいは、同名だが別実体の曲やアーティストも、完全に区別することができます。 それらは同じ文字列情報と別の ID を持つ、別の行に過ぎないのです。

何から始めよう

大概のことはできる

私のやっている例としてカラオケで歌った履歴とかいうしょーもない例を出しましたが、では実際 RDB で何を管理できるものなのでしょうか。

実のところ、よほど不規則なデータでもなければ基本的に RDB で管理できてしまうのです。

あらゆる web サービスは、本質的には RDB のフロントエンドである。

— 発言者不詳

まあ「あらゆる」は言いすぎにしても、実際のところ一般人向けのサービスでデータを管理しているもののバックエンドはほとんどが RDB で実現可能でしょう。 文書 DB とか triplestore のようなものはまた別の話になってきますが[11]、これらは相応に特殊な要件や注意深い設計がないと使いこなすのは難しいでしょうし、 RDB にあった都合の良い性質のいくらかが損なわれているので、初心者向けではありません。 あの Wikipedia で使われている MediaWiki のバックエンドさえ RDB なのですから、軽率に使うなら文書だろうが何だろうが RDB に突っ込んでしまえばいいのです。

ただ、それでも敢えて指標を考えるとするなら、「表を1つ以上使ってデータを並べられるなら RDB が使える」と考えるのが良いのではと思います。

くだならいことに使おう

たとえば蔵書管理に使いたいなどの需要は実にありがちです。 私もたいへん欲しい。

しかし! そういうのをマトモにやろうとすると、だんだん専用アプリ (あるいはサービス) を実装している感じになってきて、最終的にソフトウェア開発っぽくなっていきます。 (べつにそういう欲求を無視してひたすらデータを打ち込むだけでも構わないのですが、データ入力って手間でしょう? きっとバーコード入力とか使いたくなりますよ。)

そういう「みんなが欲しがりそうな重い機能」は本当に専用のサービスに任せてしまうべきです。 個人的にエ○セルを使って軽率にファイルを保存するくらいのノリでデータベースを作りましょう。 そのためには、くだらないくらいのことが手始めとして丁度良いのです。 たとえばカラオケの履歴とかね。

何を使うか

では RDB といっても何を使おうかという話です。 とりあえず、軽率に触るならサーバを立てる必要のない SQLite が最有力の選択肢になるでしょう。 とはいえ SQLite はライブラリとコマンドラインツールで、直に触るには若干の PC 慣れが必要ですから、もっと楽に使うには SQLiteStudio を使いましょう。 ギャラリーから操作画面がどのような感じか確認することができます。

サーバを立てたりコンテナを動かす知識と体力があるなら、 MySQL / MariaDB をバックエンドにして、 phpMyAdmin を web フロントエンドとして使うのが手頃です。 いずれも公式に Docker コンテナが用意されています (MySQL / MariaDB / phpMyAdmin) ので、環境を汚さずに試したり、ローカルで実験したデータベースをそのままサーバに持っていったりなどできます。 (もちろんサーバで稼動させるなら、セキュリティ設定はしっかりしましょう。)

その他の話題

正規化は面倒ではない

正規化なんて小難しい理屈が付いてますが、あんなの重複排除したい気持ちさえあれば直観でできます。 直観主義論理よりよほど直観的です[12]

最初にスキーマを雑に作っても、テーブル定義自体の編集も後からできますから、取り返しのつかないことなんてありません。 SQL の表現力は強いですから、後から「アッここまとめられるじゃん」と思ったときにコンソールで SQL を入力してポチーすれば運用中の正規化くらい簡単です。 常時稼動かつビジネスロジックと連携する必要のある web サービスだといろいろ考えることがあるでしょうが、趣味で RDB を直接叩いているような人にとってはスキーマのダイナミックな変更くらい大したことはありません。

そもそも、正規化しなくてもデータは格納できるし編集もできるのです。 どんなに雑なスキーマを作っても (たとえば全データをひとつのテーブルに格納しても)、表計算ソフトで素朴にやるより状況が悪くなることはまずないでしょう。 軽率に使っていきましょう。

グラフ構造と木構造もお手の物

RDB はグラフ構造と木構造の扱いが苦手だという話がありますが、それは大昔の話なので、そのような古い情報はガン無視してください。 先に軽く触れましたが、最近のメジャーな OSS の RDBMS (MySQL, MariaDB, PostgreSQL, SQLite など) はどれも再帰クエリ (WITH RECURSIVE) に対応しています。 グラフ構造や木構造を表現するために非自明な工夫を凝らさずとも、自然に木構造や「関係性」そのものを扱えるようになっているのです。

まとめ

RDB はいいぞ。 表計算ソフトの代わりに軽率にくだらない用途に使っていこうな。

詳しいことはググれば無限に出てくるので、やる気が出たならこんなしょーもない記事ではなくもっとマトモな情報を読んでください。