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.

SQLアンチパターン メンター用資料

10,404 views

Published on

SQLアンチパターン 読書会用メンター資料

Published in: Technology
  • Be the first to comment

SQLアンチパターン メンター用資料

  1. 1. SQLアンチパターン メンター用資料 VOYAGE GROUP システム本部 ERDG 三浦 裕典@hironomiu
  2. 2. 0章 この資料について • この資料について • O’ReillyのSQLアンチパターン勉強会用のメンター用として作成 • 書籍と合わせて利用するための資料です • 個人の主観が大きく入っています • サンプルデータベースについて • SQLアンチパターン書籍中 xxi ~ xxiii 参照 • サンプルコード • http://www.oreilly.co.jp/books/9784873115894/ • bksqla-code.tgz • その他 • MySQLを前提に記載しています(Oracleも場合により)
  3. 3. 0章 はじめに • xviii 世の中のアンチパターンの多くにはユーモラスで刺激的なタイトルがつい ています。 • 「黄金のハンマー(Golden Hammer)」 • 「車輪の再発明(Reinventing the Wheel)」 • 「委員会による設計(Design by Committee)」 • その他は wikipedia:アンチパターン 参照 • xix 本書のテーマはSQLとリレーショナルデータベースであり、他の代替手段 ではありません。
  4. 4. 1章ジェイウォーク • [Gist](https://gist.github.com/hironomiu/18e67de38341a16e7f08) • ジェイウォーク(題名)の由来 • 交差テーブル(交差点)ー> 無視してカンマ区切りのデータの作成(信号無視)= ジェイウォーク • 1.2 アンチパターンを実践するDDLの流れ? • テーブルのカラムをINTからVARCHARに変更することによるデータの洗い替え方法を考える • サービス無停止(サービス稼働中)で実行可能か? • 1.2.1 regexpやfind_in_setの実行計画 • 等価性による比較が出来なくなるデメリットとは? • 一つはインデックスで実現されているキーからの導出が困難
  5. 5. 1章ジェイウォーク • 1.2.2 例のSQLが直積となっているイメージが湧くか?(Products × Accounts) • クロス積の記載改修済み(product_idで絞り込み後Accountsのレコード数分、正規表現で突きあわせ) • 1.2.3 実装しているSQLはどういう意図のSQL? • 1.2.4 • remove.phpを参照しアカウントの更新、削除がキーで導出出来るケースとどれだけ差がある? • 業務でこの変更(追加、更新、削除)処理をしようした場合どこらへんに気をつけることがある? • ロストアップデートの危険 • どうやって回避する? • プログラム的には`product_id = 123`はプレースフォルダを使うべきだがサンプルコードの意味が大きいので割愛 • 1.2.5 bananaの妥当性はどのようにする?一般的にはどのように担保する?(制約) • 1.2.6 個々の入力値に区切り文字が含まれる場合は?
  6. 6. 1章ジェイウォーク • 1.3 アンチパターンの再確認 • アンチパターンを用いても良い場合以外、基本交差テーブルを作成すること • 1.4 アンチパターンを用いても良い場合 • 業務でアンチパターンの利用例はある? • リスト内の各要素への個別アクセスが不要 = 導出することが無い(text型のデータなど) • 1.5 交差テーブルを作成する • 交差テーブルとは多対多の関連を表現するテーブル = 連関エンティティ • 1.5.7 交差テーブルの他のメリットについて考えてみましょう • 例えば、連絡先が追加された日付を記録し • 閑話 FKをつける際に気をつける事 • 親、子のカラム定義は厳密に同じ内容を指定すること(null ,not null,正負など)
  7. 7. 2章ナイーブツリー • [Gist](https://gist.github.com/hironomiu/e3343fe507441c5b8db1) • 2.1 階層構造とは • 組織図 • 商品カテゴリ • 掲示板(この章は掲示板を前提に記されている) • ネットワーク図ではありません(循環しない等) • 隣接リスト(+再起クエリ) • 再起クエリ WITH句、CONNECT BY PRIOR構文 • http://www.oracle.com/technetwork/jp/articles/otnj-sql-image7-1525406-ja.html • 親キー = 子キー のデータを挿入した場合どのような問題が生じるか(循環=無限ループ • 親子関係のSQLは直感的にわかりやすい
  8. 8. 2章ナイーブツリー • 2.2 なぜ隣接リストはアンチパターンなのか? • 2.2.2 それは、すべての子孫を取得するクエリ • そもそも1回のSQLで任意の階層データ全てを取得する要件はどのようなものか? • コメント数のようなcountがしずらい(か?)(数件 ~ 数万 ~ 数千億) • 2.4 アンチパターンを用いてもよい場合 • 隣接リスト設計は、アプリケーションで求められているタスクに適している状態とは? • 2.5 解決策 • 隣接モデルでは要件が満たせない場合に選択 • パフォーマンス • ノード変更の柔軟性
  9. 9. 2章ナイーブツリー • 2.5.1 経路列挙 • パンくずリスト • ジェイウォークと同様の問題点を抱える • 存在しない親、不正な文字列が挿入された場合(外部キーによる 整合性が保証出来ない) • 挿入出来る文字数の限界 • pathに自分のIDを入れる理由は?
  10. 10. 2章ナイーブツリー • 2.5.2 入れ子集合 • P25 しかし入れ子集合では、直近の親の取得などの、隣接リストでは簡単に実行できるクエリの一部が複雑になっ てしまいます。 • SQLが直感的にわかりずらい • 参照整合性により親子関係のキーを制限できない • 参考 SQLで木と階層構造のデータを扱う(1)―― 入れ子集合モデル • http://www.geocities.jp/mickindex/database/db_tree_ns.html • 業務で実装実績あり • SQLは複雑になるが大規模な親子データを「塊」としてを扱う場合にパフォーマンスの観点で有利 • 参考 発展系 入れ子区間集合 • http://gihyo.jp/dev/serial/01/sql_academy2/000601
  11. 11. 2章ナイーブツリー • 2.5.3 閉包テーブル • ジェイウォークの解決版? • TreePaths = 交差テーブル(連関エンティティ) • 10階層目にレコードを挿入する場合55行TreePathsには挿入? • 自分のIDを入れる理由? • 参照整合性により親子関係のキーを制限できる
  12. 12. 2章ナイーブツリー • 2.5.4 比較表から適所を考える(隣接リスト、経路列挙、入れ子集合、閉包テーブル) • 自分から親をたどる • 自分から子をたどる • どれが自分の親か?(複数の先祖(親、祖父、祖祖父)がいる場合) • メンテナンス性 • 挿入(末端に追加、途中に追加) • 削除(自身のみ削除、自身から子孫についても削除) • 更新(自身の更新、属する親の変更、自身から子孫についても従属) • 親子キーの整合性の保証(参照整合性)
  13. 13. 3章IDリクワイアド • 3.1 目的:主キーの規約を確立する • 擬似キー • 代理キー • 35P 主キーは必要か? • リレーショナルモデルでの集合ではなく物理実装されたRDBMSにてレコードを一意にする方法は? • RowID、PK、etc • 主キー(ナチュラルキー)を更新(変更)したいケースが存在するか • カラムデータの変更に対する弾力性 • マスタテーブルなどでサロゲートキーをPKにするケースで多い • 余談 パーティションテーブル、主キー = パーティションキーの場合、内部ではどのような動きが発生しているか
  14. 14. 3章IDリクワイアド • 3.2 なぜこれがアンチパターンなのか考える • 特定のプラットフォームでの仕様による考慮(Innodb クラスタインデックス) • http://dev.mysql.com/doc/refman/5.1-olh/ja/innodb-index-types.html • RDBMSでの行の一意方法(rowid;Oracle, PK:MySQL Innodb) • 実演 userテーブルに100万レコード で UUIDのようなuser_id 主にインデック スのスプリットについて考える • サロゲートキーでのinsert • user_idをPKにしてinsert
  15. 15. 3章IDリクワイアド • 論理設計にてマスタ、トランザクション(+サマリー)の観点でIDを考える • 3.2.1 冗長なキーが作成されてしまう • マスタテーブルを例にメリット、デメリット(変更に対する弾力性、親子関係(外部整 合性制約)によるデータの妥当性) • 3.2.2 重複行を許可してしまう • Unique制約で対応する場合、IDは無駄になるか? • 3.2.3 キーの意味 テーブル名+カラム名、カラム名だけで意味をもたす?(3.5.1も同様 ) • P39 シーケンスについて(auto_increment、Oracle sequence、などなど)
  16. 16. 3章IDリクワイアド • 3.3 アンチパターン • 多対多の関連が重複してしまった • いつ気付く?どうやって見つける? • 3.4 アンチパターンを用いても良い場合 • 疑似キーは自然キーがあまりにも長過ぎる場合には良い選択肢になります。 • 「しかし、ファイルパスのように長い文字列の列にインデックスをつけるのは非効率的で す」 • なぜ?(格納効率?、後述のセカンダリインデックス?、etc) • セカンダリインデックスがレコードの探索をPKで格納する場合は特に重要
  17. 17. 3章IDリクワイアド • 3.5 解決策:状況に応じて適切に調整する • MySQL Innodbの場合はパフォーマンスを考慮して基本ID列を 採用して良いが、状況に応じる柔軟性は大事 • 3.5.3 自然キー、サロゲートキー、複合キーとは? • 「一意であるとこが保証できて、NULLを許容しない・・・」 • 擬似キーを追加する義務を感じる必要はない
  18. 18. 4章キーレスエントリ(外部キー嫌い ) • DRY(Don't Repeat Your Self:繰り返しを避けること)原則を強く意識して読み進めるのが良い章 • P43 文中の「論理的な関連(リレーションシップ)」は誰(アプリケーション?DB?)が保証してるのか? • 誰かが(かつ単一の責務として)データの整合性を保証しないと辛い思いを? • 結論としては外部キーは使った方が良い(「使うべき」と言う強いニュアンスかも) • イントロ • 外部キー制約をサポートしていないMyISAMでした • 論理的な関連(リレーションシップ)があったのにも関わらず • DRY原則的にはアプリケーションが論理的な関連の整合性を保証していた • トランザクションも切り捨てているので例示としては色々とアレな気も • 本当に必要だったのは、ユーザが無効なデータを入力した際にアプリケーションがすぐにエラーを返すことでした
  19. 19. 4章キーレスエントリ(外部キー嫌い ) • 4.1 データベースのアーキテクチャの単純化 • リレーション • 属性同士が結びついたエンティティ(集合)の関係を表す • リレーションシップ • エンティティ間の結びつきを表す • リレーションシップの可視化(DLLの追跡で)、整合性の責務の明確化(DRY原則によるDBによる責 務の明確化) • 外部キーを宣言する構文を調べなければならない • 論外 • テスト環境について(テーブル毎のexp,imp)
  20. 20. 4章キーレスエントリ(外部キー嫌い ) • 4.2.1 完璧なコードを前提にしている • 仮登録の場合(別テーブルで回避する?(設計レベル)) • データフロー(親から挿入、子から挿入) • 参照整合性が可能なケース • データフロー(親(マスタデータ)、子(トランザクションデータ))社員マスタ ー 行動履歴トランザクショ ン • マスタとトランザクションを非同期で削除したい場合(カスケードを除外するか) • 親データは消えるが、子データは将来も残る(商品マスタは都度変わるが購買履歴上の商品情報は残したい) (※商品マスタを履歴化することにも絡む) • データフロー(親(トランザクションデータ)、子(トランザクションデータ))受注トランザクション ー 受 注明細トランザクション • 同一ドメインレベルでの縛りと参照整合性
  21. 21. 4章キーレスエントリ(外部キー嫌い ) • 4.2.3 「私のミスではありません!」 • DRY原則 • アプリケーションの様々な箇所に〜アプリケーション内のすべての箇所で適切な変更を行ったことを確認する のは • DBの機能を機械的に利用し単一の責務として寄せる • 4.2.4 「キャッチ=22」なUPDATE • [キャッチ=22について wiki](http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%83%83%E3%83%81%3D22) • データ削除の順序性 • UPDATE文のような状況(ステータスマスタ、ステータスを参照する子テーブル)はどうする? • 普通はマスターに新しいステータスをINSERTして子テーブルの参照先を更新する(ハズ)
  22. 22. 4章キーレスエントリ(外部キー嫌い ) • 4.5 ポカヨケ • [ポカヨケ wiki](http://ja.wikipedia.org/wiki/%E3%83%9D%E3%82%AB%E3%83%A8%E3%82%B1) • 4.5.1 カスケード更新 • [MySQL 5.6 Reference Manual](http://dev.mysql.com/doc/refman/5.6/en/innodb-foreign-key-constraints.html) • 削除に関してはデータを削除しないというのも一つの選択 • 4.5.2 オーバーヘッドになるか否か • 過去は少ないリソースでRDBの運用(チューニング)を行った名残もあり論理整合性を保つレベルでデータの整合 性を保つことが多かったが今はオーバーヘッドを考慮する必要は無く整合性を保つメリットを享受するべき • データの不整合で不具合に陥った経験ありますか? • 冒頭のような経験 • 不具合がクリティカルな場合、4.2.2 ミスを調べなければならない -> 整合性制約で良いのでは?
  23. 23. 5章EAV(エンティティアトリビュート・バリュー ) • [Gist](https://gist.github.com/hironomiu/6e8cf7af96ba9776e136) • そもそも正規化をするとこうなる? • 初期からではなく仕様追加の際に現れやすい(もしくは予め将来を見越す場合) • (この章全般で出てくる)継承と言う言葉をそもそもテーブル定義で使います? • 5.1 可変属性をサポートする • 「リレーショナルデータベースのメタデータの柔軟性」とは? • オブジェクト指向のクラスの継承 • テーブル定義の継承 • クラスのオブジェクト化(各々独立) = データが格納されている状態(同じ集合として存在) • 違和感あります?
  24. 24. 5章EAV(エンティティアトリビュート・バリュー ) • 5.2 anti 汎用的な属性テーブルを使用する • 5.2.1 属性を取得するにはどうするか • EAVの参考SQLで属性指定「WHERE attr_name = ‘date_reported’」は筋が良い? • 5.2.2 データ整合性をどう保つか(EAVの問題点) • 必須属性を指定できない • 様々なattributeとvalueがあるため強制出来ない • SQLのデータ型を使えない • 日付も全て文字列で表現 • 参照整合性を強制出来ない • attribute(メタデータ)すら間違いに気付けない(整合性を保てない)
  25. 25. 5章EAV(エンティティアトリビュート・バリュー ) • 5.2.3 行を再構築しなければならない • DRY原則を踏まえて考える • 「attr_name = ‘XXX’」の責務はSQLを構築しているアプリケーション • 流動的に変わる場合、対応漏れなどのバグが混入する可能性 • 5.4 アンチパターンを用いても良い場合 • 「リレーショナルデータベースの多くの長所が失われてしまう」 • 「メタデータが流動的であると、シンプルなクエリの作成が難しくなる」 • RDBではなく代替のNoSQLを選択する余地がある • 代替のNoSQLの場合DRY原則としてのデータの一貫性の責務は誰が持つ? • RDBからNoSQLに変わっても本質的な問題(誰がデータの一貫性を保証する)は解決しない
  26. 26. 5章EAV(エンティティアトリビュート・バリュー ) • 5.5 サブタイプモデリング • スーパータイプ、サブタイプについて • 排他的(片方に存在)、共存的(重複して存在) • 完全(スーパータイプのキーが全てサブタイプに存在する) • 不完全(完全では無い場合) • 5.5.1 シングルテーブル継承 = スーパータイプに統合して実装 • 5.5.2 具象テーブル継承 = サブタイプのみで実装 • 5.5.3 クラステーブル継承 = スーパータイプ、サブタイプをそのまま実装 • スーパータイプに複数のサブタイプのデータを保存する場合削除運用などについてどうする? • issueがどのサブタイプに属しているかどう判断する?(不完全な外部キー) • どちらにも属していないissueの存在 • 複数のサブタイプに属しているissueの存在
  27. 27. 5章EAV(エンティティアトリビュート・バリュー ) • 5.5.4 半構造化データ = ジェイウォーク • 短所「このような構造においてSQLが特定の属性にアクセスする手段 をほとんど持っていない。」 • 5.5.5 後処理 • EAVを使わないといけない状況 • プロジェクトを引き継いだ場合 • 経験あります?
  28. 28. 6章ポリモーフィック関連 • この章に限らず大体のアンチパターンは対象となる事象からモデリングし正規化を進めたらありえない実装 • イントロ • Bugs - Comments, FeatureRequest - Comments • P68 そもそもコメントを1つのテーブルに格納したい? • この考えがアンチパターンでは?(ここからポリモーフィック関連で対策するのでアンチパターンアンチパターン話) • 抽象度を高めると同義になるが各々には別のエンティティ内のアトリビュートとして存在するところから始まる • Bugsのコメント、FeatureRequestのコメントの各々のドメイン • 具象テーブルを利用するのはNG?(Bugs,FeatureRequestsの各々にコメント情報を持つ) • 外部キーが貼れない • Bugsのコメント数の集計、FeatureRequestのコメント数の集計などを行いたい場合どうする? • 削除運用(Bugsの生存期間、FeatureRequestの生存期間が各々違う場合)
  29. 29. 6章ポリモーフィック関連 • 6.2 アンチパターン:二重目的の外部キーを使用する • 機能しない、もしくは不完全な関連(リレーションシップ)が発生する • 6.2.1 ポリモーフィック関連を定義する • ポリモーフィック関連を「機能」させるには • この章のアンチパターンとなる作法がここから始まる • ポリモーフィック関連 issue_type はEAV(メタデータ:テーブル名の挿入) • EAVと同じ問題点が存在する • メタデータの整合性を保つには?(内容が不正だった場合は?) • 6.2.2 SQLを実行して確認 • [Gist](https://gist.github.com/hironomiu/18ed8a3205110fe52852)
  30. 30. 6章ポリモーフィック関連 • 6.2.3 非オブジェクト指向の例 • 図6-3 User,Orders,Addressesの関係を読み取る • 業務でこういう関連を実装したことある? • 複数の住所を管理したい場合Usersとだけ親子関係にし,OrdersとUsers(親)もUser.Keyで親子関係にしたら? • 送付先がユーザ登録されていない場合はNG(もしくは工夫が必要)だが、一般的な関連としてある • 6.4 アンチパターンを用いても良い場合 • ORMなどで経験あります? • 6.4.1 ポリモーフィック関連を意識的に選択するとき • ORMを使った設計を行う際に、子側のテーブルを設計/作成する時点でまだ存在しない親テーブルとの関連を作成できる • ORMを使わない場合や、親子ともに1つのアプリケーションで、親子テーブルがほぼ同時期に設計される場合、この章のアン チパターンが当てはまります
  31. 31. 6章ポリモーフィック関連 • 6.5.1 参照を逆にする • 6.2.3の解法を逆さまに(UserとAddressesの関係の逆転) • 6.5.2 交差テーブルの作成 • Commentsを親としBugsCommentsを子と見立てながら連関エンティティとしBugsを紐付ける • 他のエンティティでCommentsに紐付けたい場合同様の連関エンティティを作成する(今回は FeatureRequests) • 交差テーブルを作る必要はある? • Bugs用のComments、Feature用のCommentsだと不都合あるか? • 交差テーブルにした場合BugsComments、FeatureCommentsの関係 • 同じキーの存在(排他、共存)などどう考慮する?
  32. 32. 6章ポリモーフィック関連 • 6.5.3 交差点に交通信号 • XXXComenntsにユニークキーを貼る理由 • 仕様としてXXXCommentsとCommentsを1対1にしたい? • BugsComments、FeaturesCommentsの両方に同じComment_idがある場合は? • P76 結果的にコメントがバグと機能要求の両方に関連付けられてしまうことを防げません • 6.5.5 「道」を合流させる • 「P68 そもそもコメントを1つのテーブルに格納したい?」を改めて考える • 6.5.6 issueのサブタイプ化 • ちょっと無理のある実装
  33. 33. 7章マルチカラムアトリビュー ト • イントロ • ユーザ情報などで複数の電話番号(固定、携帯、携帯2台目など)を格納したい場合どうする? • 複数のカラムを作ることで対応する? • 可変では無いので柔軟に対応できない • 7.1 目的:複数の値を持つ属性を格納する • ジェイウォークと同じテーマの問題とは? • 複数の値を持つ属性を格納するとは? • 例 タグ付け時に複数設定 • 1対N、N対Nの様々ケースデータをイメージしながらこの後読み進めると色々な解が出て良い
  34. 34. 7章マルチカラムアトリビュー ト • 7.2 アンチパターン:複数の列を定義する • RDBで定義可能なカラム数まで対応可能(有限) • 7.2.1 値の検索 • 検索が不便、Index設計はどうする? • co1=a and col2=b and col3=c • co1=b and col2=c and col3=a • co1=c and col2=a and col3=b • ‘リテラルな文字列’ in (col1,col2) の動き • P83 ‘performance’ in (tag1,tag2,tag3) ー> Full Scan • 7.2.2 、値の追加と削除 • SELECTでデータ取得、アプリでtag[1-3]の内容確認しUPDATE -> 更新も不便
  35. 35. 7章マルチカラムアトリビュー ト • 7.2.3 一意性の保証 • 一意性(行内のカラム)が保証できない • 7.2.4 増加する値の処理の限界 • Alter時の注意(業務オンライン中に実施する場合) • レプリケーション遅延も考慮する(MySQLの場合) • 「まず新規テーブルを定義し既存テーブルからデータをコピー〜」 • MySQL、Oracle各々の場合は? • Alter後SQLのメンテ(追加したカラム分だけ or XXX = ‘hoge’の追加)
  36. 36. 7章マルチカラムアトリビュー ト • 7.4 アンチパターンを用いてよい場合 • 1番目の列にはバグを報告したユーザ、2番目の列にはバグの修理を、3番目の列には修正 の確認を • 例は可変なマルチカラムでは無い状況(ドメインは同じだが、カラムには各々意味があ る) • 7.5 解決策:従属テーブルを作成する • 親子の関係で解決する メリットは? • Bugs -> BugTags(連関エンティティ)<- Tagsのような関連では? • tagの内容について整合性の責務をDBで持てる
  37. 37. 8章メタデータトリブル • 8.1 目的:スケーラビリティを高める • 「この章の目的は、クエリの実行速度を劣化させずに、データが 増加し続けるテーブルに対応できるよう、データベースの構造を 設計することです。」 • 冒頭の例は直接関係ない(かも?)8.2.8で復活する • 時間軸でデータの肥大化に対してテーブル分割、カラム追加な どのアンチパターンの施策が潜んでいると言うスタンスで読み 進めると理解し易い
  38. 38. 8章メタデータトリブル • P90 「データの移行、表領域の再構成、新しい列の追加」の背景 • 昔は表領域をきめ細かく領域管理していたが最近はhot spotを無くす考えが主流 • Oracle S.A.M.E.(Stripe And Mirror Everything) • 余談 32bit、64bit(扱えるメモリ)、搭載出来るメモリ(10年前は2Gとか)、ストレージの性能&役割分担 • メモリの格納効率を最大化する一環でDiskから要求するページ(ブロック)内の格納効率を最大化することの重 要度が現在より高く、かつ手動でスケジュール(場合によっては業務を停止して)を組んで行っていた • P91 メタデータへのデータの混入 • やりがちな例(bk,newがデータ) • rename table hoge to hoge_bk ,hoge_new to hoge; • データへのメタデータの混入の逆
  39. 39. 8章メタデータトリブル • 8.2 アンチパターン • 行数の多いテーブルを複数のテーブルに分割する • 表領域、表の容量の上限による分割(過去のRDBMSの制限からアンチパターンは出現しやすい) • 8.2.1 テーブルの増殖 • アプリケーションがどのテーブルを参照するか判断する • 業務でこういう事例ありますか? • 挿入時の主キーの衝突による性能の頭打ちを防ぐ • テーブルの分割(アプリケーションで対象テーブルの導出) • 意図したsharding(この章のshardingとは違うが) • PK(INDEX)のハッシュパーティション化
  40. 40. 8章メタデータトリブル • 8.2.2 データの整合性を管理する • データが挿入したテーブル名Bugs_2009の「2009」が意図したデータのみ格納する方法 • 8.2.3 データの同期 • テーブルを跨ぐため単純なUPDATEでは対応できない • 8.2.4 一意性の保証 • テーブルを跨いで一意にしたいケースについて • 8.2.5 テーブルをまたいだクエリ実行 • この手のUNION句をVIEWにして実装してる経験あります? • パフォーマンス上問題が発生しやすい箇所 • 8.2.8 メタデータトリブル列の特定 • 集計結果をどう扱うか
  41. 41. 8章メタデータトリブル • 8.3 アンチパターンの見つけ方 • 「今朝アプリケーションが新規データの追加に失敗した理由がわかっ た。新しい年のデータを格納するためのテーブルを作成し忘れていた んだ。」 • DRY原則でアプリケーションに持たせるべきではない責務がアプリ ケーションに存在している • パーティションでも手動で追加する場合同じ問題が潜んでいる • Oracleならインターバルパーティションで対応可能
  42. 42. 8章メタデータトリブル • 8.4 アンチパターンを用いてもよい場合 • 「過去データを最新のデータから分離するようなアーカイブが目的」 • 直近のデータが多く参照され、過去のデータは古くなるほど参照の頻度が下がるデータ • 読み取り専用にすることでパフォーマンスが向上する場合など • 「一般的に、データが最新のデータではなくなった場合、これらの過去データに対してクエリを 実行する必要性は大幅に低下します」 • 同じページ(ブロック)内に新旧のデータが混在する場合、見た目上の格納効率が高くても参 照されるデータは希薄 • 例 過去のつぶやきやメッセージなどはあまり読み返されない • 一次記憶装置(メモリ)ではなく必要になったら二次記憶装置(Disk)から読み出す
  43. 43. 8章メタデータトリブル • 8.5.1 水平パーティショニング(sharding?) • 8.5.1の例はRDBMSのパーティショニング機能 • パーティショニング機能を利用するメリットは? • パーティションプルーニング(バッチ処理向き) • パーティション単位でのセグメント管理(Partition Dropによる領域解放) • 挿入時のボトルネックの改善(主に主キーの衝突をRDBMSレベルで回避) • 主にハッシュパーティション • RDBMSレベルでのI/Oのコントロール(均等化、局所化) • 均等化 主にハッシュパーティション、局所化 レンジ(日付、最新のみ書き込み参照) • 一般的(?)なshardingとは • 物理的な分割(ただし各ノードのI/Oは均等になるよう設計) • 水平の1スライス毎(shard毎)に独立し全機能の提供
  44. 44. 8章メタデータトリブル • 8.5.2 垂直パーティショニング • 機能分割、カラム分割 • 余談 1台のサーバでサービス提供している場合 • WEB+AP,DBと2台のサーバに分けるのも垂直分割(パーティションでは無いが) • Text,Blob以外の切り離しだと • user_master,user_attributeのようなモデリング • どちらも不要なI/Oを減らせる • 8.5.3 イントロの解決策は?
  45. 45. 9章ラウンディングエラー • 型毎のbyte数 • http://dev.mysql.com/doc/refman/5.1-olh/ja/numeric-types.html • (浮動小数点型では、MySQL は単精度値には 4 バイトを使用し、倍精度値には 8 バイト使用します。 ) • 9.2 アンチパターン • IEEE_754 • http://ja.wikipedia.org/wiki/IEEE_754 • DB視点での型の選択 • ドメイン • 可逆性(もしくは同一値) • エスケープしてからデータを格納する -> 基本NG • キャストしてからデータを格納する -> 基本NG • 導出項目、導出結果(計算結果)の扱い
  46. 46. 10章サーティワンフレーバ ー • 章を読む前に「マスターテーブル(エンティティ)」とは • 組織や人、「もの」などの経営資源を管理するもの(DataBaseSpecialist 過去問) • status等の状態をマスタ(10.5 解決策 参照テーブルとして持つ)で管理する? • 区分やフラグ -> アプリケーション側に値の妥当性についての責務 • なんでもマスタにして困る?(テーブルを沢山作って困る事ある?) • 一度に開けるテーブル数の制限(がある場合)、file descriptorの制限 • 10.1 列を特定の値に限定する • 特定の値に限定する = カラムデータの妥当性の責務をどこに持たせるか • DRY原則 アプリ or DB? • DBの場合 チェック制約?ユーザ定義型?エンティティ? • アプリの場合 区分値等による判断(テーブルにはコメント句で明示)
  47. 47. 10章サーティワンフレーバ ー • 10.2 アンチパターン • enum,check • 内部的に列に格納されるのは、定義されたリスト中の文字列の位置です。 • 余談 厳密判定について mysql set sql_mode ='STRICT_ALL_TABLES'; • [MySQL](http://dev.mysql.com/doc/refman/5.6/en/sql-mode.html) • ドメイン、ユーザー定義タイプ(UDT)などのRDBプラットフォームごとの実装具合 • 解決策も論理設計上のドメインは利用されている? • 10.2.1 中身はなんだろう • 挿入して良い状態(区分値)をテーブル検索して把握したい時がある? • 実際のデータからではなくテーブル定義(メタデータ)情報をディクショナリから取得し確認する? • 「INFORMATION_SCHEMAシステムビューを検索するには」
  48. 48. 10章サーティワンフレーバ ー • 10.2.2 新しいフレーバーの追加 • 整数値の区分にしアプリケーションに整数値に対応した責務を持たせたら? • ETL(Extract、Transform、Load) • DWHなどでデータ挿入の仕組みで良く利用される • 10.2.3 昔ながらの味は色褪せない • 過去データを業務仕様としてどう捉えるか?(基本変更しない?) • 過去データはそのまま、新しいデータから新しいSTATUSにしたい場合どうする? • マスタにして更に有効フラグのような状態を持つ?
  49. 49. 10章サーティワンフレーバ ー • 10.2.4 移植が困難 • 特定の製品にロックインされない状態は好ましい • 10.3 アンチパターン • 「異なる場所で情報を二重管理していると、このようなリスクが生じます」 • DRY原則 • 10.4 アンチパターンを用いてもよい場合 • ENUMはあくまでも例で「メタデータを検索するのは困難であるものの」とある通りデー タの整合性の責務を「どこに?」「どのように?」持たせるかを意識して読み取る
  50. 50. 10章サーティワンフレーバ ー • 10.5.3 廃止された値のサポート • 新規挿入からは新しい値を反映するが過去分の値は変更したく無い場合 • BugsStatus.activeカラムはサーティワンフレーバーにならない? • 前前ページ 10.2.3 「マスタにして更に有効フラグのような状態を持つ?」 • 10.5.4 移植が用意 • テーブルによる実装なのでどのRDBMSでも実装は容易 • 10.5.3のように値の有効、無効を追記した場合参照整合性は保てるが意図したもの からはずれる?
  51. 51. 11章ファントムファイル • アーキテクチャ上の都合 バッファキャッシュ(格納効率)、ネット ワーク(memory - disk)RDBはオンメモリではない、RDBと直接 CDNとの連携とか出来る? • イントロ • 画像ファイルの実体はファイルシステムで管理しパスをDBに保 存し紐付ける • ファイルシステム上の画像はバックアップしない? -> DBと整 合性の合うバックアップ方法は?
  52. 52. 11章ファントムファイル • 11.2 アンチパターン:物理ファイルの使用を必須と思い込む • 「物理ファイルの使用を必須と思い込む」という選択肢しかないと思い、かつDBと物理ファイルでの一 貫性に配慮が掛けることがアンチパターン • 11.2.1 ファイル削除時の問題 • パスの削除だけではファイルは残る • バッチによる定期的なクリーンアップ • 11.2.2 トランザクション分離の問題 • トレードオフとしてREDO、UNDOに画像データが乗るためオーバーヘッドが大きい • 11.2.3 ロールバック時における問題 • 11.2.2の問題を抱える。11.2.1のようにパスだけ削除し非同期でクリーンアップで対応する方法もある
  53. 53. 11章ファントムファイル • 11.2.4 バックアップ • 画像データも含め一貫性のあるバックアップが必要なケースの場合DBに格納するべき • 一般的にはDB、ファイルシステムのバックアップは非同期でも問題のないシステムが多い • 11.2.5 SQLアクセス権限使用時における問題 • DBとOSの双方で認証、認可について整合性を取るシステム設計が必要 • 11.2.6 ファイルはSQLデータ型ではない • パスの妥当性の確認、アプリケーション側でパスの内容に対する責務が存在する(存在しないパスの対策など) • 11.3 アンチパターンの見つけ方 • リストア試験 DB、物理ファイルのバックアップタイミングの不一致を考慮したリストア後のサービス稼働の確認 • 削除運用、DB、物理ファイルのACL、物理ファイルの変更(更新)&巻き戻し手段 • 「そのプロジェクトできんちんと検討されないまま、外部ファイルの使用が採用されている」
  54. 54. 11章ファントムファイル • 11.4 アンチパターンを用いてもよい場合 • データベースの容量が減らせるとなぜ良いか? • データベース上の共有メモリやメモリとDisk間のネットワークなどについて • Webシステムの場合、CDNなどと連携する場合 • 11.4.1 常に2つの設計を検討する • 「そうした様々な技術的制約があったことを考えれば」全てのアンチパターンに通じるが過去の技術的制約によ り当時はベストな選択だったものが現在はアンチパターンとなっているもは多い • 11.5 BLOBの採用 • [BLOB](http://dev.mysql.com/doc/refman/5.6/en/blob.html) • 2つの設計として常に検討する。メモリの大容量化、キャッシュアルゴリズムの洗練など選択肢に入るケースは 多い。
  55. 55. 12章インデックスショットガ ン • 12.1 目的:パフォーマンスを最適化する • パフォーマンスを最適化するとは? • システム(チューニング) マクロ、トップダウン • SQL(チューニング) ミクロ、ボトムアップ • 最適化の対象や指標は? • CPU利用率(+LA)、メモリ使用量(+ヒット率)、レスポンスタイム、スループット • 「データベースのパフォーマンスを改善する最善の方法は、インデックスを効果的に使用すること」 • 必要となる結果セットを取得する際に結果セットに限りなく近い物理アクセスで済むことがI/OバウンドのDBでは最良となる 場合が多い • インデックスが適切に利用されたかをどのように判断する? • システム 稼働情報の確認 • SQL アクセスパスの確認
  56. 56. 12章インデックスショットガ ン • 12.2 アンチパターン:闇雲にインデックスを使用する • 適切なインデックスの張り方とは? • そのテーブルにアクセスするSQLの把握、SQLの監視 • 12.2.1 インデックスをまったく定義しない • 検索時のコストとトレードオフ • 12.2.2 インデックスを多く定義し過ぎる • インデックスの多寡(挿入更新時のオーバーヘッド)が問題になる場合もあるが、多寡より 実際に使われるSQL(SELECT、INSERT、UPDATE、DELETE)を踏まえて考えるべき • このテーブルがMySQL InnoDBの時、①がPKと構造的に違いがあることに注意
  57. 57. 12章インデックスショットガ ン • 12.2.3 インデックスが役立たないとき • しかし、名前(ファーストネーム)が「チャールズ」の人を • BtreeIndexの特徴 ユニークなデータを均一な計算量で導出 • 以下は何故インデックスが役立たないか?改善策は? • (last_name,first_name) -> order by first_name,last_name • where MONTH(date_reported) = 4
  58. 58. 12章インデックスショットガ ン • P134 選択性(selectivity) • カーディナリティ(が高い=種類が多い) • ヒストグラム(データの分布状況) • MySQLではSQL実行時に都度ヒストグラムを取りアクセスパスを決定 • B+treeだけではなくRDBで一般的に実装されているインデックスを理解しているか?(適材適所な利用をす る) • B+treeが効果的なシチュエーションは? • index skip scan , index full scanと言われてピンとくる? • ビットマップインデックスが効果的なシチュエーションは? • その他インデックス(ハッシュ、ファンクション、全文)
  59. 59. 12章インデックスショットガ ン • 12.5 MENTOR • 12.1のパフォーマンスを最適化するとは?からある指標により行う • Measure(測定) • 観察の方がしっくりくる?(もしくはこの前に観察がある) • ピックアップ対象の指標は?(読み込みページ数、CPU利用時間、SQL実行時間など) • Explain(解析) • QEP : クエリ実行計画 • Nominate(指定) • インデックスを使用させる理由は?(オンライン処理 • カバーリングインデックス パフォーマンス対策の1つの手段
  60. 60. 12章インデックスショットガ ン • Test(テスト) • 評価軸や改善目標は? • レスポンスタイム、スループット、物理読み込み、論理読み込み、CPU時間、SQL実行時間 • Optimize(最適化) • システム(サーバ、RDBMS)の最適化としてここでは使われている • Rebuild(再構築) • なぜRebuildすると良いのか? • フラグメンテーション、不均衡(B+treeでは基本的には無い)の解消 • MySQL Optimize • Oracle ALTER INDEX~ Rebuild [online] • テーブルの再構築(再編成)もパフォーマンス改善になる
  61. 61. 13章フィア・オブ・ジ・アンノウ ン • 前提知識 • NULL、空文字について • MySQLのnull、 空文字の扱い(nullと空文字を区別する) • [Problems with NULL Values](http://dev.mysql.com/doc/refman/5.6/en/problems-with-null.html) • [NULL 値に関する問題](http://dev.mysql.com/doc/refman/5.6/ja/problems-with-null.html) • Oracleのnullの扱い(空文字をnullと扱う) • [NULL とは](http://www.shift-the-oracle.com/element/null/) • wiki • [Null](http://ja.wikipedia.org/wiki/Null)
  62. 62. 13章フィア・オブ・ジ・アンノウ ン • イントロ • パイプによる連結 • SELECT first_name || ' ' || last_name AS full_name FROM Accounts; • concatによる連結(mysqlは主にこちらを使う) • SELECT concat(concat(first_name , ' '),last_name) AS full_name FROM Accounts; • mysqlでパイプを連結で利用する場合(セッションにて設定時) • set @@session.sql_mode = ‘PIPES_AS_CONCAT’; • COALESCE • [MySQL en](http://dev.mysql.com/doc/refman/5.6/en/comparison-operators.html#function_coalesce) • [MySQL ja](http://dev.mysql.com/doc/refman/5.6/ja/comparison-operators.html#function_coalesce) • [Oracle](http://docs.oracle.com/cd/E16338_01/server.112/b56299/functions030.htm)
  63. 63. 13章フィア・オブ・ジ・アンノウ ン • 13.1 目的:欠けている値を区別する • 無(null)、不明(unknown)、適用不能(inapplicable) • 作成時点では不明な値 • 更新(update)により値を設定 • 13.2 アンチパターン:NULLを一般値として使う、または一般値をNULLとして使う • 文脈的には13.2.1-13.2.4までの全てがアンチパターンとして捉える • 13.2.1 式でNULLを扱う • select null + 10 ; • select 0 / null ; (0除算)
  64. 64. 13章フィア・オブ・ジ・アンノウ ン • 13.2.2 NULLを許容する列の検索 • select * from Accounts where middle_initial = ‘J.'; • select * from Accounts where NOT(middle_initial = ‘J.'); • 13.2.4 NULLの使用を避ける • どのような問題があるか? • 特定の値、文字列に別の意味を持たせるリスク • 「例えば、不明(unknown)な値を表すために、-1を使用する場合を考え ます」
  65. 65. 13章フィア・オブ・ジ・アンノウ ン • 13.4 今回のアンチパターンとは • NULLを一般値として利用したり、一般値をNULLに相当するものとして扱うこと • 13.5 3値理論 2値理論にNULLが追加 • そもそも2値理論とは(and,or,xor,not) • 論理「和」or • 論理「積」 and • 13.5.1 スカラー式でのNULL • NULL = 0 (nullは0値かどうか不明の方が妥当) • NULL = NULL (不明な値と不明な値の「値」の比較は成り立たない。FALSE) • NULL IS NULL (「不明」な値と「不明」な値は「同じ不明」なのでTRUE) • 論理式でのNULL
  66. 66. 13章フィア・オブ・ジ・アンノウ ン • 13.5.2 論理式でのNULL • 論理「和」= 「or」 • 論理「積」= 「and」 • 直感的にイメージできますか? • 13.5.3 NULLの検索 • <=> ,is distinct from • select * from Accounts where middle_initial is NULL; • select * from Accounts where middle_initial <=> NULL;
  67. 67. 13章フィア・オブ・ジ・アンノウ ン • 13.5.4 NOT NULL制約 • いつNOT NULLを使う?(文字列の場合、数値の場合、その他) • データフローを踏まえてみる(更新時に値の登録等) • sql_mode、NULL、空文字 • 最後 • [データ型を問わず、欠けている値にはNULLを用いるようにしましょう。] • 補足 有識者のNULLに対する考え方 • [リレーショナル・データベースの世界 ](http://www.geocities.jp/mickindex/database/db_getout_null.html)
  68. 68. 14章アンビギュアスグループ(曖昧なグルー プ) • [gist](https://gist.github.com/hironomiu/f4643e5d679cea1f4f72) • 14.1 曖昧なグループ化 • SQL標準に則ったグループ化 • SELECT product_id, MAX(date_reported) AS latest FROM Bugs JOIN BugsProducts USING (bug_id) GROUP BY product_id; • 曖昧なグループ化(SQL標準に則っていない) • SELECT product_id, MAX(date_reported) AS latest,bug_id FROM Bugs JOIN BugsProducts USING (bug_id) GROUP BY product_id; • 14.2 アンチパターン • そもそもSQL標準から外れたSQLの利用は避ける
  69. 69. 14章アンビギュアスグループ(曖昧なグルー プ) • 14.2.1 単一値の原則 • 一般論(DataBaseSpecialistとかの解答)では • group by句を指定したSELECT文では、SELECTの後に指定する列には次のものだけが可能である。 • グループ化対象化の列(group byの後に指定した列名)、集合関数、定数 • 14.2.2,14.3,14.4 • SQLを実行して確認する • 14.3 単一値の原則に反する • ONLY_FULL_GROUP_BYについて • [MySQLマニュアル](http://dev.mysql.com/doc/refman/5.6/en/sql-mode.html)
  70. 70. 14章アンビギュアスグループ(曖昧なグルー プ) • 14.5.1 関数従属性 • 項目Xの値が決定すると、項目Yの値が一つに決定される • 14.5.2 相関サブクエリ • パフォーマンスに注意(但しMySQL5.6からは改善されている模様) • http://gihyo.jp/dev/serial/01/sql_academy2/000901 • 14.5.3 導出テーブル • 「ただし、データベースは導出テーブルの中間結果をテンポラリテーブルで格納しなければならいため」 • パフォーマンス上、ボトルネックになる可能性がある • MySQLの場合tempテーブルの
  71. 71. 14章アンビギュアスグループ(曖昧なグルー プ) • 14.5.4 JOIN(外部結合) • where xxx is nullにより外部結合にて存在しない行のみ取り出すテクニック • 14.5.5 集約関数の利用 • 単一値の原則に則っている(本来はこうあるべき)取り出したい結果セットに依存する • 14.5.6 グループごとにすべての値を連結する • ジェイウォーク的な結果セットを返す • 結果セットを受けた側で区切り文字から値を抜き出す • 対象レコードを全て取るより冗長な部分(product_id、latest)が省かれるぐらいのメリットしかない • [MySQLマニュアル](http://dev.mysql.com/doc/refman/5.5/en/group-by-functions.html#function_group-concat)
  72. 72. 15章ランダムセレクショ ン • イントロ • 「テスト環境のデータベースでテストデータを使用し」-> 本番環境との 差異(今回は日々蓄積されるデータ量) • 15.1 目的:サンプル行をフェッチする • 「プログラミングにおける再現性と決定性の原則」 • 「直接データベースからクエリでサンプルを抽出する方が良い方法」 • SQLでデータのランダムサンプルのみを返す、効率の良い方法とは?
  73. 73. 15章ランダムセレクショ ン • 15.2 アンチパターン:データをランダムにソートする • ランダムにソートを行い、最初の行を取得する • 少量のデータに対してクエリを実行するときは特に目立ちません。 • 本番稼働後にデータベースのデータ量が増えていくにつれ、問題が現れ始める • データ走査は常にO(N)となり線形、ソートは設定した閾値内までメモリだが閾値を越えた場合Diskソ ートとなり性能劣化は激しい • 「インデックスとは本質的にある列の値を事前にソートした集合」 • B+*treeインデックスの特徴 • 「ランダムソートのもう1つの弱点〜必要な行が最初の1行」 • すべての行を対象としたソート以外の抽出方法はある
  74. 74. 15章ランダムセレクショ ン • 15.4 アンチパターンを用いてもよい場合 • データセットが小さい場合は特に問題にはなりません • 余談 mysql rand() について • select *,rand() from sort_a order by rand(); • select句のrand()とorder byのrand()は同値の可能性が高い • where句での評価 • select *,rand() from sort_a where rand() > 0.5 order by rand() desc; • where句とはselect句、order byとは同値とならない
  75. 75. 15章ランダムセレクショ ン • 15.5 解決策:特定の順番に依存しない • ランダムなソートを用いたクエリでは、テーブルスキャンが発生し、インデックスを 使えない高コストなソートが行われてしまいます。 • 15.5.1 1と最大値の間のランダムなキー値を選択する • select ceil(rand() * (select max(id) from sort_a)); • キー値が連続の場合に有効 • 15.5.2 欠番の穴の後にあるキー値を選択する • 文中の b1.bug_id >= b2.bug_id ORDER By b1.bug_id LIMIT 1 で性能的な問題があるケ ースは?
  76. 76. 15章ランダムセレクショ ン • 15.5.3 すべてのキー値のリストを受けとり、ランダムに1つを選択する • ランダムなデータの取得責務をアプリにて • 15.5.4 オフセットを用いてランダムに行を選択する • select * from sort limit 1 offset 10; • SQLの書き方次第ではアンチパターンと同様にFull Scanが発生しソートのみオフセット内 の低コストとなるので注意 • 15.5.5 ベンダー依存の解決策 • Oracle sample句 データを格納しているBlockをサンプリングする • 統計情報の取得などでも用いられている手法
  77. 77. 16章プアマンズ・サーチエンジ ン • イントロ • crash、crashed、crashes、crashingなどをヒットさせる方法は? • 16.1 目的:全文検索を行う • 「比較の際には値全体が比較されます。」 RDBのおさらい。 • エンティティ(キーからレコードを導出)、リレーションシップ(正規化 により抜き出したエンティティ間の繋がり) • キーから文字列「群」の導出。文字列からキーの導出、キーから文字列群 の導出
  78. 78. 16章プアマンズ・サーチエンジ ン • 16.2 アンチパターン:パターンマッチ述語を使用する • LIKE述語、正規表現(サポートされてるデータベース製品は多数) • 基本FullScanとなる • 意図しない検索結果 • ワードレベルなら許容出来る場面もあるが、フレーズレベルになると許容出来ないことも多い • 単語境界を考慮 例 REGEXP ‘[[:<:]]one[[:>:]]’ • 一般的な英文(スペース区切り) = ジェイウォーク? • P183 転置索引の自作 • 文字コードによるソート、意図した価値によるランク、出現頻度、その他 • 16.3 アンチパターン • 「データ量が増加すると、このアンチパターンのスケーラビリティ上の弱点が明らかになります。」
  79. 79. 16章プアマンズ・サーチエンジ ン • 16.5 解決策:適切なツールを使用する • RDBで利用される全文検索 • Full text index(MySQL)、mroonga(MySQL)、Oracle Text(Oracle) • 全文検索エンジン • Apache Solr、Elasticsearch • 検索結果の出力順 • 文字コードによるソート、意図した価値によるランク、出現頻度、その他 • 結論と言うか。。。 like < full text < mroonga .. 全文検索エンジン • 同じDBで管理出来るなどメリットもあるが。。。餅は餅屋
  80. 80. 16章プアマンズ・サーチエンジ ン • 転置インデックスの自作 • 転置インデックスとは? • 検索対象となりうる可能性があるすべての語のリスト(辞書+リスト)です。 • 語の取り出し方(辞書化) • 形態素解析、N-gram • 辞書とテキスト内の語を紐付け素なデータを作成する • 辞書からテキスト群を参照し存在する語(列)を行として定義する • 辞書の語を行としテキスト毎を列とした「転置」を行う • 転置インデックス(辞書+リスト(行)) • リスト内の列はテキスト数分あるためリレーションで表現する限界を越える。但し内容は素なデータ。 • リレーション以外で格納効率やランクなどを考慮した最適な格納(全文検索エンジン)
  81. 81. 17章スパゲッティクエリ • デカルト積(直積) • ただしデカルト積が問題の本質じゃなく「取り出すデータ≒アクセスするデータ」のSQLを記述す ることが大事 • 17.1 目的:SQLのクエリ数を減らす(SELECT以外も含め) • メリット ネットワーク間のやりとりが減る • デメリット 意図しないアクセスパスになりパフォーマンスの問題が出る場合がある • MySQLの場合は相関サブクエリと解釈されるSQLは問題になりやすい • レプリケーション環境はレプリケーション遅延について考慮も必要 • DWHなどのRDBMSでは1つのSQLに纏める方がパフォーマンス上、良い場合もあるので都度見直 す
  82. 82. 17章スパゲッティクエリ • 17.2.1 意図に反した結果 • 本文中のSQL読み取れます?(デカルト積) • 17.2.2 さらなる弊害 • 複数テーブルをJOINしたSQL < —— > シンプルなSQLをアプリケーションでコントロール • どちらも一長一短あるのでトレードオフなど踏まえ検討(OLTP&行志向(シンプルなSQLが好まれる) <—> 列志向DB(まとまっ たSQLが好まれる)) • 過度に複雑なSQLはアンチパターンに陥りやすい • 過度にシンプルなSQLをアプリケーションでコントロールするとDBで最適化できない問題あり • ネットワークボトルネックなど • 17.4 アンチパターンを用いるケース • ALL ROWSに最適化された製品 • DBの得意領域(データのソート)
  83. 83. 17章スパゲッティクエリ • 17.5 分割統治 • アプリケーション開発の責務分割と同じだがRDBではオプティマイザの存在に注意 • BI、DWH 分割しない方が良い場合がある(主にネステッドループ以外を利用する場合)。ALL Rows • OLTP(Online Transaction Processing)チューニングで分割統治する場合がある。FirstRows • 17.5.1 • なぜLEFT JOIN • 17.5.2 unionを用いる • 集合演算子 union ,union allの違い • どちらも和集合で重複無し、重複有りの違い • intersect(積集合)、except(差集合)
  84. 84. 17章スパゲッティクエリ • 17.5.3 CASE式とSUM関数を組み合わせる • CASE式が有効な場合のSQLとは? • 17.5.4 上司の問題を解決する • 責務単位でSQLを記載 • 責務単位なので必要な場合はJOINも用いる • 「いま見てきたクエリのうちいくつかは、それ自体で十分に手の込んだものであると言えます。」 • 17.5.5 SQLを用いたSQLの自動的な記述 • All Rows(スループット),First Rows(レスポンスタイム)を意識する • SQLが長くなることを避け分割統治する意味はある? • 意味のない冗長なSQLは問題だが意図のある長いSQLは有効
  85. 85. 18章インプリシットカラム(暗黙の列 ) • イントロ エイリアス(別名) • エイリアスの利用出来るシーン • SELECT句中のカラム名、FROM句中のテーブル名 • エイリアスと言うのが妥当じゃない可能性があるがGROUP BY句中に自然数 • エイリアスのメリット(重複を区別する以外にパフォーマンスの向上(後述の閑話にて)) • イントロのようなSQLはDB、アプリ(例はPHP)のどちらでもエラーにならない? • 「1つの列にはエイリアスを付けて、かつ他の列もすべて取得するには」 • SELECT a.*,b.* FROM ~
  86. 86. 18章インプリシットカラム(暗黙の列 ) • 18.1 タイプ数を減らす • 補完機能を利用する • 「*はすべての列を意味するため」 • 「列の集合」のニュアンスより「行」を示すニュアンスが強い • 18.2 アンチパターン:ショートカットの罠に陥る • アプリケーション開発の中で組み込むSQLと言う文脈で読む • 18.2.1 カラムの追加時 • insert時に明示的にカラム指定する場合と暗黙指定(明示的にカラム指定しない場合) • select時に同様
  87. 87. 18章インプリシットカラム(暗黙の列 ) • 18.2.2 隠れた代償 • 従来のRDBMSを想定(ビッグデータなどで使われるSQLは除外) • 「多くのデータがアプリケーションとデータベースサーバ」 = ネットワークコスト • DISK(セクタ、キャッシュ) -> メモリ(ページ) -> ネットワーク(プロトコル由来) アーキテクチャ上での伝搬理 解 • 18.2.3 求めなければ得られない • 「SQLでは「不要な列以外のすべての列」を意味する構文はサポートされていません」 • 18.3 アンチパターンの見つけ方 • 「アプリケーションに障害が発生した。データベースの結果セットを古い列名で列を参照〜」 • テストを書いて防ぐことができるか?できる場合どのようなテストを書くか? • DB内のテーブルの変更とアプリケーションとの整合性の責務は誰がどう行うか?
  88. 88. 18章インプリシットカラム(暗黙の列 ) • 18.4 アンチパターンを用いてもよい場合 • 「アドホックなSQLを素早く書きたい場合には妥当」 • 18.5 解決策:列名を明示的に指定する • アプリケーション内で記述するSQLは必ずする • 18.5.1 ポカヨケ(4章に掛かってる理由はすることがオーバーヘッドにならないから) • http://ja.wikipedia.org/wiki/%E3%83%9D%E3%82%AB%E3%83%A8%E3%82%B1 • ワイルドカードについて • 行を取る、行をカウント(count(*))する場合に使うケース • count(*) or count(pk)
  89. 89. 18章インプリシットカラム(暗黙の列 ) • 閑話 • 今昔なスレッド • [select文でアスタリスク使用 ](http://otn.oracle.co.jp/forum/thread.jspa?threadID=28001914) • [表別名によるパフォーマンスアップについて ](http://otn.oracle.co.jp/forum/message.jspa?messageID=8056606) • どのRDBMSに関わらずオプティマイザは日々進歩しているので都 度パフォーマンスについて情報をキャッチアップすること
  90. 90. 19章リーダブルパスワード (読み取り可能パスワード) • 19.1 パスワードを忘れた場合メールを通じたパスワードの再設定 • 19.2 「権限のない人に特権的アクセスを与える」とは? • アクセスコントロール? • 19.2.1 「ネットワークの上で平文パスワードをやりとりするのは、なおさら危険です。」とは? • この場合のネットワークとは?(LAN、WAN、VPN、イントラ、インターネット、プロトコル(TCP/IP、SQL*NET)な どなど) • パスワード以外の重要な情報(個人情報等)は平文で流通しても良い? • 19.2.1 「データベースサーバ上のSQLクエリログ」 • MySQL スローログ、クエリログ、バイナリログ(mysqlbinlogで整形可能) • 19.2.1 「バックアップファイル、またはバックアップメディア」 • データベースそのものの暗号化、メディアの暗号化
  91. 91. 19章リーダブルパスワード (読み取り可能パスワード) • 19.2.2 「2つの条件をひとまとめにしない」 • WHERE句にaccount_idとpasswordの2つを指定するのがNGな理由について • 19.3 アンチパターン「平文、または複合可能な暗号化」が必要な場合とは? • パスワードの特徴をトレーニングデータとした不正ユーザ検出(あり?なし?) • 19.4 本人識別と認証、認証と認可 • 徳丸本 これまで「認訓という用語をとくに説明なしに使ってきました。認証(Authentication)とは、利用者が確 かに本人で あることを芯んらかの手段で確認することを指します。Webアプリケーションで用いられる 認証手段には、Basに認証のほ か、HTMLフォームでIDとパスワードを入力させるフォーム認証、SSLク ライアント証明書を用いるクライアント認証芯ど があります。認証と対になる用語に「認可(Authorization)」があります。認可は、認証済みの利用者に権限を与えるこ とで す。具体的には、データの参照・更新・削除や、預金の振り込み、物品の購入などを「できるように する」ことです。認証 と認可は画面上とくに区別されないので、混同しやすいですね。IDとパスワードを入力して認証さ れると、即座に権限が与 えられる場合がほとんどです。しかし、アプリケーション開発やセキュリティを 考える上では、認証と認可をきちんと区別 して理解し、別物として扱う習慣をつけましょう。認証と認可については5.1節と5.3節で詳しく説明します。
  92. 92. 19章リーダブルパスワード (読み取り可能パスワード) • 19.5 ストレッチの回数 • SQLでは無理?(19.5.2 「MySQLではSHA2関数が使えます」) • select sha2(sha2(sha2(sha2(sha2(sha2(sha2(‘abcd’,256),256),256),256),256),256),256); • ソルトもconcatで付与出来そう • 19.5.1 MD5はパスワードハッシュ化に用いるべきではない • 19.5.3 「辞書攻撃」 • 19.5.4 「しかしパスワードは、SQL文の中ではまだ平文として使用されています。」 • SQLでハッシュ化しない動機となる • 19.5.5 「一時パスワードを電子メールで送る方法」 • 19.5.5 「電子メールに新しいパスワードを記載する代わりに、リクエストをデータベーステーブルに記録し、一意のト ークンを識別子として割り当てる」
  93. 93. 20章SQLインジェクショ ン • 参考 • [安全なSQLの呼び出し方](http://www.ipa.go.jp/files/000017320.pdf) • [SQLインジェクション対策もれの責任を開発会社に問う判決 ](http://blog.tokumaru.org/2015/01/sql.html) • [間違いだらけのSQL識別子エスケープ](http://blog.tokumaru.org/2013/12/sql.html) • [Webアプリケーションとかの入門本みたいのを書く人への心からのお願い ](http://d.hatena.ne.jp/ajiyoshi/20100409/1270809525)
  94. 94. 20章SQLインジェクショ ン • 20.5.1 入力のフィルタリング(=validation) • RDB的にはドメイン • 現状はAPPでvalidation、DBで型、有効桁、NOT NULL等の制約での対応 • 注釈にある通りSQLインジェクションの主となる対策ではないので注意 • 20.5.3 IN述語のパラメータ化 • SELECTしたkeyを用いたIN句は良く見かけるので重要 • ?を文字列連結し?の数分のarrayをPDOに送り込む • 20.5.5 コードレビュー • してますか? • してる場合どのように脆弱性を防いでいるか
  95. 95. 21章シュードキー・ニートフリーク (疑似キー潔癖性) • 疑似キーとは?(= サロゲートキー) • 主にRDBMSの機能(何かしらの仕組み シーケンスジェネレータ)で生成される値を格納しPKとして扱う • Oracle sequence 、MySQL auto_increment • 21.1 欠番に問題はある? • 疑似キー シーケンスジェネレータの仕様(キャッシュ破棄、ロールバック等) • 有意キー そもそも採番が番号以外の場合もある • そもそも欠番に気付く? • 欠番に問題のあるもの( = 気付く)は番号の振り方そのものを見直す。(金融関係の伝票など業務制約があるもの) • ユニーク、連番の関係(ユニークで連番、ユニークで非連番、非ユニークで連番、非ユニークで非連番) • Oracle sequenceだと細かく設定することができる。但しスタンドアロン、RACとノードの形態や機能要件を照らしあわせ性 能とのトレードオフを考慮し設定をする必要がある。 • http://docs.oracle.com/cd/E16338_01/server.112/b56299/statements_6015.htm
  96. 96. 21章シュードキー・ニートフリーク (疑似キー潔癖性) • 21.2.1 欠番を求めるSQLに不備は無い? • 存在するレコードより小さい番号の欠番 • P237 「並行処理の問題が生じる」-> P39 コラム • select max(bug_id) + 1 from Bugs; • 問題点は? • 21.2.2 「主キー値の欠番を、すぐにでも埋めたい場合」ある? • 疑似キージェネレーター = シーケンスジェネレーター
  97. 97. 21章シュードキー・ニートフリーク (疑似キー潔癖性) • 21.4 アンチパターン • 主キーを変更する状況とは? • 余談 パーティションテーブルで主キーを変更する場合、内部でどのような動作がおきるか? • 疑似キーの値それ自体が重要な意味を持つべきではない • 主キー列の値が何らかの意味を持つ場合とは? • 物流システムのテーブルで疑似キーをお問い合わせ番号にした場合、この場合は? • wiki 人口キーと自然キー • http://ja.wikipedia.org/wiki/主キー #.E4.BA.BA.E5.B7.A5.E3.82.AD.E3.83.BC.E3.81.A8.E8.87.AA.E7.84.B6.E3.82.AD.E3.83.BC
  98. 98. 21章シュードキー・ニートフリーク (疑似キー潔癖性) • 21.5.2 GUID(UUID)MySQLの場合 select uuid(); • http://dev.mysql.com/doc/refman/5.1/ja/miscellaneous-functions.html • メリット「複数のデータベースサーバ間で、重複した値を生成することな く」 • shardingの際、PK利用に有効 • ただしMySQL innodbでは整数値のシーケンスがPKとして最適 • 注意点レプリケーション時 http://dev.mysql.com/doc/refman/5.1/ja/replication-features- functions.html
  99. 99. 22章シー・ノー・エビル(臭いものに蓋 ) • 適切に例外処理を入れる • 適切に戻り値の判定をいれる • 22.2.1 See-No-Evil/anti/no-check.php • 問題点は?①例外②戻り値③戻り値④戻り値 • 22.3 動的なSQL生成 • 22.5.1 ソース参照 • 例外、戻り値の判定 • 22.5.2 デバック時に実際に構築されたSQLクエリを使用する • DBセッションを追跡 • Oracle TKPROF • クエリログの収集 • http://dev.mysql.com/doc/refman/5.1/ja/query-log.html
  100. 100. 23章ディプロマティック・イミュニティ(外交特 権) • イントロ 「安易な方法を選んだことで」 • 文書やテストがなく。。。どちらかと言うと俗人化? • 23.1 ベストプラクティス • バージョン管理 • 新規から変更はALTER文を差分で抽出とCREATE文を作り管理(ER管理ツールで行い作りバージョン管理する) • テスト • ドキュメント • 23.2 SQL(DDL、DML)を特別扱い してます? • データベース上に定義するDDLと定義後に格納されるデータ、格納されたデータを参照するDMLの違い(開発と運用) • データベース管理者は「お客さん」 • 善し悪しは別として特権部分はある。(ERの部分のような破壊的な機能やACL周りなどを考慮すると)
  101. 101. 23章ディプロマティック・イミュニティ(外交特 権) • 23.5.1 文書化 • してますか?正直面倒。頻繁に変わるため管理が大変 • ER図 • ObjectBrowserER • MySQL workbench • DBオブジェクト管理(テーブル、列、ビュー、リレーションシップ、スト アド、トリガー、セキュリティ、インフラ) • どう管理していますか?中々大変
  102. 102. 23章ディプロマティック・イミュニティ(外交特 権) • 23.5.2 バージョン管理 • 巻き戻し方 • 直進のみの性質 • 定義とデータは別 • 23.5.3 テスト • してます? • テスト対象となるコードは過去とリリース分のDDL? • データ件数に依存はある?(例 マスタ) • 死活監視では簡易テストのようなスクリプトは良く使います • 23.5.4 複数のブランチを扱う
  103. 103. 24章マジックビーンズ(魔法の 豆) • DDD?(ドメイン駆動設計?) • 24.2 • CRUD(Create,Read,Update,Delete) • アクティブレコード • 24.2.4 モデルのテスト • 24.3 • DRYの原則(Don’t Repeat Yourself:同じ事を繰り返さない) • 24.5.1 モデルを理解する • 情報エキスパート • 生産者 • 疎結合性 • 高凝集性
  104. 104. 25章砂の城 • 25.1 24時間365日、停止時間を極限まで抑える • 稼働率 例 AWS 99.9%(年間8時間46分) 高可用性により実現 • http://ja.wikipedia.org/wiki/可用性 • 25.2 想定する(サービスレベルの障害、局所(機能)レベルの障害)、対応する • キャパシティ • Disk容量、CPU、コネクション、etc • 情報を採取する • 日々観測し予測、施策を講じる • 但し情報採取がボトルネックになることもある • SPOF(単一障害点)
  105. 105. 25章砂の城 • 25.3 アンチパターン 想定外の発生 • データサイズが想定以上に増えるとどういう問題が発生するか? • 想定内ならどういう対処をしているか? • 25.4 アンチパターンを用いてもよい場合 • スタートアップ、スモールスタート • ステージ毎のアーキテクチャの見直し • 規模が大きくない時点で大規模サイトの真似をしても良いことはありません
  106. 106. 25章砂の城 • 25.5 解決策 • 25.5.5 高可用性(High Availability) • システム継続 • 冗長化(HA 現用、待機 現用、現用)、HAサーバ、RAID(ミラーリング)、N/W冗長構成 • 25.5.1 ベンチマーク(予め行うもの) • どういう情報を取ってどう判断しています? • トラフィック、データ量 • シナリオ試験(ロードジェネレータ) • 25.5.2 テスト環境 • 本番と同等(スペックだけでなくデータ等も)だと良いが全てを同等にするのは難しい • 25.5.6 ディザスタリカバリ • 最近ではBCP(事業継続計画)の一部として検討される
  107. 107. 25章砂の城 • 25.5.7 運用ポリシー • 以下について予めどのような対応をするか策定(事前に検討?)する • 高可用の限界を超えた障害 • 「ぴんぽん」現用待機の切り替えの繰り返し • 問題の調査 • 再現は困難な場合が多い • 性能の劣化
  108. 108. 付録A正規化 • A.1 リレーショナルとは何か • リレーションとリレーションシップの違い • A.2 正規化の神話 • 正規化はデータベースを遅くする • 適切なSQL、INDEX設計をしていれば遅くならない • 疑似キーを用いて参照すること • 空間効率を考慮した際に採用される
  109. 109. 付録A正規化 • A.3 正規化とは • 正規化のルールを満たしたものを正規形と呼ぶ • 情報無損失分解 • 分解後に分解前の関係に復元出来る分解(可逆的) • A.3.1 第一正規形 • 繰り返しグループがないこと • A.3.2 第二正規形 • 関数従属性の抜き出し(キー) • A.3.3 第三正規形 • 推移従属性の抜き出し(非キー)

×