#db_jissen_night リレーショナルモデルについて熱く漢が語る、理論から学ぶデータベース実践入門に参加したまとめ
理論から学ぶデータベース実践入門という本がございますが、その著者である@nippondanji様が登壇して発表してくれるという勉強会「理論から学ぶデータベース実践入門Night」があったので飛びついて参加してきました。
その際のメモになります。
なぜ、いまリレーショナルモデルなのか
なぜいまさら?
- リレーショナルモデルは非常に枯れた理論
- 最近はBIGDATAや、どうやって大量アクセスを処理するかなど、リレーショナルモデルと関係ない問題だったりする
- リレーショナルモデルは理論の話なので座学で小難しい話ばかりで避けていたのではないか
- 本気でリレーショナルモデルを語ってる人がいない
巷にあふれるあやふやな情報
- バックグラウンドにある理論が抜けてたりしていてSQLにふれない解説があったりする
- 理論に基づかないノウハウが多い
- リレーションは2次元のひょうです -> 理論が間違っている
- DBは単なる入れ物です-> リレーショナル関係ない
- 正規化の目的は冗長性の排除です ー> ちょっとまちがってるね
- 正規形は第3までおkです -> その根拠は?
- すべてのテーブルにサロゲートキーをつけるべき -> それはどうなの?何の議論にもとづいているか?
- ORMを使えばSQLは知らなくてもいい -> ふざけるなよ
- @nippondanji氏の感情は高ぶっていく・・・
そして真実を知るものは現場からいなくなった
- クソクエリだらけでも世の中はなんとか回っているが、開発効率が悪いために、デスマーチがたくさん発生しているのではないか
- -> どげんかせんといかん!ということで本を書きました
本で伝えたいこと
- リレーショナルモデルの…重要性、本当の姿、使い方、限界、リレーショナルモデル以外に必要な知識
- C.J.Dateさんの本がおすすめ
- 日本のちゃんとした本がなかった
- あくまで本書は入門書なので日々皆様勉強していきましょう
リレーショナルモデルは道具
- あくまで目的に達成するために使う手段なので、道具には道具にあった使い道がある
データモデルとは
- データの論理的な表現方法のこと
- データを構成するのにどういう要素があるか、データに対する演算など
- カラムストアはどういうふうに物理的にレイアウトしてるのであってデータモデルではない
- DB設計のことでもない
データモデル=データ設計?
- データモデルは二通りの意味で使われる問題があるが、両者の意味は全く違う
- ちゃんと区別して使ってる人は少ない
- 本書はデータの倫理的な表現方法として認識して下さい
データは格納するだけで終わりではない
- アプリケーションがちゃんと利用して初めてDBの意味があるので、データの格納の仕方やデータを的確に出し入れするのが重要になっていく
データモデルと演算
- データモデル上に定義されたデータはいろいろあるが、それはなにか
- データの意味から演算の種類が必然的に決まってくる
- 整数値に対しては四則演算が定義されていたり、文字列に対しては分解・連結が定義されていたり・・・(逆はない)
- それとおなじ感覚でリレーショナルモデルには射影や結合などの演算があるが、これは処理系に最初から用意されているので高速で信頼できる
- 用意された演算を適切に使えば簡潔に使える
- 例えば1万個のカンマ区切りの文字列で配列を実装するケースで考えた場合、カンマが一万個目の要素になるまでスキャンとしないといけない
- 文字列の中にカンマが含まれてるとどうするのなど、いろいろ考えないといけない
- めんどくさいし、遅いし、もし実装してもバグだらけだが、そもそも実装する必要が無い
DBを単なる入れ物だと考えてはいけない理由
- なぜならDBはデータモデルを意識して作られているから
- データモデルに沿った演算というのが得意
- どうしてDBが単なる入れ物と考えるのか?
- 自分で書けばなんでもできると考えてるから
- そもそもデータモデルを知らないのでは
プログラミングパラダイムとデータモデル
- 昔は手続き型しかなかったが、オブジェクト指向や関数型が出てきたりした
- それぞれのプログラミング言語には適した書き方がある
- たとえばJavaはオブジェクト指向で書くべき
- DBを単なるデータの入れ物という考え方はjavaでmainメソッドに全てを記述するのに等しい
様々なデータモデル
- リレーショナルモデル
- グラフ
- 階層型
- キーバリュー
- オブジェクト
- XML
- ドキュメント
適切なデータモデルを選ぶ
- どんなケースにもRDBを使えとは思っていない。アプリケーションによって使うものは変わるので双方向で適切なものを選んでいきましょう。
- どいういうことができるか、アプリケーションがどんな機能が必要かで考える
- できることは1つだけではないのでメンテナンス性などの利点を考えて最大公約数で選ぶようにしましょう
- 演算がうまく表現できないものも存在するが、データモデルに合致しない部分はデータベースソフトウェアが備えている、データモデルから逸脱した演算(ソートやマテビューなど)を活用するとうまく解決できたりする。
1つのデータモデルでは足りない場合
- 複数の製品を組み合わせる
- しかし複数のデータが分散してしまうので、データをどう管理するかという問題も発生するが、分散トランザクションがあれば理想的に使える
- トランザクションがない製品はキャッシュを使う
- マルチモデル
- 例えばMySQLもJSON型をもつようになったりと、1つの製品が複数のデータモデルをもつものがある
- データの同期について考える必要がないが、スケーラビリティが課題になる
リレーショナルモデル
- 集合に根ざしたデータモデル
- リレーションという名前のデータ構造を用いてデータを表現する
- リレーションが集合になる
- リレーショナルモデルとはテーブル同士の関係性を表現するものと書いてあったりするが、その認識は改めましょう!
- 集合演算に基づいたもに射影などの演算がつく
- リレーションはデータそのもので、テーブル同士の関係性のことではない
- リレーションとは物事に対する事実の集合であるので、テーブル≒リレーションになる
集合の性質
- テーブルと比較すると重複もなく、NULLもなく、要素間に順序がない
- 要素が含まれるかどうかだけが重要
リレーションの構成部品
- リレーション=見出し+本体
- 見出しは属性の集合
- 属性は名前と型
- 属性値は属性で定義された型を持つ値 ≒ 列
- 組(タプル)は見出しに対応した属性値の集合 ≒ 行
- 本体は組の集合
- リレーショナルモデル≠SQL
データモデルを知ることは超重要
- データにはそれぞれの性質にあった演算がある
- リレーションとしてデータを表現することが重要
- しかしリレーショナルモデルには適さないデータがあるので、そういったデータにはリレーショナルモデルを適用すべきでない
- ただ、 適するかかどうかを判断するにはちゃんとリレーショナルモデルを知っておく必要がある
SQLとリレーショナルモデル
- SQLにあってリレーショナルモデルにないものは、行データの重複、行データの順序、カラムの順序、テーブルの更新、ストアドプロシージャ、トリガー、トランザクション、NULL
- リレーションには更新という概念がない。
なぜSQLとリレーショナルモデルは違うのか
- なぜならリレーショナルモデルには浅いところで限界がある
- 格納できるのは集合として表現できるものに限る
- 実行できる演算はリレーションの演算のみでループの演算などはできない
- しかしアプリが必要とするデータは多種多様でリレーショナルモデルだけは足りなかった
- そのうち更新という概念が実装上どうしても必要だったのでトランザクションというのが必要になってきたと背景にあるのではないかと考える
- つまり、リレーショナルモデルよりもSQLのほうが適用範囲が広いのでここまでRDBは普及したのではないか
- しかしそれは諸刃の剣
NULLの功罪
- NULLはすごく便利だが、代償は大きかった
- Unknownな値とは何か
- 3血論理による理論の組み立ての複雑さの上昇
- true falseよりもかなり複雑
- 閉世界仮説の崩壊 -> リレーショナルモデルを根底から覆す
- オプティマイザも真価を発揮できない
- 今扱ってるデータがリレーショナルモデルの範疇かどうかを、NULLがあってもいいかどうかで見極める
データの正しさについての考察
正しいデータを得られないDBは無価値
- なぜDBを使うかというのは正しい答えが欲しいから。
RDB上でデータの正しさを保つ
- トランザクション
- 同時アクセス時の整合性、クラッシュリカバリ
- リレーショナルモデル
- 論理的に真となる命題の集合だが、論理的な矛盾があると、どんな帰結でも正しい答えが得られない
- 正規化理論
- 重複を排除することで論理的な矛盾の回避をした
- これがなぜ正規化をするかという理由
- たまにデータを小さくすると言った意味で使ってる人がいるが、それは違う
- 制約
- こういうデータは含めるべきではないと制約が含められるのでビジネスロジック上、おかしなデータをはじくことができる
- 以上の特性があったとしてもデータの間違いを防ぐことはできない
- 例えばユーザが入力を間違えてしまっていたりなど。
- データの正しさを保つのは難しい
NoSQL上でデータの正しさを保つ
- RDBのような便利な道具(トランザクション、リレーショナルモデル、制約など)がない
- データの正しさの保証はアプリケーション側で保証しないといけない
- データの正しさを保証するためのコードをかかないといけない -> しかしこのコードにバグがあるかもしれない -> 防ぐためにテストコードが増殖していく
分離レベルとデータの正しさ
- 分離レベルはトランザクションの概念であってリレーショナルモデル上にはそんな概念はない
- これを理解しないと危ない状況になるのではないかと思っている
- 分離レベルと整合性
- SERIALIZABLE
- リレーショナルモデルをもっとも忠実に体現できるがロックが多い。
- REPEATEABLE-READ
- 参照系においてロックを使わない。データの更新があってもちょっとまえのデータを読み取る形になる。
- ファントムリードがおきてもいいということになるので気をつけましょう。
- しかしMySQLではファントムリードが発生しない!!
- READ-COMMITED
- 本当は使うのが難しいがクエリごとに見えるデータが違って見えてきてしまうので、自分でロックなどをしないと不整合が起きてしまう
- READ-UNCOMMITED
- 一体何に使うのかはわかってない。ダーティなデータをみれるからリアルタイムなデータをみれるなどあるがそれならTCP/IPで直接見ればいいし。。
- SERIALIZABLE
分離レベルの注意点
- 製品によって違いがあるので製品の実装をよく知りましょう
- 名称が違ったり、4つ以上のレベルが合ったり
- 例えばMySQLではREPEATEABLE-READでファントムリードが発生しないが、SQL標準上は出るのが正しい
- ロックする時に取る値とロックしないときに取る値が違ったりする
- READ-UNCOMMITEDが早いのは本当か?
リレーショナルモデルの恩恵
開発効率が上がる
- クエリの記述がシンプルになる
- 全てのクエリは単一のクエリでかかないといけないが、裏を返せば単一のクエリでデータが得られるのでクエリが宣言的になる。そうなれば各効率が上がり、論理演算で結果にゆるぎがない。
- データを検査するコードが減る
- スキーマが決まっているので、ちゃんとしたデータかどうかをチェックする必要が無い
- 重複が排除されるので不整合を考える必要が無い
- 制約やトランザクションがあるのでアプリケーション側で考える必要もない
- テストコードも減る
- すなわちデスマーチ回避!
クエリが効率的になる
- スパゲッティクエリ撲滅
- シンプルなクエリはインデックスがききやすい
- 1回のクエリでデータがとれるのでクライアントとサーバ間のトラフィックも減らせる
- 正規化のおかげで更新なロジックがシンプルになることで論理的な矛盾をチェックする必要もなくなる
- すなわちRDBが真価を発揮!!
- ちゃんとした使い方をしていないのにも関わらず、遅いとかいう人がいたら@nippondanjiのもとへ連れて来て下さい。
道具を正しく使うことでのデメリットは特にない
- リレーショナルモデルが適用できないデータはあるので注意しましょう
- RDBを使うべきでないケースもある
実装について意識する
データモデルは論理的な表現
- 論理的な表現 = データモデル
- 物理的な表現 = 実装
実装について知ることの意義1
- 性能が出ないアプリケーションは役に立たないので日々ベンチマークなどをとって性能を見るのは超重要
実装について知ることの意義2
- 想定通りの動作になるかは製品の実装によりけりなのでテストが重要
- SQL標準 ≠ 実装
実装と論理の混同ダメ、ゼッタイ
- 実装はデータモデルの一部ではないので理論と実装は別々に考える
- 論理設計を考えてから物理設計を考える
結論:なぜ、今リレーショナルモデルなのか
- 古くからある技術だが、ちゃんと使われていなかったり、あやふやな情報があふれていたりするので、道具を使うためにリレーショナルモデルの使い方を理解しましょう
- 本質的にはリレーショナルモデルは流行り廃りで理論が変わったりせず、代替の理論もないので今後の世の中にも必要
Q&A
リレーショナルモデル以外にも注目しているモデルや数学の理論はあるか?
- グラフDBは現状Neo4jしか選択肢がないので、いいものが出てくればいいなぁと思っている。
- スケールも難しいのでどうやってスケールするか興味ある
- ドキュメントDBはどう頑張っていくのか生暖かい目で見ている
- XML型DBは最近息してない
- 最近やった圏論DBについてはしっくりこなかった
ならば(その弐)
ここからお酒を飲みながらのLTだったため、あまりメモはございません。
ならば(その弐) from Tomoaki Hiramoto
包含(ならば)は以下の式になる
P | Q | P⊃Q |
真 | 真 | 真 |
真 | false | false |
false | 真 | 真 |
false | false | 真 |
魔法少女で置き換えると契約した場合以外、考慮しない!!
契約(P) | 魔法少女(Q) | 契約(P)⊃ 魔法少女(Q) |
した | なる | 願い叶う |
した | ならない | 願い叶わない |
しない | なる | 願い叶う |
しない | ならない | 願い叶う |
DatalogからSQLへのトランスレータを書いた話
- 宣言型言語のDatalogの紹介とデモでしたが、残念ながらデモは時間切れでみれませんでした。
- リレーショナルDBへのクエリをSQL以外で書いた!
- Datalogを使うことで複雑なJOINを行うクエリや再起クエリを部品化できた!
MVCCでちょっとハマった話
- MultiVersion Concurrency Controlというトランザクションの並列性を高めるために編み出された仕組みがMVCC
- 制約のタイミングで商品在庫をupdateする仕組みを作っていたが、なぜか商品のSELECT文が遅くなった
- 原因はMVCCを使うとスナップショットをロールバックセグメントに貯めていってしまい、SELECTのためにそのスナップショットを全部読み込むためだった模様
NULLとの戦い
- nullセーフな等価がMySQLでは<=>でかけるがSQL標準だと以下のように長くなる
- a IS NOT DISTINCT FROM b
- 空文字がNULLになるOracle
PostgreSQLの配列型について
- ポスグレはデータに配列を入れられるので簡単に1 : Nの関係でデータががとれる
- しかし、とりだすときに使いにくい値で帰ってくるのでいろんな方法でより扱いやすいデータに取り出す方法はあるのだが、どれもつかいづらいのでそれをどうにかしてほしいというお話でした
- @nippondanji氏いわく、データに配列をいれるのは問題ないが、それを取り出して分解してゴチャゴチャやるのは問題ありとのこと
集合演算を真っ向から否定するアレの話
- DB理論も大事だがストアドプロシージャすげーんじゃないか!?というお話
- 498個のストアドプロシージャを書いたサービスも作ったそうです(キャッシュとかエラーとか大変そう・・・)
@mogmetの所感
奥野さんのお話はとても奥深いお話でした。
日頃から思っていたことでしたが、全てをRDBのケースで解決できない場合は、様々な解決するためのアプローチが最近は他にも色々出てきているので適材適所で組み合わせて使うというのを改めて大事だと感じました。
あと、演算で解決できない場合はデータモデルから逸脱した演算を使うと解決できるとありましたが、ふと思ったのはOracleはそういった演算がふんだんに実装されているから力技で大体解決できてしまうため、昔からたくさんのところで使われてきたのかなぁと思いました。(なんだかOracleの回し者みたいだ)
そしてLTもとてもおもしろいお話ばかりでていたので案外potatotipsみたいに月1開催でLT勉強会してもいろいろでてくるんじゃないかと思いました。