Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
PostgreSQLアンチパターン
What is it?
RDBの限界を感じた事ありませんか?
What is it?
PostgreSQLは銀の弾丸ではありません
What is it?
アンチパターン
What is it?
アンチパターン
↓
良かれと思ってした事が後々に苦しみを生む
What is it?
アンチパターンを知る
What is it?
アンチパターンを知る
↓
同じ過ちを繰り返さない
What is it?
愚者は経験に学び、賢者は歴史に学ぶ
      オットー・フォン・ビスマルク
What is it?
What is it?
SQLアンチパターンは厳選された失敗集
What is it?
SQLアンチパターンは厳選された失敗集
↓
DBのノウハウが詰まった名著
What is it?
しかしMySQLがベース
What is it?
今日はPostgreSQLの失敗例をご紹介します
What is it?
SQLアンチパターン本の内容
とは全く関係ありません
What is it?
俺の屍を越えて行け
あじぇんだ
1 自己紹介
2 とりあえず削除フラグ
3 困ったときの配列型とJSON型
4 マテビューの功罪
5 まとめ
あじぇんだ
1 自己紹介
2 とりあえず削除フラグ
3 困ったときの配列型とJSON型
4 マテビューの功罪
5 まとめ
自己紹介
名前:曽根 壮大(そね たけとも)
年齢:31歳(三人の子供がいます)
職業:Webエンジニア
所属:日本PostgreSQLユーザ会
   中国支部 支部長
  技術的にはLL系言語とかRDBが好きです
中国地方DB勉強会
https://dbstudychugoku.github.io/
あじぇんだ
1 自己紹介
2 とりあえず削除フラグ
3 困ったときの配列型とJSON型
4 マテビューの功罪
5 まとめ
とりあえず削除フラグ
http://www.slideshare.net/t_wada/ronsakucasual
とりあえず削除フラグ
こんなカラム名を
作ったことありませんか?
とりあえず削除フラグ
hoge_delete_flag
とりあえず削除フラグ
会員削除フラグ…
顧客削除フラグ…
hogeデータ削除フラグ…
とりあえず削除フラグ
論理削除と言う名の闇
とりあえず削除フラグ
とりあえず削除フラグ
論理削除はなぜダメなのか?
とりあえず削除フラグ
論理削除の理由
とりあえず削除フラグ
• エンドユーザから見えなくしたいがデータは消したくない
• 削除したデータを検索したい
• データを消さずにログに残したい
• 誤った操作をなかったことにしたい、直ぐに元に戻したい
とりあえず削除フラグ
そして生まれるDELETE_FLAG
とりあえず削除フラグ
論理削除のデメリット
とりあえず削除フラグ
• 積み重なるWHERE delete_flag = 0
• Unique制約が使えなくなる
• 複雑な表示条件(Query)の原因
とりあえず削除フラグ
• 積み重なるWHERE delete_flag = 0
• Unique制約が使えなくなる
• 複雑な表示条件(Query)の原因
積み重なるWHERE句
-- ブログを取ってきたい場合
SELECT
*
FROM
blog
WHERE
blog.delete_flag = 0
積み重なるWHERE句
-- ブログを取ってきたい場合
SELECT
*
FROM
blog
WHERE
blog.delete_flag = 0
ブログの削除フラグを見る
積み重なるWHERE句
-- ブログを取ってきたい場合
SELECT
*
FROM
blog
WHERE
blog.delete_flag = 0
ブログの削除フラグを見る
更新者アカウントが削除されてたら?
積み重なるWHERE句
-- 有効なアカウントのブログを取ってきたい場合
SELECT
*
FROM
blog
INNER JOIN users
ON users.id = blog.user_id
AND users.delete_flag =...
積み重なるWHERE句
-- 有効なアカウントのブログを取ってきたい場合
SELECT
*
FROM
blog
INNER JOIN users
ON users.id = blog.user_id
AND users.delete_flag =...
積み重なるWHERE句
-- 有効なアカウントのブログを取ってきたい場合
SELECT
*
FROM
blog
INNER JOIN users
ON users.id = blog.user_id
AND users.delete_flag =...
積み重なるWHERE句
-- 有効な所属の有効なアカウントのブログを取ってきたい場合
SELECT
*
FROM
blog
INNER JOIN users
ON users.id = blog.user_id
AND users.delete...
積み重なるWHERE句
-- 有効な所属の有効なアカウントのブログを取ってきたい場合
SELECT
*
FROM
blog
INNER JOIN users
ON users.id = blog.user_id
AND users.delete...
積み重なるWHERE句
-- 有効な所属の有効なアカウントのブログを取ってきたい場合
SELECT
*
FROM
blog
INNER JOIN users
ON users.id = blog.user_id
AND users.delete...
とりあえず削除フラグ
Queryの複雑度に対する対策
とりあえず削除フラグ
Queryの複雑度に対する対策
↓
有効なデータのViewを作る
とりあえず削除フラグ
Queryの複雑度に対する対策
↓
有効なデータのViewを作る
Queryの高速化にはならない
とりあえず削除フラグ
全てのINDEXのセカンダリに
DELETE_FLAGを入れる必要がある
とりあえず削除フラグ
全てのINDEXのセカンダリに
DELETE_FLAGを入れる必要がある
INDEXの肥大化よりも
そもそもINDEXを効かせる
複数のQueryを書くのが大変
とりあえず削除フラグ
PostgreSQLには
マテリアライズド・ビューがある
とりあえず削除フラグ
マテビューで有効データViewを作る
とりあえず削除フラグ
マテビューで有効データViewを作る
↓
高速でQueryもシンプル
とりあえず削除フラグ
マテビューで有効データViewを作る
↓
高速でQueryもシンプル
SELECT * FROM active_blog
とりあえず削除フラグ
それ、シンプルになるの参照だけ
とりあえず削除フラグ
それ、シンプルになるの参照だけ
↓
更新系で生まれる悪夢
とりあえず削除フラグ
更新したらマテビューを更新
とりあえず削除フラグ
更新したらマテビューを更新
↓
customersでもusersでもblogでも
更新があればマテビューも更新
とりあえず削除フラグ
更新したらマテビューを更新
↓
customersでもusersでもblogでも
更新があればマテビューも更新
頻発する
REFRESH MATERIALIZED VIEW
とりあえず削除フラグ
実際にはdeleteされないので
データは増え続ける
とりあえず削除フラグ
実際にはdeleteされないので
データは増え続ける
↓
マテビューの更新コストが肥大
とりあえず削除フラグ
実際にはdeleteされないので
データは増え続ける
↓
マテビューの更新コストが肥大
そして第三章の問題へ…
とりあえず削除フラグ
• 積み重なるWHERE delete_flag = 0
• Unique制約が使えなくなる
• 複雑な表示条件(Query)の原因
とりあえず削除フラグ
• 積み重なるWHERE delete_flag = 0
• Unique制約が使えなくなる
• 複雑な表示条件(Query)の原因
つまり外部Key制約も死ぬ
とりあえず削除フラグ
id name age deleted
1 soudai 30 1
2 soudai 30 0
3 sone 20 0
4 taketomo 31 0
とりあえず削除フラグ
id name age deleted
1 soudai 30 1
2 soudai 30 0
3 sone 20 0
4 taketomo 31 0
とりあえず削除フラグ
id name age deleted
1 soudai 30 1
2 soudai 30 0
3 sone 20 0
4 taketomo 31 0
同じユーザが2名いるので
Unique制約できない
とりあえず削除フラグ
id name age deleted
1 soudai 30 1
2 soudai 30 0
3 sone 20 0
4 taketomo 31 0
同じユーザが2名いるので
Unique制約できない
もちろん外部キー制...
とりあえず削除フラグ
id name age deleted
1 soudai 30 1
2 soudai 30 0
3 sone 20 0
4 taketomo 31 0
サロゲートキーで外部キー制約した場合は
関連したデータは別人扱いになる
とりあえず削除フラグ
id name age deleted
1 soudai 30 1
2 soudai 30 0
3 sone 20 0
4 taketomo 31 0
サロゲートキーで外部キー制約した場合は
関連したデータは別人扱いになる...
とりあえず削除フラグ
PostgreSQLには
Unique制約にWHERE句がある
Unique制約が使えなくなる
-- deletedが0の時にUnique制約をかける
CREATE UNIQUE INDEX
user_idx
ON
users (name)
WHERE
deleted = 0;
とりあえず削除フラグ
id name age deleted
1 soudai 30 1
2 soudai 30 0
3 sone 20 0
4 taketomo 31 0
とりあえず削除フラグ
id name age deleted
1 soudai 30 1
2 soudai 30 0
3 sone 20 0
4 taketomo 31 0
とりあえず削除フラグ
id name age deleted
1 soudai 30 1
2 soudai 30 0
3 sone 20 0
4 taketomo 31 0
とりあえず削除フラグ
id name age deleted
1 soudai 30 1
2 soudai 30 0
3 sone 20 0
4 taketomo 31 0
deletedが1なのでUnique制約対象外
とりあえず削除フラグ
id name age deleted
1 soudai 30 1
2 soudai 30 0
3 sone 20 0
4 taketomo 31 0
nameでUnique制約をかけれる
とりあえず削除フラグ
id name age deleted
1 soudai 30 1
2 soudai 30 0
3 sone 20 0
4 taketomo 31 0
nameでUnique制約をかけれる
しかし外部キー制約は死ぬ
とりあえず削除フラグ
Unique制約にWHERE句
↓
結局は外部キー制約は死ぬ
とりあえず削除フラグ
外部キー制約が死ぬ
とりあえず削除フラグ
外部キー制約が死ぬ
↓
テーブルの関連性の担保が死ぬ
とりあえず削除フラグ
データの不整合を防げない
とりあえず削除フラグ
データの不整合を防げない
↓
バグの温床になる
とりあえず削除フラグ
• 積み重なるWHERE delete_flag = 0
• Unique制約が使えなくなる
• 複雑な表示条件(Query)の原因
とりあえず削除フラグ
正しいデータを
表示させる条件が多い
積み重なるWHERE句
-- 有効な所属の有効なアカウントのブログを取ってきたい場合
SELECT
*
FROM
blog
INNER JOIN users
ON users.id = blog.user_id
AND users.delete...
とりあえず削除フラグ
1つのデータを取るために
関係するTABLEが多すぎる
とりあえず削除フラグ
「あのデータ取るには○○と☓☓と
△△をJOINしてWHEREしてSELECT
句にASで別名を付けて…」
みたいな事が頻発する
とりあえず削除フラグ
仕様変更の時の影響範囲が広い
とりあえず削除フラグ
仕様変更の時の影響範囲が広い
↓
つまりバグの温床になる
とりあえず削除フラグ
論理削除は使わないほうが良い
とりあえず削除フラグ
論理削除は使わないほうが良い
↓
TABLEに状態を持たせない
とりあえず削除フラグ
論理削除は使わないほうが良い
↓
TABLEに状態を持たせない
リレーショナルモデルで表現する
とりあえず削除フラグ
処方箋
とりあえず削除フラグ
有効なデータのみを残す
とりあえず削除フラグ
有効なデータのみを残す
↓
例えば削除済みTABLEを作る
とりあえず削除フラグ
deleted_usersusers
とりあえず削除フラグ
deleted_usersusers
soudai
sone
taketomo
とりあえず削除フラグ
deleted_usersusers
soudai
sone
taketomo
削除(DELETE文)
とりあえず削除フラグ
deleted_usersusers
soudai
sone
taketomo
soudai
トリガーで移す
とりあえず削除フラグ
deleted_usersusers
sone
taketomo
soudai
テーブルには実際のデータのみが残る
とりあえず削除フラグ
注意点
とりあえず削除フラグ
注意点
↓
トリガーは仕様変更に弱い
とりあえず削除フラグ
注意点
↓
トリガーは仕様変更に弱い
例えばALTER文でカラムを増やすと
トリガーが死ぬ
とりあえず削除フラグ
ケースバイケースで手法は選ぶこと
とりあえず削除フラグ
ケースバイケースで手法は選ぶこと
↓
論理削除は使わない
とりあえず削除フラグ
関連したテーブルは?
とりあえず削除フラグ
関連したテーブルは?
↓
必要なら削除済みTABLEを作る
不要ならDELETEする
とりあえず削除フラグ
関連したテーブルは?
↓
必要なら削除済みTABLEを作る
不要ならDELETEする
外部キー制約が使えればCASCADEも出来る
とりあえず削除フラグ
関連したテーブルは?
↓
必要なら削除済みTABLEを作る
不要ならDELETEする
外部キー制約が使えればCASCADEも出来る
事実のみを保存する
とりあえず削除フラグ
•ユーザの状態(statusカラム)
•課金状態(与信、請求済み)
•カート情報(カゴの中、購入済み)
類似例
とりあえず削除フラグ
DBに状態を持たせるのは危ない
とりあえず削除フラグ
DBに状態を持たせるのは危ない
↓
DBには事実のみを保存する
あじぇんだ
1 自己紹介
2 とりあえず削除フラグ
3 困ったときの配列型とJSON型
4 マテビューの功罪
5 まとめ
困ったときの配列型とJSON型
PostgreSQLは型が豊富
困ったときの配列型とJSON型
配列型やJSON型を使うと
困ったときの配列型とJSON型
配列型やJSON型を使うと
↓
1:Nを1つのカラムで表現出来る
困ったときの配列型とJSON型
id title body
1 初めてのポスグレ …
2
pg9.5 beta
リリース
…
3
篠崎愛
「おしのブログ」
…
blog_id tag
1 postgres
1 beginner
3 魂
blog...
困ったときの配列型とJSON型
id title body
1 初めてのポスグレ …
2
pg9.5 beta
リリース
…
3
篠崎愛
「おしのブログ」
…
blog_id tag
1 postgres
1 beginner
3 魂
blog...
困ったときの配列型とJSON型
id title body tag
1 初めてのポスグレ … [ postgres , beginner ]
2
pg9.5 beta
リリース
… null
3
篠崎愛
「おしのブログ」
… [ 魂 ]
blo...
困ったときの配列型とJSON型
テーブルを減らす事が出来る
困ったときの配列型とJSON型
テーブルを減らす事が出来る
↓
しかもINDEXも効く
困ったときの配列型とJSON型
JSON型の場合
困ったときの配列型とJSON型
JSON型の場合
↓
KeyValueを表現できる
困ったときの配列型とJSON型
id title body properties
1 初めてのポスグレ … {tag:[ postgres , beginner ]}
2
pg9.5 beta
リリース
… null
3
篠崎愛
「おしのブログ...
困ったときの配列型とJSON型
id title body properties
1 初めてのポスグレ … {tag:[ postgres , beginner ]}
2
pg9.5 beta
リリース
… null
3
篠崎愛
「おしのブログ...
困ったときの配列型とJSON型
id title body properties
1 初めてのポスグレ … {tag:[ postgres , beginner ]}
2
pg9.5 beta
リリース
… null
3
篠崎愛
「おしのブログ...
とりあえず削除フラグ
注意点
↓
トリガーは仕様変更に弱い
例えばALTER文でカラムを増やすと
トリガーが死ぬ
とりあえず削除フラグ
注意点
↓
トリガーは仕様変更に弱い
例えばALTER文でカラムを増やすと
トリガーが死ぬ
JSON型ならDB構造を変えない
→仕様変更時にトリガーが死なない
困ったときの配列型とJSON型
JSON型はデータに柔軟性を与える
困ったときの配列型とJSON型
JSON型はデータに柔軟性を与える
↓
それは整合性を犠牲にする
困ったときの配列型とJSON型
配列型もJSON型も
データを守る機能が弱い
困ったときの配列型とJSON型
外部キー制約→使えない
CHECK制約→使えない
困ったときの配列型とJSON型
外部キー制約→使えない
CHECK制約→使えない
該当のカラムが
紐づくテーブルを関連付けなれない
困ったときの配列型とJSON型
外部キー制約→使えない
CHECK制約→使えない
該当のカラムに
入るデータを制限出来ない
困ったときの配列型とJSON型
UPDATE文に弱い
困ったときの配列型とJSON型
UPDATE文に弱い
↓
特定の要素のみの更新が難しい
困ったときの配列型とJSON型
仕様が曖昧な時にJSON型
困ったときの配列型とJSON型
仕様が曖昧な時にJSON型
↓
仕様変更には強いので有効だが
運用時にデータが守れない
困ったときの配列型とJSON型
処方箋
困ったときの配列型とJSON型
ちゃんと正規化する
困ったときの配列型とJSON型
ちゃんと正規化する
↓
面倒でも正規化すれば
運用フェーズで必ず救われる
困ったときの配列型とJSON型
ちゃんと正規化する
↓
面倒でも正規化すれば
運用フェーズで必ず救われる
逆説的にリソースが許されるなら
困ってから正規化の選択肢もアリ
困ったときの配列型とJSON型
使っていい場合
困ったときの配列型とJSON型
• UPDATEが無い(INSERTのみ)
• データを守る必要が無い(制約を使わない)
• データを関連付けない(JOINしない)
• UPDETE時は対象カラムをまるっと更新
• 集約関数等の対象にならない
困ったときの配列型とJSON型
•ブログのTags
•可変なプロパティ
•外部のWebAPIの結果
具体例
困ったときの配列型とJSON型
•ブログのTags
•可変なプロパティ
•外部のWebAPIの結果
具体例
例えばServerのOS情報などは
ディストリビューションの違いを
気にしなくても良くなる
困ったときの配列型とJSON型
•ブログのTags
•可変なプロパティ
•外部のWebAPIの結果
具体例
いつ仕様変更が来るかわからない
→その変更に柔軟に対応できる
困ったときの配列型とJSON型
ご利用は計画的に
困ったときの配列型とJSON型
ご利用は計画的に
↓
基本的に正規化しましょう
あじぇんだ
1 自己紹介
2 とりあえず削除フラグ
3 困ったときの配列型とJSON型
4 マテビューの功罪
5 まとめ
マテビューの功罪
マテビューはPostgreSQL 9.3から
マテビューの功罪
•複雑なテーブルをシンプルに
•遅いクエリを高速に
•INDEXチューニングも可能
メリット
マテビューの功罪
•表領域を使う
•リフレッシュが必要
•リフレッシュのコストが高い
デメリット
マテビューの功罪
•表領域を使う
•リフレッシュが必要
•リフレッシュのコストが高い
デメリット
マテビューの功罪
•表領域を使う
•リフレッシュが必要
•リフレッシュのコストが高い
デメリット実体を持つのでデータファイルが作成される
作った分だけディスクスペースを圧迫する
マテビューの功罪
•表領域を使う
•リフレッシュが必要
•リフレッシュのコストが高い
デメリット実体を持つのでデータファイルが作成される
作った分だけディスクスペースを圧迫する
参照元のテーブルの増加と合わせてマテビューが増えれば
指数的にディ...
マテビューの功罪
•表領域を使う
•リフレッシュが必要
•リフレッシュのコストが高い
デメリット
マテビューの功罪
集計済み表課金log
計算結果をマテビューにする
マテビューの功罪
集計済み表課金log
課金1
計算結果をマテビューにする
課金2
マテビューの功罪
集計済み表課金log
課金1
計算結果をマテビューにする
課金2
リフレッシュ
マテビューの功罪
集計済み表課金log
課金1 集計結果
計算結果をマテビューにする
課金2
リフレッシュ
マテビューの功罪
集計済み表課金log
課金1 集計結果
計算結果をマテビューにする
課金2
集計結果を参照するので高速でシンプル!!
マテビューの功罪
集計済み表課金log
課金1 集計結果
計算結果をマテビューにする
課金2
課金3
マテビューの功罪
集計済み表課金log
課金1 集計結果
計算結果をマテビューにする
課金2
課金3
☓
更新失敗
マテビューの功罪
集計済み表課金log
課金1 集計結果
計算結果をマテビューにする
課金2
課金3
☓
更新失敗
前回の更新結果のままなので不整合
マテビューの功罪
更新が失敗した際の処理が必要
マテビューの功罪
更新が失敗した際の処理が必要
↓
自動更新の場合に
アプリケーションで制御出来ない
マテビューの功罪
更新が失敗した際の処理が必要
↓
自動更新の場合に
アプリケーションで制御出来ない
DBはテストの自動化も大変
未然にバグを検知しにくい
マテビューの功罪
•表領域を使う
•リフレッシュが必要
•リフレッシュのコストが高い
デメリット
マテビューの功罪
•表領域を使う
•リフレッシュが必要
•リフレッシュのコストが高い
デメリット
PostgreSQLには差分更新は無い
→データがクエリの実行速度が遅ければ更新も遅い
マテビューの功罪
•表領域を使う
•リフレッシュが必要
•リフレッシュのコストが高い
デメリット
PostgreSQLには差分更新は無い
→データがクエリの実行速度が遅ければ更新も遅い
データが大きくなるにつれ、負荷も上がる
→特に集約関数を使...
マテビューの功罪
•表領域を使う
•リフレッシュが必要
•リフレッシュのコストが高い
デメリット
PostgreSQLには差分更新は無い
→データがクエリの実行速度が遅ければ更新も遅い
データが大きくなるにつれ、負荷も上がる
→特に集約関数を使...
マテビューの功罪
処方箋
マテビューの功罪
DB状態を監視する
マテビューの功罪
DB状態を監視する
↓
死活監視だけでは無く
レコードの増加量やCPU使用率など
マテビューの功罪
DB状態を監視する
↓
死活監視だけでは無く
レコードの増加量やCPU使用率など
Zabbixを使っているならpg_monzなどを使う
マテビューの功罪
にも角にもマテビューはしない
マテビューの功罪
にも角にもマテビューはしない
↓
マテビューを集計してマテビュー
のような闇を作らない
マテビューの功罪
マテビューは便利だが銀の弾丸ではない
↓
必要になった時、それは多くの場合
設計に問題を抱えている
マテビューの功罪
マテビューは便利だが銀の弾丸ではない
↓
必要になった時、それは多くの場合
設計に問題を抱えている
マテビューの功罪
マテビューは便利だが銀の弾丸ではない
↓
必要になった時、それは多くの場合
設計に問題を抱えている
根本的な解決策が必要なので
マテビューが必要になった時は設計を見直す
マテビューの功罪
使わないに越した事は無い
マテビューの功罪
使わないに越した事は無い
↓
積極的に使うものではない
マテビューの功罪
使わないに越した事は無い
↓
積極的に使うものではない
新機能は使いたくなるけども
あじぇんだ
1 自己紹介
2 とりあえず削除フラグ
3 困ったときの配列型とJSON型
4 マテビューの功罪
5 まとめ
まとめ
PostgreSQLは高機能
まとめ
PostgreSQLは高機能
↓
設計の不備を
機能でカバー出来てしまう
まとめ
機能に依存し過ぎない
まとめ
機能に依存し過ぎない
↓
シンプルな設計は全てに勝る
まとめ
愚者は経験に学び、賢者は歴史に学ぶ
まとめ
周囲の経験談から学ぶ
まとめ
周囲の経験談から学ぶ
↓
積極的にコミュニティを利用する
参考資料
・公式ドキュメント(日本語)
https://www.postgresql.jp/document/9.4/html/postgres-fdw.html
・postgresql-jp Slack(チャットルーム)
https://po...
まとめ
データの寿命はコードよりも長い
まとめ
一度作ったDBは消せない
まとめ
一度作ったDBは消せない
↓
設計が大事
まとめ
より良い設計を
一緒に考えて行きましょう
ご静聴ありがとうございました。
Upcoming SlideShare
Loading in …5
×

PostgreSQLアンチパターン

33,342 views

Published on

・OSC徳島
・PostgreSQLカンファレンス
・JJUG CCC
の登壇資料です

Published in: Data & Analytics

PostgreSQLアンチパターン

  1. 1. PostgreSQLアンチパターン
  2. 2. What is it? RDBの限界を感じた事ありませんか?
  3. 3. What is it? PostgreSQLは銀の弾丸ではありません
  4. 4. What is it? アンチパターン
  5. 5. What is it? アンチパターン ↓ 良かれと思ってした事が後々に苦しみを生む
  6. 6. What is it? アンチパターンを知る
  7. 7. What is it? アンチパターンを知る ↓ 同じ過ちを繰り返さない
  8. 8. What is it? 愚者は経験に学び、賢者は歴史に学ぶ       オットー・フォン・ビスマルク
  9. 9. What is it?
  10. 10. What is it? SQLアンチパターンは厳選された失敗集
  11. 11. What is it? SQLアンチパターンは厳選された失敗集 ↓ DBのノウハウが詰まった名著
  12. 12. What is it? しかしMySQLがベース
  13. 13. What is it? 今日はPostgreSQLの失敗例をご紹介します
  14. 14. What is it? SQLアンチパターン本の内容 とは全く関係ありません
  15. 15. What is it? 俺の屍を越えて行け
  16. 16. あじぇんだ 1 自己紹介 2 とりあえず削除フラグ 3 困ったときの配列型とJSON型 4 マテビューの功罪 5 まとめ
  17. 17. あじぇんだ 1 自己紹介 2 とりあえず削除フラグ 3 困ったときの配列型とJSON型 4 マテビューの功罪 5 まとめ
  18. 18. 自己紹介 名前:曽根 壮大(そね たけとも) 年齢:31歳(三人の子供がいます) 職業:Webエンジニア 所属:日本PostgreSQLユーザ会    中国支部 支部長   技術的にはLL系言語とかRDBが好きです
  19. 19. 中国地方DB勉強会 https://dbstudychugoku.github.io/
  20. 20. あじぇんだ 1 自己紹介 2 とりあえず削除フラグ 3 困ったときの配列型とJSON型 4 マテビューの功罪 5 まとめ
  21. 21. とりあえず削除フラグ http://www.slideshare.net/t_wada/ronsakucasual
  22. 22. とりあえず削除フラグ こんなカラム名を 作ったことありませんか?
  23. 23. とりあえず削除フラグ hoge_delete_flag
  24. 24. とりあえず削除フラグ 会員削除フラグ… 顧客削除フラグ… hogeデータ削除フラグ…
  25. 25. とりあえず削除フラグ 論理削除と言う名の闇
  26. 26. とりあえず削除フラグ
  27. 27. とりあえず削除フラグ 論理削除はなぜダメなのか?
  28. 28. とりあえず削除フラグ 論理削除の理由
  29. 29. とりあえず削除フラグ • エンドユーザから見えなくしたいがデータは消したくない • 削除したデータを検索したい • データを消さずにログに残したい • 誤った操作をなかったことにしたい、直ぐに元に戻したい
  30. 30. とりあえず削除フラグ そして生まれるDELETE_FLAG
  31. 31. とりあえず削除フラグ 論理削除のデメリット
  32. 32. とりあえず削除フラグ • 積み重なるWHERE delete_flag = 0 • Unique制約が使えなくなる • 複雑な表示条件(Query)の原因
  33. 33. とりあえず削除フラグ • 積み重なるWHERE delete_flag = 0 • Unique制約が使えなくなる • 複雑な表示条件(Query)の原因
  34. 34. 積み重なるWHERE句 -- ブログを取ってきたい場合 SELECT * FROM blog WHERE blog.delete_flag = 0
  35. 35. 積み重なるWHERE句 -- ブログを取ってきたい場合 SELECT * FROM blog WHERE blog.delete_flag = 0 ブログの削除フラグを見る
  36. 36. 積み重なるWHERE句 -- ブログを取ってきたい場合 SELECT * FROM blog WHERE blog.delete_flag = 0 ブログの削除フラグを見る 更新者アカウントが削除されてたら?
  37. 37. 積み重なるWHERE句 -- 有効なアカウントのブログを取ってきたい場合 SELECT * FROM blog INNER JOIN users ON users.id = blog.user_id AND users.delete_flag = 0 WHERE blog.delete_flag = 0
  38. 38. 積み重なるWHERE句 -- 有効なアカウントのブログを取ってきたい場合 SELECT * FROM blog INNER JOIN users ON users.id = blog.user_id AND users.delete_flag = 0 WHERE blog.delete_flag = 0 ユーザの削除フラグを見る
  39. 39. 積み重なるWHERE句 -- 有効なアカウントのブログを取ってきたい場合 SELECT * FROM blog INNER JOIN users ON users.id = blog.user_id AND users.delete_flag = 0 WHERE blog.delete_flag = 0 ユーザの削除フラグを見る 所属が削除されてたら?
  40. 40. 積み重なるWHERE句 -- 有効な所属の有効なアカウントのブログを取ってきたい場合 SELECT * FROM blog INNER JOIN users ON users.id = blog.user_id AND users.delete_flag = 0 INNER JOIN customers ON customers.id = users.customer_id AND customers.delete_flag = 0 WHERE blog.delete_flag = 0
  41. 41. 積み重なるWHERE句 -- 有効な所属の有効なアカウントのブログを取ってきたい場合 SELECT * FROM blog INNER JOIN users ON users.id = blog.user_id AND users.delete_flag = 0 INNER JOIN customers ON customers.id = users.customer_id AND customers.delete_flag = 0 WHERE blog.delete_flag = 0 JOINがどんどん積み重なる
  42. 42. 積み重なるWHERE句 -- 有効な所属の有効なアカウントのブログを取ってきたい場合 SELECT * FROM blog INNER JOIN users ON users.id = blog.user_id AND users.delete_flag = 0 INNER JOIN customers ON customers.id = users.customer_id AND customers.delete_flag = 0 WHERE blog.delete_flag = 0 JOINがどんどん積み重なる Queryがボトルネックに
  43. 43. とりあえず削除フラグ Queryの複雑度に対する対策
  44. 44. とりあえず削除フラグ Queryの複雑度に対する対策 ↓ 有効なデータのViewを作る
  45. 45. とりあえず削除フラグ Queryの複雑度に対する対策 ↓ 有効なデータのViewを作る Queryの高速化にはならない
  46. 46. とりあえず削除フラグ 全てのINDEXのセカンダリに DELETE_FLAGを入れる必要がある
  47. 47. とりあえず削除フラグ 全てのINDEXのセカンダリに DELETE_FLAGを入れる必要がある INDEXの肥大化よりも そもそもINDEXを効かせる 複数のQueryを書くのが大変
  48. 48. とりあえず削除フラグ PostgreSQLには マテリアライズド・ビューがある
  49. 49. とりあえず削除フラグ マテビューで有効データViewを作る
  50. 50. とりあえず削除フラグ マテビューで有効データViewを作る ↓ 高速でQueryもシンプル
  51. 51. とりあえず削除フラグ マテビューで有効データViewを作る ↓ 高速でQueryもシンプル SELECT * FROM active_blog
  52. 52. とりあえず削除フラグ それ、シンプルになるの参照だけ
  53. 53. とりあえず削除フラグ それ、シンプルになるの参照だけ ↓ 更新系で生まれる悪夢
  54. 54. とりあえず削除フラグ 更新したらマテビューを更新
  55. 55. とりあえず削除フラグ 更新したらマテビューを更新 ↓ customersでもusersでもblogでも 更新があればマテビューも更新
  56. 56. とりあえず削除フラグ 更新したらマテビューを更新 ↓ customersでもusersでもblogでも 更新があればマテビューも更新 頻発する REFRESH MATERIALIZED VIEW
  57. 57. とりあえず削除フラグ 実際にはdeleteされないので データは増え続ける
  58. 58. とりあえず削除フラグ 実際にはdeleteされないので データは増え続ける ↓ マテビューの更新コストが肥大
  59. 59. とりあえず削除フラグ 実際にはdeleteされないので データは増え続ける ↓ マテビューの更新コストが肥大 そして第三章の問題へ…
  60. 60. とりあえず削除フラグ • 積み重なるWHERE delete_flag = 0 • Unique制約が使えなくなる • 複雑な表示条件(Query)の原因
  61. 61. とりあえず削除フラグ • 積み重なるWHERE delete_flag = 0 • Unique制約が使えなくなる • 複雑な表示条件(Query)の原因 つまり外部Key制約も死ぬ
  62. 62. とりあえず削除フラグ id name age deleted 1 soudai 30 1 2 soudai 30 0 3 sone 20 0 4 taketomo 31 0
  63. 63. とりあえず削除フラグ id name age deleted 1 soudai 30 1 2 soudai 30 0 3 sone 20 0 4 taketomo 31 0
  64. 64. とりあえず削除フラグ id name age deleted 1 soudai 30 1 2 soudai 30 0 3 sone 20 0 4 taketomo 31 0 同じユーザが2名いるので Unique制約できない
  65. 65. とりあえず削除フラグ id name age deleted 1 soudai 30 1 2 soudai 30 0 3 sone 20 0 4 taketomo 31 0 同じユーザが2名いるので Unique制約できない もちろん外部キー制約もできない
  66. 66. とりあえず削除フラグ id name age deleted 1 soudai 30 1 2 soudai 30 0 3 sone 20 0 4 taketomo 31 0 サロゲートキーで外部キー制約した場合は 関連したデータは別人扱いになる
  67. 67. とりあえず削除フラグ id name age deleted 1 soudai 30 1 2 soudai 30 0 3 sone 20 0 4 taketomo 31 0 サロゲートキーで外部キー制約した場合は 関連したデータは別人扱いになる ナチュラルキーの場合は死ぬ
  68. 68. とりあえず削除フラグ PostgreSQLには Unique制約にWHERE句がある
  69. 69. Unique制約が使えなくなる -- deletedが0の時にUnique制約をかける CREATE UNIQUE INDEX user_idx ON users (name) WHERE deleted = 0;
  70. 70. とりあえず削除フラグ id name age deleted 1 soudai 30 1 2 soudai 30 0 3 sone 20 0 4 taketomo 31 0
  71. 71. とりあえず削除フラグ id name age deleted 1 soudai 30 1 2 soudai 30 0 3 sone 20 0 4 taketomo 31 0
  72. 72. とりあえず削除フラグ id name age deleted 1 soudai 30 1 2 soudai 30 0 3 sone 20 0 4 taketomo 31 0
  73. 73. とりあえず削除フラグ id name age deleted 1 soudai 30 1 2 soudai 30 0 3 sone 20 0 4 taketomo 31 0 deletedが1なのでUnique制約対象外
  74. 74. とりあえず削除フラグ id name age deleted 1 soudai 30 1 2 soudai 30 0 3 sone 20 0 4 taketomo 31 0 nameでUnique制約をかけれる
  75. 75. とりあえず削除フラグ id name age deleted 1 soudai 30 1 2 soudai 30 0 3 sone 20 0 4 taketomo 31 0 nameでUnique制約をかけれる しかし外部キー制約は死ぬ
  76. 76. とりあえず削除フラグ Unique制約にWHERE句 ↓ 結局は外部キー制約は死ぬ
  77. 77. とりあえず削除フラグ 外部キー制約が死ぬ
  78. 78. とりあえず削除フラグ 外部キー制約が死ぬ ↓ テーブルの関連性の担保が死ぬ
  79. 79. とりあえず削除フラグ データの不整合を防げない
  80. 80. とりあえず削除フラグ データの不整合を防げない ↓ バグの温床になる
  81. 81. とりあえず削除フラグ • 積み重なるWHERE delete_flag = 0 • Unique制約が使えなくなる • 複雑な表示条件(Query)の原因
  82. 82. とりあえず削除フラグ 正しいデータを 表示させる条件が多い
  83. 83. 積み重なるWHERE句 -- 有効な所属の有効なアカウントのブログを取ってきたい場合 SELECT * FROM blog INNER JOIN users ON users.id = blog.user_id AND users.delete_flag = 0 INNER JOIN customers ON customers.id = users.customer_id AND customers.delete_flag = 0 WHERE blog.delete_flag = 0 表示させるために 3つのテーブルが関係している
  84. 84. とりあえず削除フラグ 1つのデータを取るために 関係するTABLEが多すぎる
  85. 85. とりあえず削除フラグ 「あのデータ取るには○○と☓☓と △△をJOINしてWHEREしてSELECT 句にASで別名を付けて…」 みたいな事が頻発する
  86. 86. とりあえず削除フラグ 仕様変更の時の影響範囲が広い
  87. 87. とりあえず削除フラグ 仕様変更の時の影響範囲が広い ↓ つまりバグの温床になる
  88. 88. とりあえず削除フラグ 論理削除は使わないほうが良い
  89. 89. とりあえず削除フラグ 論理削除は使わないほうが良い ↓ TABLEに状態を持たせない
  90. 90. とりあえず削除フラグ 論理削除は使わないほうが良い ↓ TABLEに状態を持たせない リレーショナルモデルで表現する
  91. 91. とりあえず削除フラグ 処方箋
  92. 92. とりあえず削除フラグ 有効なデータのみを残す
  93. 93. とりあえず削除フラグ 有効なデータのみを残す ↓ 例えば削除済みTABLEを作る
  94. 94. とりあえず削除フラグ deleted_usersusers
  95. 95. とりあえず削除フラグ deleted_usersusers soudai sone taketomo
  96. 96. とりあえず削除フラグ deleted_usersusers soudai sone taketomo 削除(DELETE文)
  97. 97. とりあえず削除フラグ deleted_usersusers soudai sone taketomo soudai トリガーで移す
  98. 98. とりあえず削除フラグ deleted_usersusers sone taketomo soudai テーブルには実際のデータのみが残る
  99. 99. とりあえず削除フラグ 注意点
  100. 100. とりあえず削除フラグ 注意点 ↓ トリガーは仕様変更に弱い
  101. 101. とりあえず削除フラグ 注意点 ↓ トリガーは仕様変更に弱い 例えばALTER文でカラムを増やすと トリガーが死ぬ
  102. 102. とりあえず削除フラグ ケースバイケースで手法は選ぶこと
  103. 103. とりあえず削除フラグ ケースバイケースで手法は選ぶこと ↓ 論理削除は使わない
  104. 104. とりあえず削除フラグ 関連したテーブルは?
  105. 105. とりあえず削除フラグ 関連したテーブルは? ↓ 必要なら削除済みTABLEを作る 不要ならDELETEする
  106. 106. とりあえず削除フラグ 関連したテーブルは? ↓ 必要なら削除済みTABLEを作る 不要ならDELETEする 外部キー制約が使えればCASCADEも出来る
  107. 107. とりあえず削除フラグ 関連したテーブルは? ↓ 必要なら削除済みTABLEを作る 不要ならDELETEする 外部キー制約が使えればCASCADEも出来る 事実のみを保存する
  108. 108. とりあえず削除フラグ •ユーザの状態(statusカラム) •課金状態(与信、請求済み) •カート情報(カゴの中、購入済み) 類似例
  109. 109. とりあえず削除フラグ DBに状態を持たせるのは危ない
  110. 110. とりあえず削除フラグ DBに状態を持たせるのは危ない ↓ DBには事実のみを保存する
  111. 111. あじぇんだ 1 自己紹介 2 とりあえず削除フラグ 3 困ったときの配列型とJSON型 4 マテビューの功罪 5 まとめ
  112. 112. 困ったときの配列型とJSON型 PostgreSQLは型が豊富
  113. 113. 困ったときの配列型とJSON型 配列型やJSON型を使うと
  114. 114. 困ったときの配列型とJSON型 配列型やJSON型を使うと ↓ 1:Nを1つのカラムで表現出来る
  115. 115. 困ったときの配列型とJSON型 id title body 1 初めてのポスグレ … 2 pg9.5 beta リリース … 3 篠崎愛 「おしのブログ」 … blog_id tag 1 postgres 1 beginner 3 魂 blog tag
  116. 116. 困ったときの配列型とJSON型 id title body 1 初めてのポスグレ … 2 pg9.5 beta リリース … 3 篠崎愛 「おしのブログ」 … blog_id tag 1 postgres 1 beginner 3 魂 blog tag 1:N
  117. 117. 困ったときの配列型とJSON型 id title body tag 1 初めてのポスグレ … [ postgres , beginner ] 2 pg9.5 beta リリース … null 3 篠崎愛 「おしのブログ」 … [ 魂 ] blog(配列型の使用例)
  118. 118. 困ったときの配列型とJSON型 テーブルを減らす事が出来る
  119. 119. 困ったときの配列型とJSON型 テーブルを減らす事が出来る ↓ しかもINDEXも効く
  120. 120. 困ったときの配列型とJSON型 JSON型の場合
  121. 121. 困ったときの配列型とJSON型 JSON型の場合 ↓ KeyValueを表現できる
  122. 122. 困ったときの配列型とJSON型 id title body properties 1 初めてのポスグレ … {tag:[ postgres , beginner ]} 2 pg9.5 beta リリース … null 3 篠崎愛 「おしのブログ」 … {tag:[ 魂 ]} blog(JSON型の使用例)
  123. 123. 困ったときの配列型とJSON型 id title body properties 1 初めてのポスグレ … {tag:[ postgres , beginner ]} 2 pg9.5 beta リリース … null 3 篠崎愛 「おしのブログ」 … {tag:[ 魂 ], event:[ 握手会 ]} blog(JSON型の使用例)
  124. 124. 困ったときの配列型とJSON型 id title body properties 1 初めてのポスグレ … {tag:[ postgres , beginner ]} 2 pg9.5 beta リリース … null 3 篠崎愛 「おしのブログ」 … {tag:[ 魂 ], event:[ 握手会 ]} blog(JSON型の使用例) JSON型はドキュメント指向なスキーマレスを表現できる
 →つまりDB構造を変更すること無く項目を追加できる
  125. 125. とりあえず削除フラグ 注意点 ↓ トリガーは仕様変更に弱い 例えばALTER文でカラムを増やすと トリガーが死ぬ
  126. 126. とりあえず削除フラグ 注意点 ↓ トリガーは仕様変更に弱い 例えばALTER文でカラムを増やすと トリガーが死ぬ JSON型ならDB構造を変えない →仕様変更時にトリガーが死なない
  127. 127. 困ったときの配列型とJSON型 JSON型はデータに柔軟性を与える
  128. 128. 困ったときの配列型とJSON型 JSON型はデータに柔軟性を与える ↓ それは整合性を犠牲にする
  129. 129. 困ったときの配列型とJSON型 配列型もJSON型も データを守る機能が弱い
  130. 130. 困ったときの配列型とJSON型 外部キー制約→使えない CHECK制約→使えない
  131. 131. 困ったときの配列型とJSON型 外部キー制約→使えない CHECK制約→使えない 該当のカラムが 紐づくテーブルを関連付けなれない
  132. 132. 困ったときの配列型とJSON型 外部キー制約→使えない CHECK制約→使えない 該当のカラムに 入るデータを制限出来ない
  133. 133. 困ったときの配列型とJSON型 UPDATE文に弱い
  134. 134. 困ったときの配列型とJSON型 UPDATE文に弱い ↓ 特定の要素のみの更新が難しい
  135. 135. 困ったときの配列型とJSON型 仕様が曖昧な時にJSON型
  136. 136. 困ったときの配列型とJSON型 仕様が曖昧な時にJSON型 ↓ 仕様変更には強いので有効だが 運用時にデータが守れない
  137. 137. 困ったときの配列型とJSON型 処方箋
  138. 138. 困ったときの配列型とJSON型 ちゃんと正規化する
  139. 139. 困ったときの配列型とJSON型 ちゃんと正規化する ↓ 面倒でも正規化すれば 運用フェーズで必ず救われる
  140. 140. 困ったときの配列型とJSON型 ちゃんと正規化する ↓ 面倒でも正規化すれば 運用フェーズで必ず救われる 逆説的にリソースが許されるなら 困ってから正規化の選択肢もアリ
  141. 141. 困ったときの配列型とJSON型 使っていい場合
  142. 142. 困ったときの配列型とJSON型 • UPDATEが無い(INSERTのみ) • データを守る必要が無い(制約を使わない) • データを関連付けない(JOINしない) • UPDETE時は対象カラムをまるっと更新 • 集約関数等の対象にならない
  143. 143. 困ったときの配列型とJSON型 •ブログのTags •可変なプロパティ •外部のWebAPIの結果 具体例
  144. 144. 困ったときの配列型とJSON型 •ブログのTags •可変なプロパティ •外部のWebAPIの結果 具体例 例えばServerのOS情報などは ディストリビューションの違いを 気にしなくても良くなる
  145. 145. 困ったときの配列型とJSON型 •ブログのTags •可変なプロパティ •外部のWebAPIの結果 具体例 いつ仕様変更が来るかわからない →その変更に柔軟に対応できる
  146. 146. 困ったときの配列型とJSON型 ご利用は計画的に
  147. 147. 困ったときの配列型とJSON型 ご利用は計画的に ↓ 基本的に正規化しましょう
  148. 148. あじぇんだ 1 自己紹介 2 とりあえず削除フラグ 3 困ったときの配列型とJSON型 4 マテビューの功罪 5 まとめ
  149. 149. マテビューの功罪 マテビューはPostgreSQL 9.3から
  150. 150. マテビューの功罪 •複雑なテーブルをシンプルに •遅いクエリを高速に •INDEXチューニングも可能 メリット
  151. 151. マテビューの功罪 •表領域を使う •リフレッシュが必要 •リフレッシュのコストが高い デメリット
  152. 152. マテビューの功罪 •表領域を使う •リフレッシュが必要 •リフレッシュのコストが高い デメリット
  153. 153. マテビューの功罪 •表領域を使う •リフレッシュが必要 •リフレッシュのコストが高い デメリット実体を持つのでデータファイルが作成される 作った分だけディスクスペースを圧迫する
  154. 154. マテビューの功罪 •表領域を使う •リフレッシュが必要 •リフレッシュのコストが高い デメリット実体を持つのでデータファイルが作成される 作った分だけディスクスペースを圧迫する 参照元のテーブルの増加と合わせてマテビューが増えれば 指数的にディスクスペースの使用量が増える
  155. 155. マテビューの功罪 •表領域を使う •リフレッシュが必要 •リフレッシュのコストが高い デメリット
  156. 156. マテビューの功罪 集計済み表課金log 計算結果をマテビューにする
  157. 157. マテビューの功罪 集計済み表課金log 課金1 計算結果をマテビューにする 課金2
  158. 158. マテビューの功罪 集計済み表課金log 課金1 計算結果をマテビューにする 課金2 リフレッシュ
  159. 159. マテビューの功罪 集計済み表課金log 課金1 集計結果 計算結果をマテビューにする 課金2 リフレッシュ
  160. 160. マテビューの功罪 集計済み表課金log 課金1 集計結果 計算結果をマテビューにする 課金2 集計結果を参照するので高速でシンプル!!
  161. 161. マテビューの功罪 集計済み表課金log 課金1 集計結果 計算結果をマテビューにする 課金2 課金3
  162. 162. マテビューの功罪 集計済み表課金log 課金1 集計結果 計算結果をマテビューにする 課金2 課金3 ☓ 更新失敗
  163. 163. マテビューの功罪 集計済み表課金log 課金1 集計結果 計算結果をマテビューにする 課金2 課金3 ☓ 更新失敗 前回の更新結果のままなので不整合
  164. 164. マテビューの功罪 更新が失敗した際の処理が必要
  165. 165. マテビューの功罪 更新が失敗した際の処理が必要 ↓ 自動更新の場合に アプリケーションで制御出来ない
  166. 166. マテビューの功罪 更新が失敗した際の処理が必要 ↓ 自動更新の場合に アプリケーションで制御出来ない DBはテストの自動化も大変 未然にバグを検知しにくい
  167. 167. マテビューの功罪 •表領域を使う •リフレッシュが必要 •リフレッシュのコストが高い デメリット
  168. 168. マテビューの功罪 •表領域を使う •リフレッシュが必要 •リフレッシュのコストが高い デメリット PostgreSQLには差分更新は無い →データがクエリの実行速度が遅ければ更新も遅い
  169. 169. マテビューの功罪 •表領域を使う •リフレッシュが必要 •リフレッシュのコストが高い デメリット PostgreSQLには差分更新は無い →データがクエリの実行速度が遅ければ更新も遅い データが大きくなるにつれ、負荷も上がる →特に集約関数を使ったようなクエリは メモリに乗らなくなった瞬間に急激に遅くなる
  170. 170. マテビューの功罪 •表領域を使う •リフレッシュが必要 •リフレッシュのコストが高い デメリット PostgreSQLには差分更新は無い →データがクエリの実行速度が遅ければ更新も遅い データが大きくなるにつれ、負荷も上がる →特に集約関数を使ったようなクエリは メモリに乗らなくなった瞬間に急激に遅くなる 更新が遅くなった事に気づきにくい
  171. 171. マテビューの功罪 処方箋
  172. 172. マテビューの功罪 DB状態を監視する
  173. 173. マテビューの功罪 DB状態を監視する ↓ 死活監視だけでは無く レコードの増加量やCPU使用率など
  174. 174. マテビューの功罪 DB状態を監視する ↓ 死活監視だけでは無く レコードの増加量やCPU使用率など Zabbixを使っているならpg_monzなどを使う
  175. 175. マテビューの功罪 にも角にもマテビューはしない
  176. 176. マテビューの功罪 にも角にもマテビューはしない ↓ マテビューを集計してマテビュー のような闇を作らない
  177. 177. マテビューの功罪 マテビューは便利だが銀の弾丸ではない ↓ 必要になった時、それは多くの場合 設計に問題を抱えている
  178. 178. マテビューの功罪 マテビューは便利だが銀の弾丸ではない ↓ 必要になった時、それは多くの場合 設計に問題を抱えている
  179. 179. マテビューの功罪 マテビューは便利だが銀の弾丸ではない ↓ 必要になった時、それは多くの場合 設計に問題を抱えている 根本的な解決策が必要なので マテビューが必要になった時は設計を見直す
  180. 180. マテビューの功罪 使わないに越した事は無い
  181. 181. マテビューの功罪 使わないに越した事は無い ↓ 積極的に使うものではない
  182. 182. マテビューの功罪 使わないに越した事は無い ↓ 積極的に使うものではない 新機能は使いたくなるけども
  183. 183. あじぇんだ 1 自己紹介 2 とりあえず削除フラグ 3 困ったときの配列型とJSON型 4 マテビューの功罪 5 まとめ
  184. 184. まとめ PostgreSQLは高機能
  185. 185. まとめ PostgreSQLは高機能 ↓ 設計の不備を 機能でカバー出来てしまう
  186. 186. まとめ 機能に依存し過ぎない
  187. 187. まとめ 機能に依存し過ぎない ↓ シンプルな設計は全てに勝る
  188. 188. まとめ 愚者は経験に学び、賢者は歴史に学ぶ
  189. 189. まとめ 周囲の経験談から学ぶ
  190. 190. まとめ 周囲の経験談から学ぶ ↓ 積極的にコミュニティを利用する
  191. 191. 参考資料 ・公式ドキュメント(日本語) https://www.postgresql.jp/document/9.4/html/postgres-fdw.html ・postgresql-jp Slack(チャットルーム) https://postgresql-hackers-jp.herokuapp.com/
  192. 192. まとめ データの寿命はコードよりも長い
  193. 193. まとめ 一度作ったDBは消せない
  194. 194. まとめ 一度作ったDBは消せない ↓ 設計が大事
  195. 195. まとめ より良い設計を 一緒に考えて行きましょう
  196. 196. ご静聴ありがとうございました。

×