SlideShare una empresa de Scribd logo
1 de 54
Descargar para leer sin conexión
必読名著

SQLアンチパターンの紹介
+ とあるOSSの闇
PHPカンファレンス北海道2019
株式会社ゆめみ 川井健太
!1
プロフィール
• 川井健太(Qiita ID = Mister_K)
• 株式会社ゆめみ サーバーサイドエンジニア
• Laravel, AWS, Serverless, 木材 とかで開発してます
• 趣味は沢山。バイクに乗ります。
!2
この発表は……
• QiitaでちょっとバズったSQLアンチパターンの解説です
• どちらかというとDB設計初学者向けです
• 名著SQLアンチパターンを例を用いて一部解説します
• 実例を用いて設計の大切さを伝えます
!3
!4
発表概要
• SQLアンチパターンとは?
• 見るに耐えないER図の紹介
• アンチパターンの紹介
• アンチパターンを回避しよう
• とあるOSSに潜むアンチパターン
• 究極のアンチパターンとは
!5
SQLアンチパターンとは?
設計者が良かれと思って施した設計が
裏目に出て酷い目に合うパターン
!6
!7
とある債務管理システム
ざっくりとした要件として
1. 債務者を登録でき、プロフィールを入力できる。
2. 債務者の家族構成を登録でき、そのプロフィールを入力できる。
3. 連帯保証人を登録でき、そのプロフィールを入力できる。
4. 取り立て人が債務者に借金の回収に行って、それを記録できる
5. 債務者の借金を管理できる。
6. 債務者の返済状況を管理できる。
7. 債務者、家族、連帯保証人をブラックリストで管理できる。
!8
!9
とある
空想上の
債務者
管理
システム
ジェイウォーク(信号無視)
目的:複数の値を持つ属性を格納する
!10
カンマ区切りのリストを格納する
!11
とある
空想上の
債務者
管理
システム
やってしまった事
• debtors.families に families.id を

カンマ区切りで入れて関連させている
• これにより債務者に複数の家族を設定できるようにした
!12
id … families
1 … 1,2,3
2 … 4,5
3 … 6,7
debtorsテーブルのレコード
どうなるのか?
• 家族を追加するたびに debtors のレコードを更新する必
要が出てしまう
• プログラムのバグにより、重複が発生する可能性がある
• JOIN句が複雑になる(正規表現が必要&インデックス無効)
!13
Entity Attribute Value
目的:可変属性をサポートする
!14
Key:Valueの汎用的な属性テーブルを使用する
!15
とある
空想上の
債務者
管理
システム
やってしまった事
• debtor の属性を汎用的にするため、profiles に
Key:Valueで値をストアするようにした
!16
id key Value
1 is_dead 0
2 middle_name John
どうなるのか?
• SQLで用意したデータ制約が利用できなくなる

よって値の整合性はコードで保障せねばならない
• 例えばNOT NULL制約も使えない
!17
ナイーブツリー
目的:階層構造を格納し、クエリを実行する
!18
常に親のみに依存する
!19
とある
空想上の
債務者
管理
システム
やってしまった事
• 連帯保証人を定義するため debtors.joint_garantor_id
を定義した
• これに debtors.id を入れる事で、債務者と連帯保証人の
関係を定義できるようにした
!20
どうなるのか
• RDBMSによっては、

クエリの長さが拾う階層分だけ長くなってしまう
!21
SELECT d1.* d2.*, d3.*
FROM debtors c1
LEFT OUTER JOIN debtors c2
ON c2.joint_garantor_id = c1.joint_garantor_id
LEFT OUTER JOIN debtors c3
ON c3.joint_garantor_id = c2.joint_garantor_id
3階層まで拾う場合のクエリ
どうなるのか?!
• RDBMSによってはメンテナンスが大変

外部キー制約がある場合は簡単にノードを削除できない
!22
Debtor
Id = 1
Debtor
Id = 2
parent = 1
外部キー制約があると削除できないし、
ノードの昇格も難しい
アンチパターンの例外
• 共通テーブル式を用いた再帰クエリの使えるRDBMSであ
れば問題ない
• 例として
• MySQL 8.0以上
• PostgreSQL 8.4以上
!23
IDリクワイアド
目的:主キーの規約を確立する
!24
全てのテーブルに id 列を用いる
!25
とある
空想上の
債務者
管理
システム
やってしまった事
• 全てのテーブルに id カラムを用意した
!26
どうなるのか
• 冗長となる場合がある
• 重複行を許可してしまう場合がある
• キーの意味がわからなくなる

例えばJOIN したらどっちの id だかわからない
!27
ポリモーフィック関連
目的:複数の親テーブルを参照する
!28
二重目的の外部キーを使用する
!29
とある
空想上の
債務者
管理
システム
やってしまった事
• ブラックリストで債務者とその家族を管理したい
• だから blacklist.debtor_family_id には debtors.id,
families.idのいずれかが入るようにした
!30
Id debtor_family_id
1 24(debtors の id)
2 24(families の id)
どうなるのか
• 外部キー制約、つまり参照整合性制約を定義できない
• 誤って参照先の存在しないブラックリストのレコードがで
きてしまうかも。
• 外部キー制約なんて邪魔?

それこそアンチパターンの一つ!
!31
アンチパターンを回避しよう
!32
!33
リファクタリング後のER図
ポリモーフィック関連回避
• 共通の親テーブルを作成する

例:debtor の親クラスを作り、それをブラックリスト
に追加する。
!34
債務者
• 人物id
人物
!35
今回は人物エンティティ
に統一した
連帯保証人は契約単位で
設定されるので、別にテー
ブルを用意して人物を関
連づけた
ナイーブツリー回避
• 共通テーブル式を指定する再起クエリを利用できる
RDBMSを用いる
• 代替ツリーモデルを使用する

経路列挙 ディレクトリ構造を記録するカラムを追加する。

入れ子集合 子孫の集合に関する情報を各ノードに格納する。

閉包テーブル エンティティの親子関係を定義する別のテーブルを用意。

詳しいことは本を見てくれ!
!36
ジェイウォーク回避
• 交差(関連、中間)テーブルを作成する
!37
familie
Id = 2
debtor
Id = 3
closs_table
debtor_id = 3
familie_id = 2
!38
家族関係の交差
テーブルを作成した。
同時にナイーブツリーの
回避も行なった。
EAV回避
• 要件を絞る

とりあえず拡張できるようにするには犠牲を伴うため
• サブタイプのモデリングを行う
• JSON型を用いる
!39
!40
債務者
• Id
• Name
• Address
低評価債務者
• has_bunkrupt
特別債務者
• is_richmen
要件を確定し、

債務者を3パターンに分ける
SELECT するときはサブテー
ブルを JOIN して用いる
やはり要件は絞る必要がある
サブタイプモデリング
!41
要件を整理して
項目を絞った
idリクワイアド回避
• 複合ユニークキーを用いる
• テーブル名_id と言うように名前をつける
!42
!43
person_to,
person_from
複合主キーを定義
ここからは
PHPに関係するお話
!44
この世には
多くの人に使われる
闇を抱えしOSSが存在する
!45
!46
WordPressとは
• オープンソースのブログソフトウェア

ウェブサイトのCMSとしても使われる
• SEOに最適化されている点でとても強い

34%のウェブサイトがWordPress製らしい(公式より)
• 2003年に最初のバージョンが世に出た
!47
!48
WordPressの
ER図
(v4.9時点)
!49
EAVが使われている!
何故EAVを使ったのか考察
• 最初にWordPressを作った人が、とりあえずEAVを使っ
た。
• 2003年当時、json型はなかった。
• SQLアンチパターンの初版が2010年なので、認知もさ
れていなかっただろう。
!50
何故EAVを使ったのか考察
• WordPressがウケたが、既にデータはストアされていて
手を出せなくなっていた。
• 自社でソース・データベースを管理していたら改善はでき
ただろうが、WordPressは世界中で動きすぎた。
• スキーマをメタテーブルで管理する地獄もある
!51
WordPressから学べる事
• とりあえず世に出すことは大切
• でもデータベースはちょっと考えろ!

ウケた時どうなっても知らんぞ!
• 究極、ソースは後からどうにでもなる

データベースは容易に変更できない
!52
究極のアンチパターンとは
将来的な変更や
アンチパターンを意識せず
適当に設計をすること
!53
!54
https://www.satofull.jp/static/oenkifu/201909_typhoon_15.php
さとふる にて募金を受け付けています
ご静聴ありがとうございました

Más contenido relacionado

La actualidad más candente

Javaから見たRubyの世界
Javaから見たRubyの世界Javaから見たRubyの世界
Javaから見たRubyの世界
Takafumi Yoshida
 
クラスメソッド会社説明会 in 北海道札幌 at smokeymonkey #cmdevio
クラスメソッド会社説明会 in 北海道札幌 at smokeymonkey #cmdevioクラスメソッド会社説明会 in 北海道札幌 at smokeymonkey #cmdevio
クラスメソッド会社説明会 in 北海道札幌 at smokeymonkey #cmdevio
smokey monkey
 
元インフラエンジニアが
Scalaを触ってつまづいたところ。
元インフラエンジニアが
Scalaを触ってつまづいたところ。元インフラエンジニアが
Scalaを触ってつまづいたところ。
元インフラエンジニアが
Scalaを触ってつまづいたところ。
takako onoue
 
クラスメソッド会社説明会in札幌 — メンバー紹介 #cmdevio
クラスメソッド会社説明会in札幌 — メンバー紹介   #cmdevioクラスメソッド会社説明会in札幌 — メンバー紹介   #cmdevio
クラスメソッド会社説明会in札幌 — メンバー紹介 #cmdevio
Shuji Watanabe
 

La actualidad más candente (20)

NoNoSQL
NoNoSQLNoNoSQL
NoNoSQL
 
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
 
頑張りすぎないScala
頑張りすぎないScala頑張りすぎないScala
頑張りすぎないScala
 
SaCSS vol.56 こんなに素敵なBrackets!
SaCSS vol.56 こんなに素敵なBrackets!SaCSS vol.56 こんなに素敵なBrackets!
SaCSS vol.56 こんなに素敵なBrackets!
 
[Scalamatsuri2016]あ、社内コミュニティ
[Scalamatsuri2016]あ、社内コミュニティ[Scalamatsuri2016]あ、社内コミュニティ
[Scalamatsuri2016]あ、社内コミュニティ
 
ぼくのかんがえたさいきょうの Rails スタートダッシュ
ぼくのかんがえたさいきょうの Rails スタートダッシュぼくのかんがえたさいきょうの Rails スタートダッシュ
ぼくのかんがえたさいきょうの Rails スタートダッシュ
 
Javaから見たRubyの世界
Javaから見たRubyの世界Javaから見たRubyの世界
Javaから見たRubyの世界
 
クラスメソッド会社説明会 in 北海道札幌 at smokeymonkey #cmdevio
クラスメソッド会社説明会 in 北海道札幌 at smokeymonkey #cmdevioクラスメソッド会社説明会 in 北海道札幌 at smokeymonkey #cmdevio
クラスメソッド会社説明会 in 北海道札幌 at smokeymonkey #cmdevio
 
元インフラエンジニアが
Scalaを触ってつまづいたところ。
元インフラエンジニアが
Scalaを触ってつまづいたところ。元インフラエンジニアが
Scalaを触ってつまづいたところ。
元インフラエンジニアが
Scalaを触ってつまづいたところ。
 
CSSから国民を守る党ver2
CSSから国民を守る党ver2CSSから国民を守る党ver2
CSSから国民を守る党ver2
 
MultiParadimeDesign
MultiParadimeDesignMultiParadimeDesign
MultiParadimeDesign
 
クラスメソッド会社説明会in札幌 — メンバー紹介 #cmdevio
クラスメソッド会社説明会in札幌 — メンバー紹介   #cmdevioクラスメソッド会社説明会in札幌 — メンバー紹介   #cmdevio
クラスメソッド会社説明会in札幌 — メンバー紹介 #cmdevio
 
おっさんES6/ES2015,React.jsを学ぶ
おっさんES6/ES2015,React.jsを学ぶおっさんES6/ES2015,React.jsを学ぶ
おっさんES6/ES2015,React.jsを学ぶ
 
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
 
【アジャイルサムライ】6章_ユーザストーリーを集める
【アジャイルサムライ】6章_ユーザストーリーを集める【アジャイルサムライ】6章_ユーザストーリーを集める
【アジャイルサムライ】6章_ユーザストーリーを集める
 
TDD BootCamp in JJUG CCC - レガシーコード対策編 -
TDD BootCamp in JJUG CCC - レガシーコード対策編 -TDD BootCamp in JJUG CCC - レガシーコード対策編 -
TDD BootCamp in JJUG CCC - レガシーコード対策編 -
 
カスタムNodeのススメ
カスタムNodeのススメカスタムNodeのススメ
カスタムNodeのススメ
 
Microservices Architecture の利点と欠点
Microservices Architecture の利点と欠点Microservices Architecture の利点と欠点
Microservices Architecture の利点と欠点
 
ゲーム会社でのRuby : rails活用事例
ゲーム会社でのRuby : rails活用事例ゲーム会社でのRuby : rails活用事例
ゲーム会社でのRuby : rails活用事例
 
【ScalaMatsuri2016】関西のScalaコミュニティ紹介
【ScalaMatsuri2016】関西のScalaコミュニティ紹介【ScalaMatsuri2016】関西のScalaコミュニティ紹介
【ScalaMatsuri2016】関西のScalaコミュニティ紹介
 

Similar a Introduction of SQL Anti-pattern at Phpcon Hokkaido

Rdbms起点で考えると見えない世界 okuyama勉強会
Rdbms起点で考えると見えない世界 okuyama勉強会Rdbms起点で考えると見えない世界 okuyama勉強会
Rdbms起点で考えると見えない世界 okuyama勉強会
Masakazu Muraoka
 

Similar a Introduction of SQL Anti-pattern at Phpcon Hokkaido (20)

リーダブルパスワード - SQLアンチパターンより抜粋 -
リーダブルパスワード - SQLアンチパターンより抜粋 -リーダブルパスワード - SQLアンチパターンより抜粋 -
リーダブルパスワード - SQLアンチパターンより抜粋 -
 
KPT発表会 - アジャイルひよこクラブ
KPT発表会 - アジャイルひよこクラブKPT発表会 - アジャイルひよこクラブ
KPT発表会 - アジャイルひよこクラブ
 
Railsエンジニアが サーバーレスアーキテクチャに 手を出したよ - 川崎Ruby会議01
Railsエンジニアが サーバーレスアーキテクチャに 手を出したよ - 川崎Ruby会議01Railsエンジニアが サーバーレスアーキテクチャに 手を出したよ - 川崎Ruby会議01
Railsエンジニアが サーバーレスアーキテクチャに 手を出したよ - 川崎Ruby会議01
 
SQLで陥りがちなアンチパターンを知ろう「SQLアンチパターン」
SQLで陥りがちなアンチパターンを知ろう「SQLアンチパターン」SQLで陥りがちなアンチパターンを知ろう「SQLアンチパターン」
SQLで陥りがちなアンチパターンを知ろう「SQLアンチパターン」
 
Works of site reliability engineer
Works of site reliability engineerWorks of site reliability engineer
Works of site reliability engineer
 
サーバサイドエンジニアが 1年間まじめにSPAやってみた
サーバサイドエンジニアが 1年間まじめにSPAやってみたサーバサイドエンジニアが 1年間まじめにSPAやってみた
サーバサイドエンジニアが 1年間まじめにSPAやってみた
 
Scalaz-StreamによるFunctional Reactive Programming
Scalaz-StreamによるFunctional Reactive ProgrammingScalaz-StreamによるFunctional Reactive Programming
Scalaz-StreamによるFunctional Reactive Programming
 
Ph perがawsと出会ってdev opsを目指した話
Ph perがawsと出会ってdev opsを目指した話Ph perがawsと出会ってdev opsを目指した話
Ph perがawsと出会ってdev opsを目指した話
 
オープンソース・データベースの最新事情
オープンソース・データベースの最新事情オープンソース・データベースの最新事情
オープンソース・データベースの最新事情
 
MacroPyがすごい
MacroPyがすごいMacroPyがすごい
MacroPyがすごい
 
Rdbms起点で考えると見えない世界 okuyama勉強会
Rdbms起点で考えると見えない世界 okuyama勉強会Rdbms起点で考えると見えない世界 okuyama勉強会
Rdbms起点で考えると見えない世界 okuyama勉強会
 
uroboroSQLの紹介 (OSC2017 Tokyo/Spring)
uroboroSQLの紹介 (OSC2017 Tokyo/Spring)uroboroSQLの紹介 (OSC2017 Tokyo/Spring)
uroboroSQLの紹介 (OSC2017 Tokyo/Spring)
 
クラウドネイティブ世代がインフラに触れるということ
クラウドネイティブ世代がインフラに触れるということクラウドネイティブ世代がインフラに触れるということ
クラウドネイティブ世代がインフラに触れるということ
 
PHP&NewSQLで考える次世代アプリケーション
PHP&NewSQLで考える次世代アプリケーションPHP&NewSQLで考える次世代アプリケーション
PHP&NewSQLで考える次世代アプリケーション
 
AWS CDKに魅入られた PHPer がオススメする
AWS CDKに魅入られた PHPer がオススメするAWS CDKに魅入られた PHPer がオススメする
AWS CDKに魅入られた PHPer がオススメする
 
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
 
コモディティL3SW/ルータでオープンなSDNを実現しよう
コモディティL3SW/ルータでオープンなSDNを実現しようコモディティL3SW/ルータでオープンなSDNを実現しよう
コモディティL3SW/ルータでオープンなSDNを実現しよう
 
わかると楽しいInfrastructure as code
わかると楽しいInfrastructure as codeわかると楽しいInfrastructure as code
わかると楽しいInfrastructure as code
 
はじめてのAWS設計でやりがちな失敗パターンまとめ
はじめてのAWS設計でやりがちな失敗パターンまとめはじめてのAWS設計でやりがちな失敗パターンまとめ
はじめてのAWS設計でやりがちな失敗パターンまとめ
 
ServerlessとMicroserviceの難しさに立ち向かう
ServerlessとMicroserviceの難しさに立ち向かうServerlessとMicroserviceの難しさに立ち向かう
ServerlessとMicroserviceの難しさに立ち向かう
 

Introduction of SQL Anti-pattern at Phpcon Hokkaido