Webを支える技術:URI設計のポイント

URIを変わりにくくする

Webはハイバーメディアシステム(ハイパーメディア:グラフィックス、音声、動画、テキスト、ハイパーリンクなどを絡み合わせた情報媒体)であり、リンク切れを起こすと、システムとして機能できなくなる。よって、『URIは変わらないべきである。変わらないURIこそが最上のURI』という主張がある。

じゃあ、『どういう観点が大事か🤔』となるので、その辺をまとめる。

プログラミング言語に依存した拡張子やパスを含めない

具体的には次のようなURIにしない。

http://example.jp/cgi-bin/login.pl
http://example.jp/servlet/LoginServelt

良くない点と理由をまとめる。

良くない点 理由
cgi-bin CGIはWebサーバ上でプログラムを動かすための仕組みだが、時代の流れで使われることが少なくなると、名前修正が必要になる
.pl Webサービスの言語は多々あり、メンテナンス性及び可読性を考えると、無い方が効率が良い
servlet システムをサーブレットからPHPに変えるとURIも変更になってしまう
LoginServlet 大文字小文字文化は実装言語によって異なり、誤解を与えてしまう

メソッド名やセッションIDを含めない

具体的には次のようなURIにしない。

http://example.jp/Login.do?action=showPage
http://example.jp/home.jsp?jsessionid=12345

良くない点と理由をまとめる。

良くない点 理由
showPage メソッド名がURIに含まれると、リファクタリング時にメソッド名が変更されると、URIが変わる
jsessionid=~ CookieではなくセッションIDをURIに埋め込んでしまうと、ログインの度にURIが変わる

URIリソースは表現を名詞にする

具体的には次のようなURIにしない。

http://example.jp/sample/people/123

理由は、あるリソースを取得するか更新するかは、URIで指定するのではなく、『URIに適応するHTTPメソッド』で決定する。つまり、URIとHTTPメソッドの関係は『名詞(URI)と動詞(HTTP)』となる。もう少し補足すると、URIは『何を』意味し、HTTPは『どうする(GETorPOST...)』みたいなイメージ。

リダイレクトとは

URIに変更したい時にどうするか』という問いに対しては、できるだけ『リダイレクト』を使うようにする。リダイレクトは、古いURIに転送するためのHTTPの仕組みのこと。ページを移動もしくはリネームするような時にとても大事。

URI設計のテクニック

拡張子で表現を指定する

URI設計において拡張子は良くないと上の例にもあるが、それは実装に依存するような場合で、次のようなパターンの時には良いとのこと。

項目名 説明
コンテントネゴシエーション クライアントがAcccept-Languageヘッダでリクエストする言語設定を指定し、サーバからリクエストした表現を返してもらう。
言語を指定する拡張子 http://**/hoge.jahttp://**/hoge.enといった形でリソースの言語を明示的に指定する。コンテントネゴシエーションはブラウザ設定を変更する必要があるがこっちはない。

マトリクスURI

階層構造で表現しにくいURIを表現する際に用いる。例えば地図サービスの緯度(lat)、経度(lng)を指定するようなURIは次のようになる。

http://example.jp/map/lat=35.705471;lag=139.751898

一般的に、マトリクスURIを表現する際には、パラメータの順序が意味を持たない場合セミコロン、意味を持つ場合カンマを用いる。よって、上のURIを順序で示す場合には下のようなURIになる。

http://example.jp/map/35.705471,139.751898

参考

Webを支える技術:URI概要

URIとは

URI(Uniform Resource Identifier)は、英語の意味の通り『リソースを統一的に識別するID』のこと。URIを使うことで、Web上に存在するすべてのリソースを一意に示せる。

URIは、URL(Uniform Resource Locator)とURN(Uniform Resource Name)を総称する名前。

URNは、ドメイン名と独立してリソースに恒久的なIDを振る。

image.png

下記の理由からURLが広く利用されている。

  • URNは取得できない:サーバ名やプロトコルがないので、URIとしてリソースを取得できない
  • URLが十分永続的:Webの価値向上により、リソースとURLはなるべく永続的にアクセスできるようにすべきとなったため、URNを使うまでもなくなった。

URIの構文

例えば、http://blog.example.jp/entries/1について考えると、URIを構成するパーツは次のようなものになる。

パーツ名 該当部分 説明
URIスキーム http 一般的に、そのURIが利用するプロトコルを示す
ホスト名 blog.example.jp DNSで名前解決できるドメイン名またはIPアドレスで、インターネット上で一意に定まる
パス /entries/1 階層を示すパス。そのホストの中でリソースを一意に指し示す

上記のように、インターネット上で一意になるホスト名の仕組みと、ホスト内で一意な階層的なパスを組み合わせることで、あるリソースのURIが、他のリソースと重複しないようになっている。

次のような複雑なURIを考える。

http://goruchan:pass@blog.example.jp:8000/search?q=test&debug=true#9

パーツ名 該当部分 説明
URIスキーム http 一般的に、そのURIが利用するプロトコルを示す
ユーザ情報 goruchan:pass 当該リソースにアクセスする際に利用するユーザ名とパスワードで、で区切る。
ホスト名 blog.example.jp DNSで名前解決できるドメイン名またはIPアドレスで、インターネット上で一意に定まる
ポート番号 8000 ホスト情報は『ホスト名』と『ポート番号』から構成され、:で区切る。ポート番号は、このホストにアクセスするプロトコルで用いるTCPのポート番号を示す。
パス /search 階層を示すパス。そのホストの中でリソースを一位に指し示す
クエリパラメータ search?q=test&debug=true 検索サービスに検索ワードを渡すなど、クライアントから動的にクエリ文字列を生成する時に用いる。
URIフラグメント #9 #よりも前のURIが指し示すリソース内部の、細かい部分を指定する。この例だと、ID属性がn10の要素を指す。

URIで使える文字

URIで使用できる文字列は下記の3分類で、いわゆるASCII文字。よって日本語を入れるような時には、%エンコーディングを実施する必要がある。

分類
アルファベット A-Za-z
数字 0-9
記号 -.~:`!$&'()

URI実装での注意点

WebサービスやWeb APIを実装する際のURI仕様上の注意は次の2つ。

WebサービスやWeb APIを実装する際には、なるべく絶対URIを使う方がベター。

参考

Webを支える技術:REST概要

HTTP、URI、HTMLの関係

Webを支える基本的な技術のHTTP、URI、HTMLの関係は下図のようになる。今までそこまで意識していなかったので、この関係図は『確かに、なるほどなー😲』と思いました。

image.png

アーキテクチャスタイルとデザインパターン

アーキテクチャスタイルは別名『(マクロ)アーキテクチャパターン』、複数のアーキテクチャに共通する性質、様式、作法、流儀などを指す言葉。REST(REpresentational State Transfer)もアーキテクチャスタイルで、他にはMBC(Model View Controller)やパイプ&フィルタ、イベントシステムなどある。

一方、似たような言葉でデザインパターンもあるが、デザインパターンの別名は『(マイクロ)アーキテクチャパターン』であり、アーキテクチャスタイルよリも粒度の小さいクラスなどの設計様式を指す。

両方ともアーキテクチャ設計時の設計指針、作法、流儀、つまりアーキテクチャスタイルとして利用する。

似たような言葉がいっぱい出てきたので、アーキテクチャスタイルについて、Webのアーキテクチャスタイルとアーキテクチャ、実装の違いとして表にまとめる。

抽象化レベル Webでの例
アーキテクチャスタイル REST
アーキテクチャ ブラウザ、サーバ、プロキシ、HTTP、URI、HTML
実装 ApacheFirefoxInternet Explorer

リソースとは

リソースは『Web上に存在する、名前を持ったありとあらゆる情報』のことで、具体的には下記のようなもの。

Web上においてリソースを特定できなければプログラムがリソースを処理することができないため、リソースの名前は『あるリソースを他のリソースと区別して指し示す』ためのもの。つまりリソースの名前というのは、URIのこと。

リソースについてまとめる。

  • リソースは、Web上の情報
  • 世界中のリソースは、それぞれURIで一意の名前を持つ
  • URIを用いることで、プログラムはリソースが表現する情報にアクセス可能

また、URIが持つリソースを簡単に指し示せる性質のことを『アドレス可能性』と呼ぶ。

RESTの構成

RESTは複数のアーキテクチャスタイルを組み合わせて構築した複合アーキテクチャスタイル。ベースはクライアント/サーバであり、そこに他のアーキテクチャスタイルを追加して制約を課すことで、RESTが構成されている。

  • クライアント/サーバ

    クライアントからリクエストを出し、サーバがそれにレスポンスする。

  • ステートレスサーバ

    クライアントのアプリケーション状態をサーバが管理しない。現実では、Cookieを用いたセッション管理が多々利用されている。

  • キャッシュ

    一度取得したリソースをクライアント側で使い回す。サーバクライアント間の通信を減らすことで効率的に処理する。

  • 統一インターフェース

    URIで指し示したリソースに対する操作を統一した限定的なインタフェースで行うアーキテクチャスタイル。例えばHTTP1.1では、GETPOSTなどの限られた8個のメソッドだけが定義されている。

  • 階層化システム

    インタフェースを統一化することで、システム全体を階層化しやすくなる。例えば、Webサービスでは、サーバクライアント間にロードバランサーを設置するとか、レガシーシステムとブラウザ間にHTTPインタフェースを設置することで、クライアントは同じインタフェースを利用して色々なサービスを利用できるようになる。 こうしたシステムをいくつかの階層に分離したアーキテクチャスタイルを階層化システムと呼ぶ。

  • コードオンデマンド

    プログラムコードをサーバからダウンロードし、クライアント側で実行するアーキテクチャスタイル。JavaScriptFlashなどが該当する。

RESTを構成するスタイルは上の6つであるが、実際の設計においては、その制約を除外しても良い。例えば『ステートフルにして、そのほかは制約どおり』みたいな感じで、実際に動作して価値を提供できるシステムを作ることが大事。

REST以外の代表的なアーキテクチャに『P2P:Peer to Peer』があり、サーバを介さずにピア間通信が必要な場合にはP2Pの方が適している。

参考

RESTとは

RESTとは

最近Web系を学んでいると、目にすることが多くなった『REST』ですが、これまでは『休憩?残り?』とかイメージしていましたが、ようやく出会えました😄

と、そんなことは置いておいて、『REST:REpresentational State Transfer』の略で、Webサービスの設計モデルとのこと。

・・・設計モデルと聞いてもピンとこなかったですが、

RESTは設計に際し以下を設計原則とするよう提言されています。

  • アドレス指定可能なURIで公開されていること
  • インターフェース(HTTPメソッドの利用)の統一がされていること
  • ステートレスであること
  • 処理結果がHTTPステータスコードで通知されること

参考:RESTの設計原則であるRESTful

を読んで、ようやく腹落ちしました。上記のようなことを守るように設計されたWebサービスということなので、自分がよく使う一般的なWebサービスのことを指しているんだと分かりました。

ここで、『REST以外ってどんなの🤔』となったので少し情報収集。

どうやら『SOAP:Simple Object Access Protocol』があり、RESTもSOAPも、オンラインデータ送信に対するアプローチ方法らしい。

大きな違いとしては、SOAPプロトコルであるが、RESTはプロトコルではなくアーキテクチャ原則ということ。これが意味するところは、SOAPは厳格に組み込むための設計をしなくちゃいけないが、RESTはアーキテクチャガイドラインに沿っていれば、柔軟に実装を提供して良い。

上記のようなプロトコルガイドラインという違いからも、SOAPは多くのエンタープライズのニーズに合わせた組み込みのセキュリティとトランザクションコンプライアンスを提供するけれど、処理が重くなりやすい。REST APIは軽量で、IoT (モノのインターネット)、モバイル・アプリケーション開発、サーバーレス・コンピューティングなどの先進的なコンテキストに適しているらしい。(参考:REST とSOAP)

脱線したが、RESTのアーキテクチャを守ったWebサービスAPIを公開していると、それら公開サービスからデータを取得できるようになる。取得データを用いて、自分のシステムと組み合わせ新たなサービスを作成できるというのもRESTの魅力らしい。

RESTの特徴

  • クライアント、サーバー、およびリソースで構成されるクライアントサーバー・アーキテクチャ
  • クライアントとサーバー間の通信がステートレスであること

    サーバーにクライアントのコンテンツが要求をまたいで保存されることはなく、セッション状態に関する情報はサーバーではなくクライアントが保持する。

  • クライアントとサーバー間のやりとりの一部を不要にするためのキャッシュ可能なデータ

  • コンポーネント間で統一されたインタフェース

    アプリケーションのニーズに固有の形式ではなく、標準化された形式で情報が転送される。

  • 階層化されたシステム制約

    クライアントとサーバー間のやりとりは、階層レイヤーによって仲介可能

  • オンデマンドのコード

    サーバーは、実行可能なコードを転送することでクライアントの機能を拡張可能 (ただし可視性が低下するため、このガイドラインの準拠は必須ではない)。

REST API設計の勘どころ

下記2点を覚えておく。

  • URIは情報の資源を表現しなければならない。
  • 資源の行為は、HTTPメソッド(GET、POST、PUT、DELETE)で表現する

HTTP API Design

下記を覚えておく

  • パスのネストは最小限に抑える

参考

データベース設計:グレーノウハウ

違法すれすれの『ライン上』に位置する設計

上手に使えば論理設計に効果があるが、間違った使い方をすると運用に支障をきたすといった、『バッドノウハウ』ではないが『グレー』な設計方法について学ぶ。メリデメを理解した上で利用することが大切。

代理キー:主キーが役に立たない時

主キーを決められない、または主キーとして不十分なケースに遭遇したらどうするか?具体的なケースとその対応策を次にまとめる。

ケース1:入力データに主キーになるような一意キーが存在しない

入力データが、テーブルのデータとして成り立っていないので、データベースに登録できる形にデータを『データクレンジング(データの掃除)』をして対応する。データグレンジングについては、下記で説明。

ケース2:一意キーはあるが、サイクリックに使いまわされる

例えば、次のような市町村ごとの人口データがあるとする。

市町村コード 市町村名 人口(人)
A000 A市 100
A001 B市 300
A002 C市 500

今、B市が廃止され、新しくD市となったが、業務上のルールとして市町村コードを再利用することとなっている。

市町村コード 市町村名 人口(人)
A000 A市 100
A001 D市 900
A002 C市 500

上記のように、市町村コード『A001』は、あるときからB市からD市のデータになり、過去のB市のデータを辿ることができなくなってしまう。

ケース3:一意キーはあるが、途中で指す対象が変化する

例えば、次のような市町村ごとの人口データがあるとする。

市町村コード 市町村名 人口(人)
A000 A市 100
A001 B市 300
A002 C市 500

今、B市とC市が合併し、新たな『B市』となることになったため、市町村コードも引き継いだ。

市町村コード 市町村名 人口(人)
A000 A市 100
A001 B市 800

上記のように、合併前のデータを参照することができなくなる。

代理キーによる解決

ケース2、3のような時には『代理キー:サロゲートキー』と呼ばれる、自然キー(入力データに最初から存在するキー)の代わりに新たに追加するキーで解決する。

具体的にケース2に対して実施してみる。

市町村管理コード 市町村コード 市町村名 人口(人)
0 A000 A市 100
1 A001 B市 300
2 A002 C市 500
3 A001 D市 900

ケース3についても同様の対処ができる。ただ、代理キーは論理的には不要なキーのため、論理モデルをわかりにくくしてしまう。

自然キーによる解決

ケース2、3の問題の根本は履歴管理ができないという点であった。よって履歴管理ができるように時間を表す列を追加してしまえばよい。その方法として、タイムスタンプインターバルがある。

具体的にケース2に対して実施してみる。

  • タイムスタンプ

    タイムスタンプはあるタイミングにおけるスナップショットを取るようなもの。下の例では『年度』列がタイムスタンプに相当する。

    年度 市町村コード 市町村名 人口(人)
    2007 A000 A市 100
    2007 A001 B市 300
    2007 A002 C市 500
    2008 A001 D市 900
  • インターバル

    インターバルは有効な期間を表す方法。下の例では『開始年度』『終了年度』列がインターバルに相当する。

    開始年度 市町村コード 市町村名 人口(人)
    2007 9999 A000 A市 100
    2001 2007 A001 B市 300
    2007 9999 A002 C市 500
    2008 9999 A001 D市 900

    SQLの使い勝手的には、上の例のように終了年度についてはNULLよりも、入力上許される最大値を利用するのがベター。

列持ちテーブル

『配列型は使えないが、配列を表現したい』というようなときに、下のような列持ちテーブルを使用した。

社員ID 社員名 子1 子2 子3
000A 加藤 達夫 信二
000B 藤本
001F 三島 陽子 清美

列テーブルのメリデメは次の通り。

  • メリット
    • シンプルな設計:テーブルが直感的にわかる
    • 入出力のフォーマットと合わせやすい:アプリケーションとのインタフェース設計が簡単
  • デメリット
    • 列の増減が難しい:列を増やす際にアプリケーション側の変更が必要になる場合もある
    • 無用のNULL:上のテーブル例のようにNULLが増える

メリデメの通り、『列持ち』テーブルはメリデメが拮抗している。じゃあ、どうするかというと、基本的には『行持ち』テーブルを採用する。

具体的には次のようにする社員テーブルを用意する。

社員ID 社員名
000A 加藤
000B 藤本
001F 三島

そして、行持ちテーブルで子の関係を表現する。

社員ID 枝番
000A 1 達夫
000A 2 信二
001F 2
001F 2 陽子
001F 3 清美

『行持ち』⇄『列持ち』の変換はSQLによって変換可能なため、パフォーマンス上問題になってきたらテーブル変換するという方針がベター。

アドホックな集計キー

例えば、次ようなデータがある。

市コード 市名 人口(万人)
01 名古屋 200
02 知多 14
03 刈谷 20
04 豊田 18

上のデータに対して、地方ごと(尾張、西三河東三河)の人口を求めたいというときに、アドホック(場当たり的な)な集計キーで対応すると次のような感じになる。

市コード 市名 人口(万人) 地方コード
01 名古屋 200 01
02 知多 14 01
03 刈谷 20 02
04 豊田 18 03

簡単に地方ごとの論理構成を追加できたが、何度もこれを繰り返すと、テーブルが巨大になりパフォーマンスを劣化させてしまう。よりベターな方法として次のものがある。

  • 変換テーブルを作る

    下のように新しく変換テーブルを作る。この方法だと元のテーブルには影響しないが、検索では結局結合するのでパフォーマンス問題には寄与しない。

    市コード 地方コード
    01 01
    02 01
    03 02
    04 03
  • ビューを使う

    地方コードを追加したビューを用意すればOK。実質的にはオリジナルのテーブルにアクセスしているのと変わらないため、パフォーマンスを劣化しない。

  • GROUP BY句の中でアドホックキーをつくる

    GROUP BYアドホックキーを表現する。

多段ビュー

ビューはテーブルを新規に作るわけではないので、パフォーマンスの劣化に対して有効な手段となる。ただ、利用する際には以下2点に注意する。

  • ビューへのアクセスは2段階で行われる

    ビューでデータを見る時には、ビューを作るためのSQLが実行され、そのビューを用いてテーブルにアクセスするSQLが実行されるというような2段階の実行がされている。実際の処理としては、RDBMS内部で、ビューの処理が決定され、その2段階が1つの処理として実行される場合もあるが、純粋なSQLよりも複雑な処理になる。

  • 多段ビュー

    『ビューの背後にあるテーブルの存在を、常に意識する』ということが大事。ビューを、あまりネストしてしまうとテーブルとビューの依存関係が分かりにくくなり、管理が難しくなる。『KISSの原則:Keep It Simple, Stupid.(単純にしておけ、このばか)』を心がける

データクレンジングの重要性

データクレンジングは、データベースの構築にあたり、それまでの業務で利用されていたデータをデータベースに登録できる状態にする作業のこと。そうすることで正規化のような方法を導入できるようになる。

データクレンジングは設計に先立って行う。順番的には次のように進める。

  1. オリジナルデータ(汚れた状態)の収集
  2. データフォーマットの調査
  3. データクレンジング
  4. オリジナルデータ(綺麗なデータ)の取得
  5. データベース設計(論理/物理)
  6. データベースへ登録

では、クレンジングでは具体的に何をするかというと次のもの。

  • 一意キーの特定

    レコードを一意に特定出来るユニークキーを見つける。あるキー

  • 名寄せ

    標準化の一種に数えられる作業で、表記揺れを解消して名称を統一する。(例えば、goruchanとゴルちゃん、ごるちゃんは同一人物なので、名称をgoruchanに統一するみたいなことをする)

参考

データベース設計:設計のバッドノウハウ

論理設計の『やってはいけない』

戦略の失敗を戦術で取り返すことはできない

という有名な言葉があるらしい。システム開発における戦略は設計で、プログラミングは戦術に相当する。つまり、プログラムの品質を決めるのは設計になる。そんな設計において品質を致命的なレベルで損なってしまうバッドノウハウアンチパターン)を学ぶ。

非スカラ値(第一正規形未満)

第一正規系未満(セルにデータは1つ)のテーブルも存在する。例えば、下記のような非スカラ値のテーブルを考える。

社員ID 社員名
000A 加藤 達夫
信二
000B 藤本
001F 三島
陽子
清美

上記は1つのセルに複数のデータが入っているので、正規系でない。この場合、『子』列を追加するか、『家族』エンティティを追加するのが正規化の流れだった。

その他の対処として、SQLの配列型を用いるというものもある。イメージ的には下記のようなテーブルにする。

社員ID 社員名
000A 加藤 {達夫,信二}
000B 藤本
001F 三島 {淳,陽子,清美}

配列型にすることで、セルに入れるデータを1つにできた(非スカラ値を含むテーブルを作った)。ただ、上記のデータは、データベースを扱うアプリーケーションやミドルウェアとの整合性が悪く、設計コストが増加してしまうので用いるべきではない。

『そもそもスカラ値の基準って🤔』という問いに対しては、『意味的に分割できる限り、なるべく分割したもの』というのが回答になるとのこと。理由は、SQLでは結合は簡単だが分割は難しいということが背景にある。 例えば、『坂之上田村麻呂』というデータを姓と名に分けるときに、どこまでが名前かがわからないため、最初から分けて管理していれば苦労しないという感じ。

ダブルミーニング

ダブルミーニングは、同一の列に複数の意味を持つ状態になっていることをいう。具体的には、次のテーブルの列2のような、最初体重データで、途中から年齢に変わっているようなものを指す。

年度 学生名 列1 列2
2001 A 170 62
2001 B 168 55
2001 C 155 60
2002 D 164 19
2002 E 173 21
2002 F 166 20

テーブル作成者の意図としては、以降では年齢しか使わないので、『まぁいいだろう』というような感じで対応した。今後、このテーブルを引き継ぐ人は、ある年の前後では扱っているデータが違うということを覚えておかないといけなくなる。

テーブルのデータは変数ではなく、実世界にある色々な実体(エンティティ)の写像であるので、静的なものという認識を持っておく。

単一参照テーブル

単一参照テーブルは『あらゆるタイプのマスターテーブルを、1つのテーブルにまとめてしまった』もの。例えば、次のようなテーブルは、『識別ID』+『名称』という組み合わせになっている。

会社コード 会社名
C001 A商事
C002 B建設
部署コード 部署名
B001 開発
B002 経理

よって、まとめてしまえということで、次のようなテーブルにする。

コードタイプ コード値 会社名
comp C001 A商事
comp C002 B建設
depart B001 開発
depart B002 経理

上記のテーブルは、あるときは会社名のテーブルであり、あるときは部署名のテーブルとなるような感じで、テーブル全体の意味が変わる。単一参照にすることでテーブル数は少なくなるが、テーブル内で管理するデータ数は大きくなりSQLのパフォーマンスは劣化する。 メリデメを考慮すると、用いるべきでないノウハウになっている。

テーブル分割

一般的にパフォーマンス向上のために実施されることがあり、『水平分割』と『垂直分割』の2パターンがある。

水平分割

例えば、次ようなテーブルがある。

年度 会社コード 売上(億円)
2001 C001 50
2001 C002 43
2002 C001 77
2002 C002 62

水平分割をすると、次の2つのテーブルになる。

年度 会社コード 売上(億円)
2001 C001 50
2001 C002 43
年度 会社コード 売上(億円)
2002 C001 77
2002 C002 62

年度ごとで扱うデータが減るためパフォーマンスを向上できた。ただ次の観点からRDBMSでは原則禁止になっている。

  • 分割する意味的な理由がない:正規化に沿っていない
  • 拡張性に乏しい:全データの総なめ検索などに弱い
  • 他の代替手段がある:パーティションやインデックスなどの方法がある

垂直分割

水平分割の列バージョン。結局のところ、水平分割と同様の観点により使うべきでない。

テーブル分割の代替手段

テーブル分割の代替手段として次の2種類がある。

  • 列の絞り込み

    データマートという元テーブルから欲しいデータを抽出した小さいテーブルをコピー生成する。元テーブルを破壊しないため、使い勝手は良いが、データ同期のタイミングが課題になっている。

  • サマリテーブル

    元テーブルから事前に集約を行った結果のテーブルを作っておく。何か集約したデータのリクエストが来たら、サマリテーブルのデータを返す。ただ、この手法もデータ同期のタイミングが課題になっている。

不適切なキー

主キーや外部キーに、可変長文字列(VARCHAR)は用いない。理由は、キーが果たすべき不変姓を備えていないため。キーは識別子であるので、コロコロ変わってしまっては困る。よって可変長文字列のようなタイプは適切でない。

キーには固定調文字列の『コード』列が望ましい。

ダブルマスター

ダブルマスターは、この本の中での呼び方で、同じ役割を果たすはずのマスターテーブルが2つ存在することをいう。

例えば次のような顧客テーブルがあるとする。

顧客コード 顧客名
C001 山田太郎
C002 田中太田
C003 中島義仁
顧客コード 顧客名
C001 山田太郎
C002 田中太田
K001 小島正雄

上2つは、あるシステムを統合する際に、両者のデータベースの構成が上記のようになっているような時に起こる。必要な情報が複数のテーブルに散らばっていると、それを結合するのにコストが高くなってしまう。

参考

データベース設計:正規化の背反

RDBMSの論理設計の基本の概念は正規化であり、それは『データ整合性を保持する』ために行っている。一方で正規化による背反として、『SQLのパフォーマンス劣化』を引き起こす。

正規化を行うと基本的にテーブルが増えていく。よって、SQL文を実行する際には、結合(JOIN)が必要になるが、この結合がSQL文の処理としては高コストなものになるため、多用するとSQL文の速度が悪化する。

その対処法に非正規化があるが、『正規化によるデータ整合性』と『非正規化による検索パフォーマンス』はトレードオフの関係のため、最良策にはならない。

『じゃあ、どうするの🤔』ってことだけど、原則として非正規化は許さないという立場で良いとのこと。他の手段によってパフォーマンスの向上が図れないかを、最後の最後まで検討し、それでもダメなら非正規化を行う。その時にも可能な限り高次元の正規化をするということが大事らしい。

それくらいデータベースにとって整合性は大事という知見の表れなのだと感じた😅まぁ、確かに非正規化を行うとデータが冗長になることでデータ更新時などに不整合が起きやすくなってしまうし、冗長データの同期タイミングなど色々考慮しなきゃいけなくなってしまう。

参考