<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>RDB &#8211; SRA OSS Tech Blog</title>
	<atom:link href="https://www.sraoss.co.jp/tech-blog/tag/rdb/feed/index.xml" rel="self" type="application/rss+xml" />
	<link>https://www.sraoss.co.jp/tech-blog/</link>
	<description>OSS専門の技術ブログ。PostgreSQL、Zabbixを中心に10種類以上のOSSの解説、アップデート情報、運用ヒントを提供。</description>
	<lastBuildDate>Wed, 04 Nov 2026 06:42:41 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2018/07/blog-icon-150x150.png</url>
	<title>RDB &#8211; SRA OSS Tech Blog</title>
	<link>https://www.sraoss.co.jp/tech-blog/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>増永教授のDB特論⑫「ビューサポートの基礎理論」</title>
		<link>https://www.sraoss.co.jp/tech-blog/db-special-lecture/masunaga-db-special-lecture-12/</link>
		
		<dc:creator><![CDATA[増永良文 (Yoshifumi Masunaga)]]></dc:creator>
		<pubDate>Thu, 30 Mar 2023 01:00:19 +0000</pubDate>
				<category><![CDATA[増永教授のDB特論]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[RDB]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[ビューサポートの基礎理論]]></category>
		<category><![CDATA[リレーショナルデータベース]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=12133</guid>

					<description><![CDATA[&#160; 1. はじめに  ビュー（view）はリレーショナルデータベースの始祖コッド（E.F. Codd）がリレーショナルデータモデル[1]を世に問うてから 4 年後の 1974 年に彼自身により導入されました[2 ...]]></description>
										<content:encoded><![CDATA[<p>&nbsp;</p>
<h4>1. はじめに</h4>
<p style="margin-top: -14px;"> ビュー（view）はリレーショナルデータベースの始祖コッド（E.F. Codd）がリレーショナルデータモデル[1]を世に問うてから 4 年後の 1974 年に彼自身により導入されました[2]．ビューは定義だけが存在し実体は伴わない仮想的なリレーションであるところがデータベースに格納されているリレーション，これを実リレーション（stored relation）という，と根本的に異なるところです．</p>
<p><span id="more-12133"></span></p>
<p style="margin-top: -28px;"> ビューは<b>質問変形</b>（query modification）と呼ばれる手法[3]により，ビューに対するいかなる「質問」（query，問合せ）も常に実行可能です．これは理論でも実践（=SQL）でもその通りです．つまり，ビューへの問合せは常にサポートされているということです．しかしながら，ビューを「更新」（update）しようとすると一筋縄ではいかなくなります．つまり，更新できるビューもあれば更新できないビューもあります．その理由は「ビューは実リレーションではなくあくまでも仮想的なリレーションであるから」です．では，一体どのような条件を満たすときに，ビューは更新可能となるのでしょうか？これは<b>ビュー更新問題</b>（view update problem）と呼ばれ，コッドがビューを提案した当初からさまざまな研究がなされて現在に至っています．<br />
さて，ビュー更新問題は理論的にはビュー定義の逆関数を一意に不都合なく決定できるか否かという問題として定式化できますが，一意性には意味論（semantics）が関わってくること，逆関数の存在をタップルの重複出現を許さない集合意味論のもとで論じるのか，そうではなく（SQL テーブルのように）タップルの重複出現を許すバッグ意味論のもとで論じるのかという立場の違い，あるいは逆関数の存在を従来のようにリレーションスキーマレベルで問うのか，そうではなくインスタンスレベルで問うのか，などさまざまな観点があり，それによりビューの更新可能性に大きな変化が生じることともなり，今なお，ビュー更新問題は解決済みとは言い難い状況です．<br />
このような認識のもと，本稿では「ビューサポートの基礎理論」と題して，ビューとその更新可能性の概念，ビューの更新可能性をスキーマレベルで論じることとインスタンスレベルで論じることとの違い，スキーマレベルにおけるリレーショナルビューとバッグビューの更新可能性の違いなど，ビューサポートに関するさまざまな観点を念頭に置きつつ諸概念を整理しながら議論することで，そこから見えてくるビューサポートの全貌を報告してみたいと思います．</p>
<h4>2. ビューとその更新可能性</h4>
<p style="margin-top: -18px;"><strong>2.1 ビューとは</strong></p>
<p style="margin-top: -20px;"> ビューとその更新可能性をリレーショナルデータモデルの観点から論じるとき，その基礎となるのは<b>リレーショナル代数</b>（relational algebra）です．一方，SQL のテーブルを念頭においてビューとその更新可能性を考えると，SQL ではタップルの重複出現を許すテーブル，これを<b>バッグ</b>（bag）という，の存在を前提としているので，その基礎となるのは<b>バッグ代数</b>（bag algebra）です．そこで，本稿ではリレーショナル代数で定義されるビューを<b>リレーショナルビュー</b>，バッグ代数で定義されるビューを<b>バッグビュー</b>と呼び両者を区別します．</p>
<p style="margin-top: -20px;"> さて，リレーション R(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) は dom(R)=dom(A<sub>1</sub>)✕dom(A<sub>2</sub>)✕・・・✕dom(A<sub>n</sub>) の有限部分集合として定義されます．ここに dom(A<sub>i</sub>) は属性 A<sub>i</sub> がとりうる値の全集合を表します．では，ビューは一体どのように定義されるのでしょうか？その詳細な定義は 3.1 節で与えますが，たとえば，リレーション R(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) の選択ビューV は V=σ<sub>φ</sub>(R(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>)) と定義されます．ここに，φ は dom(R) の元を引数とする述語で，σ<sub>φ</sub> はリレーショナル代数演算で選択（selection）を表します．バッグビューの定義は 4.1 節で与えますが，たとえば R(A, B) と S(A, B) を和両立なバッグとした時，<br />
R と S の加法和ビュー V は V(A, B)＝S(A, B)⨄R(A, B) と定義されるということです．ここに，⨄ は<br />
加法和を表すバッグ代数演算で，これはリレーショナル代数にはないバッグ代数に特有の演算です．</p>
<p style="margin-top: -20px;"> 理論上，リレーショナルビューはバッグビューの特殊な場合となるのですが，まずリレーショナルビューの更新可能性を論じ，それが拡張される形でバッグビューの更新可能性を論じる方がビューサポート理論の全貌を見通しやすいと考えられるのでそのような展開とします．本章では引き続きビューとその更新可能性について論じ，続く第 3 章でリレーショナルビューの更新可能性を，第 4 章でバッグビューの更新可能性を論じます．</p>
<p style="margin-top: -00px;"><strong>2.2 ビューの更新とは</strong></p>
<p style="margin-top: -20px;"> ビューの更新（update）とは，ビューは仮想的な構成体（construct）であるにも関わらず， SQL の用語を借りればビュー表（viewed table）として，あたかも実リレーションや実バッグであるかのように捉えてビューを更新しようとすることをいいます．しかしながら，ビューには実体がないことから更新できる場合もあればできない場合もあります．</p>
<p style="margin-top: -20px;"> 更新には，削除（delete），挿入（insert），書換（rewrite）があります．まず，削除と挿入を定義します．ここに dom(V) はビュー V のドメインを表します．</p>
<p style="margin-top: -20px;">   削除（<b>d</b>）：delete σ<sub>φ</sub>(V) from V; ここに φ は dom(V) の元を引数とする述語である．<br />
挿入（<b>i</b>）：insert X into V; ここに X⊆dom(V) とする．</p>
<p> リレーショナルビューの削除と挿入の定義は次の通りです（バッグビューの削除と挿入の定義は 4.2 節で与えます）．</p>
<p>● 削除（<b>d</b>）は，リレーショナル代数表現で表せば <b>d</b>: V←V－σ<sub>φ</sub>(V) と定義するということです．<br />
ここに－は差，φ は V に対する選択条件で，←はリレーションの置換を表します．<br />
● 挿入（<b>i</b>）は，リレーショナル代数表現で表せば <b>i</b>: V←V∪Xと定義するということです．<br />
ここに∪は和を表します．</p>
<p>ここで，ビューのドメインと書換について補足説明を行います．</p>
<h4 style="margin-top: -20px;">■ ビューのドメインについて</h4>
<p style="margin-top: -14px;"> ビュー V(A<sub>1’</sub>, A<sub>2’</sub>, <sub>…</sub>, A<sub>r’</sub>) のドメイン dom(V) は，一般に dom(A<sub>1’</sub>)×dom(A<sub>2’</sub>)×・・・×dom(A<sub>r’</sub>) そのものではなく，ビュー定義を満たすその部分集合として定義されます．</p>
<p style="margin-top: -20px;"> たとえば，リレーション R(A, B) の選択ビューを V(A, B)=σ<sub>B≦b</sub>(R(A, B)) とした場合，<br />
dom(V)=dom(A)×dom(B) ではなく， dom(V)=dom(A)×σ<sub>B≦b</sub>(dom(B))となります．具体的には，リレーション社員(社員番号，給与)を実リレーションとし，ビューを貧乏社員=σ<sub>給与≦20</sub>(社員) とした時，dom(貧乏社員)= dom(社員番号)×σ<sub>給与≦20</sub> (dom(給与)) と定義されます．その結果，ビュー貧乏社員に対して，挿入 insert {(100, 10), (101, 15)} into 貧乏社員; は受け付けられてその更新可能性が検証の対象となりますが，insert {(100, 10), (101, 40)} into 貧乏社員; は (101, 40) の存在により {(100, 10), (101, 40)}⊆dom(貧乏社員) とはならないのでビュー貧乏社員に対して発行できる挿入ではないということです．つまり，上記の dom(V) の定義はビューの持つ意味に抵触するような挿入をあらかじめ排除する意図があります．これにより，リレーショナル DBMS は発行された挿入がビュー定義に抵触しないか否かの検証，これはインスタンスレベルの検証となります，を行わなくて済むので大いに助かりますが，一方でクライアントにはビューの定義に抵触しない挿入を発行しなければならないことが求められます．この条件はビュー更新を（本稿では）スキーマレベルで論じたいから課せられた条件ということです．<br />
dom(V) の他の基本的な例としては，V＝R ならば dom(V)=dom(R) です．R と S を和両立とするとき和ビュー V=R∪S や差ビュー V=R－S のドメインは dom(V)=dom(R)=dom(S) です．直積ビュー V=R×S のドメインは dom(V)=dom(R)×dom(S) です．リレーション R(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) の属性集合 X（⊆Ω<sub>R</sub>），ここに Ω<sub>R</sub> ={A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>}，上の射影ビュー V=π<sub>X</sub>(R) のドメインは，X={A<sub>1’</sub>, A<sub>2’</sub>, <sub>…</sub>, A<sub>r’</sub>}，ここに 1≦1’≦2’≦…≦r’≦n として，dom(V)=dom(A<sub>1’</sub>)×dom(A<sub>2’</sub>)×･･･×dom(A<sub>r’</sub>) となります．選択ビューについては上記の通りです．R(A, B) と S(B,C) の等結合ビュー V(A, R.B, S.B, C)=<br />
R⨝<sub>R.B=S.B</sub>S のドメインは dom(V)=σ<sub>R.B=S.B</sub>(dom(A)×dom(R.B)×dom(S.B)×dom(C)) となります．<br />
R(A, B) と S(B,C) の自然結合ビュー V(A, R.B, C)=R⨝S のドメインは dom(V)=π<sub>{A, R.B, C}</sub>(σ<sub>R.B=S.B</sub><br />
(dom(A)×dom(R.B)×dom(S.B)×dom(C))) となります．リレーショナル代数演算を複合して適用して定義される一般的ビュー，たとえば，リレーション R(A, B, C)の選択と射影で定義されるビュー V=π<sub>{A, B}</sub>(σ<sub>C=c</sub>(R)) のドメインは dom(V)=dom(A)×dom(B) です．これは，中間ビュー V<sub>1</sub>=σ<sub>C=c</sub>(R) のドメインは dom(V<sub>1</sub>)= dom(A)×dom(B)×σ<sub>C=c</sub>(dom(C))ですが，V のドメインは dom(V<sub>1</sub>) の {A, B} 上の射影をとって定義されているのでそうなります．このようにビューのドメインはいずれもビュー定義と表裏一体の関係で定義されます．</p>
<h4 style="margin-top: -20px;">■ 書換について</h4>
<p>本稿では<b>書換</b>を削除と挿入の系列とみなします．このとき，ビューの削除は可能であったとしても，続く挿入には注意を払う必要があります．どういうことかを上記のビュー貧乏社員=σ<sub>給与≦20</sub>(社員)を例にすれば次の通りです．たとえば，社員番号 200 の社員の給与が 15 であったとすると，タップル (200, 15) がビュー貧乏社員に出現します．給与倍増ということで，社員番号=200 の給与を 30 に書換えるとします．このとき，書換は削除と挿入の系列とみなしているので，まずビュー貧乏社員から (200, 15) を削除して，続いて (200, 30) が挿入されるということです．3.2 節[11]項で示される通り，選択ビューは削除可能なのでビュー貧乏社員からの (200, 15) の削除は基底リレーション社員からの (200, 15) の削除に変換できます．しかしながら，続く，ビュー貧乏社員への (200, 30) の挿入は挿入の条件である {(200, 30)}⊆dom(貧乏社員)，ここに dom(貧乏社員)=dom(社員番号)×σ<sub>給与≦20</sub> (dom(給与))，とはならないので許されません．これは社員番号が 200 の社員は給与が 30 なのでもはや貧乏社員ではないので当然のことです．つまり，給与が倍増されたこの社員はビュー貧乏社員に挿入されるべきではなく，基底リレーション社員に直接挿入されるべきなわけです．つまり，(200, 30) をビュー貧乏社員に挿入するすべがないのではなく，それはリレーション社員に挿入され，その結果として社員番号 200 の社員はビュー貧乏社員には現れなくなる，それがビューの更新を考察する場合の「書換は削除と挿入の系列とみなす」の意味と処理です．</p>
<p style="margin-top: -00px;"><strong>2.3 ビューの更新可能性</strong></p>
<p style="margin-top: -20px;"> 一般にビューは仮想的な構成体なので，実リレーションや実バッグと異なりすべてのビューが更新可能とは限りません．ビューはどのようなときに更新可能となるのか，それをダヤール（U. Dayal）ら [4] が与えた定義を参考にして規定すると次のようになります． ここにデータベーススキーマを <span style="font-style: italic;"><b>S</b></span>，時刻 τ におけるデータベース状態を S<sub>τ</sub>（つまり，S<sub>τ</sub> は時刻 τ における <span style="font-style: italic;"><b>S</b></span> のインスタンス），ビュー定義を <b>V</b> で表すと，時刻 τ におけるビュー（状態）は V<sub>τ</sub>（=<b>V</b>(S<sub>τ</sub>)）です．</p>
<p style="margin-top: -20px;"><b>【定義１】</b>（ビューの更新可能性）<br />
時刻 τ におけるビュー V<sub>τ</sub> への更新 <b>u</b> が<b>変換可能</b>（translatable）であるとは，<b>u</b> の V<sub>τ</sub> から S<sub>τ</sub> への<b>変換</b>（translation）T が存在して，次の条件を満たすときをいう．</p>
<p style="margin-top: -20px;"> (a)</p>
<p>変換 T は一意（unique）である．</p>
<p style="margin-top: -20px;"> (b)</p>
<p>V<sub>τ</sub> に副作用がない（no side effect）．</p>
<p style="margin-top: -20px;"> (c)</p>
<p>T(<b>u</b>) には S<sub>τ</sub> に対する余計な更新がない（no extraneous update）．</p>
<p style="margin-top: -20px;"> (d)</p>
<p>T(<b>u</b>) はデータベーススキーマ <span style="font-style: italic;"><b>S</b></span> の一貫性制約に抵触しない．</p>
<p>以下，定義 1 を補足します．</p>
<p style="margin-top: -00px;"> <b>(a)</b></p>
<p><b>一意性</b></p>
<p style="margin-top: -20px;"> 更新可能性の大前提である変換に「一意性」を課したことは，変換 T に代替案があった時にその選択基準を設けられないためです．たとえば，リレーション R(A, B)={(1, 2)} と S(B, C)={(2, 3)} の自然結合ビュー V=R⨝S が定義されていて，V に対して削除 <b>d</b>=delete {(1, 2, 3)} from V; が発行されたとします．このとき，この削除を実現できる <b>d</b> の変換は次に示す 3 つ考えられます．<br />
T<sub>1</sub>(<b>d</b>)= delete {(1, 2)} from R;<br />
T<sub>2</sub>(<b>d</b>)= delete {(2, 3)} from S;<br />
T<sub>3</sub>(<b>d</b>)= begin; delete {(1, 2)} from R; delete {(2, 3)} from S; end;<br />
注意するべきは，T<sub>1</sub>(<b>d</b>)～T<sub>3</sub>(<b>d</b>) の持つ削除の意味がそれぞれ異なるということです．意味が異なるということは勝手な選択はデータベースの一貫性に問題を生じさせかねないということです．サイコロを振ってどれかにするというようなことは許されないということです．「一意性」はデータベースの一貫性維持のために必要な制約です．</p>
<p>&nbsp;</p>
<p style="margin-top: -00px;"> <b>(b)</b></p>
<p><b>副作用がない</b></p>
<p style="margin-top: -20px;"> 「副作用がない」とは<b>図 1</b> に示す可換図式が成立することをいいます．副作用が生じる例としては，2 つのリレーションを R(A, B)={(1, 1)}, S(C, D)={(1, 1)} として，V=R×S={(1, 1, 1, 1)} を直積ビューとします．このとき，V に対して挿入 <b>i</b>=insert {(2, 2, 2, 2)} into V; が発行されたとします．<b>i</b> を R と S への挿入の系列 T(<b>i</b>)=begin; insert {(2, 2)} into R; insert {(2, 2,)} into S; end; に変換すれば，確かに (2, 2, 2, 2) が V に挿入されますが，同時に (1, 1, 2, 2) と (2, 2, 1, 1) が V に出現してしまいます．これを副作用といい，それは意図した更新ではなかったので，その発生の源となった挿入 <b>i</b> を上記のように変換することは許されないということです．</p>
<p>&nbsp;</p>
<p style="margin-top: -00px;"> <b>(c)</b></p>
<p><b>余計な変換がない</b></p>
<p style="margin-top: -20px;"> S<sub>τ</sub>に対する「余計な変換がない」とは，たとえば，リレーション社員(<u>社員番号</u>, 社員名, 給与, 部門)={(001, 山田太郎，50，K55)，(002，鈴木花子，40，K41)，(003，田中桃子，60，K41)，(004，佐藤一郎，40，K55)}，ここに社員番号は社員の主キーとする，の射影ビュー V=π<sub>{社員番号，社員名}</sub>社員={ (001, 山田太郎)，(002，鈴木花子)，(003，田中桃子)，(004，佐藤一郎)} に挿入 <b>i</b>=insert {(007，ボンド)} into V; が発行されたとき，<b>i</b> をリレーション社員に対する挿入 T(<b>i</b>)= insert {(007，ボンド，null，<br />
null)} into 社員; ここに null は属性に値がないことを表す，に変換すれば問題は生じませんが，そうではなく，たとえば，T’(<b>i</b>)= insert {(007，ボンド，100，null)} into 社員;とすると，これで確かに射影ビュー V に (007，ボンド) が挿入されますが，基底リレーション社員にはボンドの給与が 100 であるという余計な値が挿入されることになり，これは許さないということです．</p>
<p>&nbsp;</p>
<p style="margin-top: -00px;"> <b>(d)</b></p>
<p><b>データベーススキーマの一貫性制約に抵触しない</b></p>
<p style="margin-top: -20px;"> 「データベーススキーマの一貫性制約に抵触しない」ですが，その意味するところは次の通りです．時刻 τ でビュー V に対して発行された更新 <b>u</b> に対して，条件 (a)～(c) を満たす更新変換 T(<b>u</b>) が存在したとします．このとき，時刻 τ におけるデータベース状態を S<sub>τ</sub> で表すと，S<sub>τ</sub> は T(<b>u</b>) で更新されないといけないわけですが，この更新がデータベーススキーマ <span style="font-style: italic;"><b>S</b></span> に課せられている一貫性制約に抵触してはならないということです．<br />
一貫性制約は多様です．キー制約はすべてのリレーションに課せられている一貫性制約ですが，データベース化の対象となった実世界に存在する意味的制約を反映した一貫性制約もあります．たとえば，リレーションスキーマ<span style="font-style: italic;"><b>社員</b></span>(<u>社員番号</u>, 社員名, 給与, 部門)について，「各部門には最低 2 名の社員が所属していなければならない」という一貫性制約が課せられていたとします．そして，ビュー「K55 社員」を K55 社員=σ<sub>部門=K55</sub>(社員)と定義したとします．このとき，ビュー K55 社員に対して一名の K55 社員を削除する操作が発行されたとします．ビュー K55 社員は選択ビューなので，それに対して発行された削除はそのまま基底リレーションであるリレーション社員の削除に変換可能です（3.2 項【11】項）．しかしながら，もし K55 社員が 2 名しかいなかった場合，この削除は「各部門には最低 2 名の社員が所属していなければならない」というリレーションスキーマ<span style="font-style: italic;"><b>社員</b></span>の一貫性制約に抵触するので受け付けてはなりません．これが条件 (d) の意味するところです．<br />
しかしながら，条件 (d) はビューに特有の条件ではないことに注意する必要があります．たとえば，上記のリレーションスキーマ<span style="font-style: italic;"><b>社員</b></span>に上記と同じ一貫性制約が課せられていれば，この制約は<span style="font-style: italic;"><b>社員</b></span>のいかなるインスタンスとしてのリレーション社員に（ビューを通してではなく）直接更新がかけられたときにもそれに抵触してはならない制約です．したがって，条件 (d) を特段にビューの更新可能性の条件として課するべきではないと捉え，本稿では<u>ビューへの更新は定義 1 の条件 (a)～(c) を満たすとき，変換可能とする</u>ことにします（関連した議論を 3.1.2 項でも行っています）．<br />
なお，ビュー V<sub>τ</sub> への更新 <b>u</b> が変換可能（translatable）であるとき，ビュー V<sub>τ</sub> は更新可能（updatable）であるともいいます．</p>
<div style="text-align: center;"><img decoding="async" style="margin-top: -08px; width: 600px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2023/03/viewsupport-figure11.png" alt="図１　時刻τにおいてビュー更新要求 u が変換可能であることを示す可換図式" /></div>
<p>&nbsp;</p>
<p style="margin-top: -12px;"><strong>2.4　スキーマレベル vs. インスタンスレベルアプローチ</strong></p>
<p style="margin-top: -20px;"> リレーショナルデータモデルにはリレーションスキーマとそのインスタンスという概念区分があります．時間的に不変なリレーションの構造がリレーションスキーマ（relation schema）で，一般に時間と共に変化するコンテンツとしてのリレーションがリレーションスキーマのインスタンス（instance）です．そして，両者の関係性は次の通りです[10]．<br />
「リレーションスキーマ <span style="font-style: italic;"><b>R</b></span> である性質 P が成り立つということは，<span style="font-style: italic;"><b>R</b></span> のすべての<br />
インスタンス R に対してその性質 P が成り立つとき，およびそのときのみである」</p>
<p> たとえば，リレーションスキーマ<span style="font-style: italic;"><b>社員</b></span>(<u>社員番号</u>, 社員名, 給与, 部門)があったとき「社員番号が<span style="font-style: italic;"><b>社員</b></span>のキーである」という性質は，リレーションスキーマ<span style="font-style: italic;"><b>社員</b></span>のすべてのインスタンス社員に対して次が成立することです．ここに t[社員番号]はタップル t の属性である社員番号がとる値を表します（⇒は含意を表す）．<br />
(∀t, t’∈社員)(t[社員番号]=t’[社員番号]⇒t=t’)</p>
<p>さて，先に与えた定義 1 はビューの更新可能性をインスタンスレベルで規定しています．しかしながら上記の観点から定義 1 で与えられたビューの更新可能性の定義を見直すと，ビューの更新可能性を定義通りにインスタンスレベルで規定することは勿論できますが，スキーマレベルで規定することも可能であることが分かります．どちらのアプローチをとるべきなのでしょうか，素朴な疑問に直面してしまいます．<br />
しかしながら，これまで行われてきたビューの更新可能性の議論に目を向けてみると，この問題は理論的にも実践的にもスキーマレベルで議論されてきました．なぜでしょうか？その理由は，スキーマレベルで規定することにより，与えられたビューの更新可能性をリレーショナル DBMS が検証するにあたり，検証を<b>テーブル参照</b>（table lookup）で行えるからです．つまり，ビューの更新可能性をスキーマレベルで規定しておくと，基本的ビューの更新可能性を<ruby>予<rt style="background-color: white;">あらかじ</rt></ruby>めメタデータとしてカタログに登録しておけば，一般的ビューが与えられた時，それが更新可能かどうかは，そのビュー定義を構文解析して，その構文解析木のノードに一つでも更新不可能とされる基本的ビュー定義があれば，その時点でその一般的ビューは更新不可能と判定できるからです．たとえば，「直積ビューは削除不可能」とカタログに登録されていれば，一般的ビューの定義に直積が用いられていることを見つけた時点で，このビューは削除不可能と判定できるわけです．これはビュー更新をサポートしようとするリレーショナル DBMS にとっては負荷が少なくとても嬉しく映るはずです．実際，現在のプロプライエタリあるいは OSS のリレーショナル DBMS のすべてはこのアプローチに基づいています．<br />
一方，もしビューの更新可能性をインスタンスレベルで判定すると状況は一変します．何が変わるのかといえば，<u>スキーマレベルで更新不可能とされるビューがインスタンスレベルでは状況により更新可能となる</u>ということです．たとえば，リレーション R(A, B) と S(B, C) の自然結合ビュー定義 V=R⨝S の更新可能性は，スキーマレベルのアプローチでは「押し<ruby>並<rt style="background-color: white;">な</rt></ruby>べて結合ビューは更新不可能だから V は更新不可能」となってしまいますが，インスタンスレベルのアプローチではそうはならず，「<ruby>この<rt style="background-color: white;">・・</rt></ruby>自然結合ビュー V に対して発行された<ruby>この<rt style="background-color: white;">・・</rt></ruby>更新 <b>u</b> は変換可能か否か」をケースバイケースで検証していくということです．したがって，インスタンスレベルのアプローチを採るとリレーショナル DBMS の負荷は増大するのですがクライアントにとっては更新できるビューが却下されてしまうことが少なくなるので福音となります．つまり，ビューの更新可能性をスキーマレベルで規定するのかインスタンスレベルで規定するのかは処理コストと更新可能性のトレードオフということになります．筆者らが考案した「更新意図の外形的推測に基づいたビューの更新可能性」[6, 7] はインスタンスレベルの考え方に基づいたビュー更新の新しいアプローチです．興味を抱いた方は是非，拙著論文にあたってみてください．</p>
<h4>3. リレーショナルビューの更新可能性（スキーマレベル）</h4>
<p style="margin-top: -12px;"><strong>3.1 リレーショナルビューの定義</strong></p>
<p style="margin-top: -12px;"><strong>3.1.1 リレーショナル代数</strong></p>
<p style="margin-top: -12px;"> リレーショナルビューはリレーショナル代数を使って定義されます．リレーショナル代数はコッドがリレーショナルデータモデルの一環として導入しましたが，以下に示す演算からなります [1]．<br />
<b>【定義２】</b>（リレーショナル代数演算）<br />
● 和（∪），差（－），共通（∩）<br />
● 直積（×）<br />
● 射影（π<sub>X</sub>(R)，ここに X⊆Ω<sub>R</sub>）<br />
● 選択（σ<sub>φ</sub> (R)，ここに φ は dom(R)上の選択条件）<br />
● <span style="font-style: italic;">θ</span>-結合（R⨝<sub>AiθBj</sub>S，ここに A<sub>i</sub>∈Ω<sub>R</sub>，B<sub>j</sub>∈Ω<sub>S</sub> で A<sub>i</sub> と B<sub>j</sub> は θ-比較可能）<br />
● 商（÷）</p>
<p> これら 8 つの演算の定義を<b>表 1</b> に示します．</p>
<div style="text-align: center;"><img decoding="async" style="margin-top: -08px; width: 726px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2023/03/viewsupport-chart11.png" alt="表1　リレーショナル代数演算" /></div>
<p>&nbsp;</p>
<p>補足をすれば次の通りです．</p>
<p style="margin-top: -20px;"> ●</p>
<p>リレーション R の全属性集合を Ω<sub>R</sub>={A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>}としたとき，R はdom(R)=dom(A<sub>1</sub>)×dom(A<sub>2</sub>)×・・・×dom(A<sub>n</sub>) の有限部分集合と定義されます．</p>
<p style="margin-top: -20px;"> ●</p>
<p>述語 R(t) はタップル t がリレーション R の元であるとき，つまり t∈R のとき及びそのときのみ真（true）となります．</p>
<p style="margin-top: -20px;"> ●</p>
<p>∨，∧，¬，⇒，⇔ はそれぞれ論理和，論理積，論理否定，含意，必要かつ十分，を表す命題結合子です．</p>
<p style="margin-top: -20px;"> ●</p>
<p>タップルを結合する演算子* は (a<sub>1</sub>, a<sub>2</sub>, <sub>…</sub>, a<sub>n</sub>)*( b<sub>1</sub>, b<sub>2</sub>, <sub>…</sub>, b<sub>m</sub>)=(a<sub>1</sub>, a<sub>2</sub>, <sub>…</sub>, a<sub>n</sub>, b<sub>1</sub>, b<sub>2</sub>, <sub>…</sub>, b<sub>m</sub>) と定義されます．</p>
<p style="margin-top: -20px;"> ●</p>
<p>R(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) と S(B<sub>1</sub>, B<sub>2</sub>, <sub>…</sub>, B<sub>m</sub>) をリレーションとするとき，それらが和両立（union compatible）であるとは n=m∧∀<sub>i</sub>(dom(A<sub>i</sub>)=dom(B<sub>i</sub>)) が成立しているときをいいます．</p>
<p style="margin-top: -20px;"> ●</p>
<p>t =(a<sub>1</sub>, a<sub>2</sub>, <sub>…</sub>, a<sub>n</sub>) をリレーション R(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) のタップル，Ω<sub>R</sub> の部分集合を X={ A<sub>1’</sub>, A<sub>2’</sub>, <sub>…</sub>, A<sub>ℓ’</sub>}，1≦1’≦2’≦・・・≦ℓ’≦n としたとき，t の X 上の射影は t[X]=(a<sub>1’</sub>, a<sub>2’</sub>, <sub>…</sub>, a<sub>ℓ’</sub>) と定義されます．</p>
<p style="margin-top: -20px;"> ●</p>
<p>比較演算子を <span style="font-style: italic;">θ</span>∈{＜, ≦，≠，＝,＞，≧} とします．</p>
<p style="margin-top: -20px;"> ●</p>
<p>A<sub>i</sub>∈Ω<sub>R</sub>，B<sub>j</sub>∈Ω<sub>S</sub> で A<sub>i</sub> と B<sub>j</sub> が <span style="font-style: italic;">θ</span>-比較可能とは A<sub>i</sub><span style="font-style: italic;">θ</span>B<sub>j</sub> の真，偽が常に決まることをいいます（3 値論理の場合は，真，偽，不定となります）．</p>
<p style="margin-top: -20px;"> ●</p>
<p>選択を定義する際に使用される選択条件 φ は次のように再帰的に定義されます．ここに A<sub>i</sub> や A<sub>j</sub> はリレーション R(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) の属性で，A<sub>i</sub> と A<sub>j</sub> は <span style="font-style: italic;">θ</span>-比較可能，c を定数，<span style="font-style: italic;">θ</span> を比較演算子とします．</p>
<p><b>【定義３】</b>（選択条件 φ）<br />
(i) A<sub>i</sub>θc，A<sub>i</sub>θA<sub>j</sub> は選択条件である．<br />
(ii) α と β を選択条件としたとき，¬α，α∨β，α∧β は選択条件である．<br />
(iii) (i) と (ii) で定義されるもののみが選択条件である．</p>
<p>選択条件は合成可能です．つまり，リレーション R に対して選択条件 φ を施した結果である σ<sub>φ</sub>(R) に対して，新たな選択条件 ψ を施すと，その結果は σ<sub>ψ</sub>(σ<sub>φ</sub>(R))となりますが，質問変形[3] により，<br />
σ<sub>ψ</sub>(σ<sub>φ</sub>(R))=σ<sub>ψ∧φ</sub>(R) が成立します．したがって，σ<sub>ψ</sub>(σ<sub>φ</sub>(R))=σ<sub>φ</sub>(σ<sub>ψ</sub>(R)) や σ<sub>φ</sub>(σ<sub>φ</sub>(R))=<br />
σ<sub>φ</sub>(R) などが成立します．また，選択条件とリレーショナル代数演算との最も基本的な関係は次の通りです．ここに，R, S をリレーション，ψ，φ は述語を表します．</p>
<p style="margin-top: -20px;"> ●</p>
<p>σ<sub>ψ∨φ</sub>(R)=σ<sub>ψ</sub>(R)∪σ<sub>φ</sub>(R)</p>
<p style="margin-top: -20px;"> ●</p>
<p>σ<sub>ψ∧φ</sub>(R)=σ<sub>ψ</sub>(R)∩σ<sub>φ</sub>(R)</p>
<p style="margin-top: -20px;"> ●</p>
<p>σ<sub>¬φ</sub>(R)=R－σ<sub>φ</sub>(R)</p>
<p>なお，コッドはリレーショナル代数演算として上記のごとく 8 つの演算を導入しましたが，演算の<br />
独立性に着目すると，たとえば，<b>和，差，直積，射影，選択</b>の 5 つはお互いに独立した演算であり，<br />
共通，結合，商やその他の演算をそれらを使って表せることはよく知られていることです．たとえば<br />
次の通りです．</p>
<p style="margin-top: -20px;"> ●</p>
<p>共通：R∩S=R－(R－S)</p>
<p style="margin-top: -20px;"> ●</p>
<p><span style="font-style: italic;">θ</span>-結合：R⨝<sub>AiθBj</sub>S=σ<sub>R.AiθS.Bj</sub>(R×S)</p>
<p style="margin-top: -20px;"> ●</p>
<p>自然結合：R⨝S=π<sub>ΩR∪ΩS</sub> (<sub>σR.C1=S.C1∧R.C2=S.C2∧．．．∧R.Cr=S.Cr</sub>(R×S))，ここに<br />
{C<sub>1</sub>, C<sub>2</sub>, <sub>…</sub>, C<sub>r</sub>}=Ω<sub>R</sub>∩Ω<sub>S</sub></p>
<p style="margin-top: -20px;"> ●</p>
<p>左外結合：R⟕S= (R⨝S)∪(R –π<sub>ΩR</sub>(R⨝S))×{(null, <sub>…</sub>, null)}</p>
<p style="margin-top: -20px;"> ●</p>
<p>右外結合：R⟖S= (R⨝S)∪{(null, <sub>…</sub>, null)}×(S –π<sub>ΩS</sub>(R⨝S))</p>
<p style="margin-top: -20px;"> ●</p>
<p>完全外結合：R⟗S= (R⨝S)∪(R –π<sub>ΩR</sub>(R⨝S))×{(null, <sub>…</sub>, null)}∪{(null, <sub>…</sub>, null)}×<br />
(S –π<sub>ΩS</sub>(R⨝S))</p>
<p>さらに補足をすると，リレーショナルデータモデルが提案された当初，選択は <span style="font-style: italic;">θ</span>-選択として定義されていました．その定義は次の通りです．<br />
<img decoding="async" style="margin-top: -00px; width: 726px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2023/03/viewsupport-theta.png" alt="θ-選択" align="middle" /><br />
つまり，<span style="font-style: italic;">θ</span>-選択は選択条件 φ の定義 3 の (i) 項の A<sub>i</sub><span style="font-style: italic;">θ</span>A<sub>j</sub> は選択条件であるという定義から直接導けます．また，上で記しましたが，選択条件は合成可能ですから <span style="font-style: italic;">θ</span>-選択を合成した演算が選択ということになります．したがって，両者をいたずらに区別する必要はなく，特に φ=A<sub>i</sub><span style="font-style: italic;">θ</span>A<sub>j</sub> を強調したい場合に <span style="font-style: italic;">θ</span>-選択という，と使い分けをすることとします．<br />
結合演算には上記のようにさまざまな結合形態があり，それらを峻別するために最も基本的な結合を <span style="font-style: italic;">θ</span>-結合としたと理解すればよいと思います．他の結合は <span style="font-style: italic;">θ</span>-結合を合成していくことで得られます．</p>
<h4 style="margin-top: -20px;">■ Null と 3 値論理</h4>
<p>コッドが初めてリレーショナルデータモデルを提案したとき，リレーションの属性が null（空，値がないことを表す）をとることは想定されていませんでした [1]．そこでは，リレーション R(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) は dom(R)=dom(A<sub>1</sub>)×dom(A<sub>2</sub>)×・・・×dom(A<sub>n</sub>) の有限部分集合と定義されますが，各ドメイン dom(A<sub>i</sub>) は単純（simple）である，つまり，integer あるいは文字列からなる集合で，それが null を含むことは想定されていませんでした．したがって，リレーショナル代数演算は 2 値論理に基づいて定義できました．<br />
リレーショナルデータモデルに null が導入されたのは，より多くの意味をリレーショナルデータモデルに取り込もうとレーショナルデータモデルを拡張したコッドの 1979 年の論文で，そこで初めて 3 値論理に基づくリレーショナル代数が導入されました [5]．<br />
一方，ビューの更新可能性を論じるときには，リレーションやビューの属性が null をとらざるを得ない状況が発生します．たとえば，リレーション R(<u>A</u>, B, C)，ここに A は主キー，の属性集合 {A, B} 上の射影ビュー V=π<sub>{A, B}</sub>(R) はキー保存なので，V に対する挿入は変換可能です（3.2 節【10】項）．たとえば，<b>i</b>=insert (a, b) into V; は R への挿入 T(<b>i</b>)=insert (a, b, null) into R; に変換可能です．つまり，リレーション R に当初は属性が null となるタップルが存在しなかったとしても，いずれはそのようなタップルが存在する可能性があるわけです．<br />
したがって，ビューサポートの理論ではリレーショナル代数演算は 3 値論理を導入した拡張が前提となります．この導入により影響を受ける演算は選択や <span style="font-style: italic;">θ</span>-結合で，それらは推量 <span style="font-style: italic;">θ</span>-選択（maybe <span style="font-style: italic;">θ</span>-selection）や推量 <span style="font-style: italic;">θ</span>-結合（maybe <span style="font-style: italic;">θ</span>-join）の導入に繋がります．定義 3 の (i) 項で与えたようにA<sub>i</sub><span style="font-style: italic;">θ</span>c，A<sub>i</sub><span style="font-style: italic;">θ</span>A<sub>j</sub> は選択条件であるので，これらの述語の値は A<sub>i</sub> や A<sub>j</sub> が null でなければ真か偽をとりますが，そうでない場合には「不定」（unknown）をとります．たとえば，「2＞3=偽」ですが「2＞null=不定」となります．そうすると，リレーション R(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) の推量 <span style="font-style: italic;">θ</span>-選択は σ<sub>AiθωAj</sub>(R)={t|R(t)∧t[A<sub>i</sub>]<span style="font-style: italic;">θ</span>[A<sub>j</sub>] IS UNKNOWN} と定義されます．ここで t[A<sub>i</sub>]<span style="font-style: italic;">θ</span>[A<sub>j</sub>] IS UNKNOWN の真理値は<b>表 2</b> に示される「3 値論理の IS ブール演算子真理値表」で規定されます．たとえば，属性に null を許容したリレーションを R(A, B, C)={(1, 5, 3), (2, 3, 8), (3, 2, null), (4, null, 6), (5, null, null)} とすれば，<br />
σ<sub>B＞C</sub>(R)={(1, 5, 3)} ですが，σ<sub>B＞ωC </sub>(R)={(3, 2, null), (4, null, 6), (5, null, null)} となります．なお，<br />
推量 <span style="font-style: italic;">θ</span>-結合は推量 <span style="font-style: italic;">θ</span>-選択を用いて，推量 <span style="font-style: italic;">θ</span>-結合は R⨝<sub>AiθωBj</sub>S=σ<sub>R.AiθωS.Bj</sub>(R×S) と定義できます [10]．<br />
このように，ビューサポートでは null を導入した 3 値論理に基づいた論理展開が必要なのですが，表 1 のリレーショナル代数演算の選択や <span style="font-style: italic;">θ</span>-結合の定義には推量 <span style="font-style: italic;">θ</span>-選択や推量 <span style="font-style: italic;">θ</span>-結合が陽には表れていません．もちろんそれらを許すように表 1 を拡張できますが，表 1 にそれらを明示していないのは，もっぱら 2 値論理のリレーショナル代数演算の下でビューの更新可能性を論じることで，ビューサポートの議論全体の見通しをよくしようと考えたからです．null を扱わないといけない状況に直面したときには，3 値論理に従って思考してください．たとえば，リレーション R(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) の属性 A<sub>i</sub> と A<sub>j</sub> 上の <span style="font-style: italic;">θ</span>-選択ビュー V は 3 値論理では V=σ<sub>AiθAj</sub>(R)={t|R(t)∧t[A<sub>i</sub>]θ[A<sub>j</sub>] IS TRUE} と定義されますが，これは 2 値論理での V=σ<sub>AiθAj</sub>(R)={t|R(t)∧t[A<sub>i</sub>]θ[A<sub>j</sub>]} と同値です．一方，R の属性 A<sub>i</sub> と A<sub>j</sub> 上の推量 <span style="font-style: italic;">θ</span>-選択ビュー V は V=σ<sub>AiθωAj</sub>(R)={t|R(t)∧t[A<sub>i</sub>]θ[A<sub>j</sub>] IS UNKNOWN} と定義され，3 値論理に従います．より具体的には，上記のリレーションR(A, B, C)={(1, 5, 3), (2, 3, 8), (3, 2, null), (4, null, 6), (5, null, null)} の属性 B と C 上の「推量大なり（＞）選択ビューV」は V=σ<sub>B＞ωC </sub>(R)={(3, 2, null), (4, null, 6), (5, null, null)} となりますが，B 上の「推量以下（≦）演算」を使った削除 <b>d</b>=delete σ<sub>B≦ω10 </sub>(V) from V; が発行されたとすると，<b>d</b> は T(<b>d</b>)= delete σ<sub>B≦ω10 </sub>(R) from R; と基底リレーション R に変換可能で，R から {(4, null, 6), (5, null, null)} が削除され，その結果 V={(3, 2, null)} となり，所望の削除が実現されていることがわかります．このような拡張はバッグ代数についても同様です．</p>
<div style="text-align: center;"><img decoding="async" style="margin-top: -08px; width: 520px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2023/03/viewsupport-chart2.png" alt="表2　3 値論理の IS ブール演算子真理値表" /></div>
<p>&nbsp;</p>
<p style="margin-top: -12px;"><strong>3.1.2 リレーショナル代数表現としてのリレーショナルビュー</strong></p>
<p style="margin-top: -12px;"> リレーショナルデータベースに対する問合せ（query）はリレーショナル代数表現（relational algebra expression）として記述できますが，ビューは問合せによって定義される仮想的リレーションなので，リレーショナルビューはレーショナル代数表現を使って再帰的に定義することができます．それを定義 4 に与えます．リレーショナル代数演算の独立性から，和，差，直積，射影，選択の 5 つの演算を使ってビューを定義しています．実リレーションとはデータベースに格納されているリレーショナルのことをいいます．なお，本来はリレーショナルビューと書くべきなのですが，ここでは特段の混乱は生じないと考えられるので，単にビューと記しています．<br />
<b>【定義４】</b>（ビュー）</p>
<p style="margin-top: -20px;"> (1)</p>
<p>実リレーション R はビューである．</p>
<p style="margin-top: -20px;"> (2)</p>
<p>V<sub>1</sub> と V<sub>2</sub> を和両立なビューとするとき，それらの和 V<sub>1</sub>∪V<sub>2</sub> はビューである（和ビュー）．</p>
<p style="margin-top: -20px;"> (3)</p>
<p>V<sub>1</sub> と V<sub>2</sub> を和両立なビューとするとき，それらの差 V<sub>1</sub>－V<sub>2</sub> をはビューである（差ビュー）．</p>
<p style="margin-top: -20px;"> (4)</p>
<p>V<sub>1</sub> と V<sub>2</sub> をビューとするとき，それらの直積 V<sub>1</sub>×V<sub>2</sub> はビューである（直積ビュー）．</p>
<p style="margin-top: -20px;"> (5)</p>
<p>V をビューとするとき，その射影 πx(V) はビューである（射影ビュー）．</p>
<p style="margin-top: -20px;"> (6)</p>
<p>V をビューとするとき，その選択 σ<sub>φ</sub>(V) はビューである（選択ビュー）．</p>
<p style="margin-top: -20px;"> (7)</p>
<p>(1)～(6) で定義されるもののみがビューである．</p>
<p>ビューを定義するときに使われる実リレーションをそのビューの<b>基底リレーション</b>（underlying base relation）といいます．基底リレーションを使って (1)～(6) 項のいずれかの演算を 1 度だけ使用して定義されるビューを<b>基本的ビュー</b>（basic view），定義4 の (1)～(6) 項で定義された演算を再帰的に適用して定義されるビューを<b>一般的ビュー</b>（general view）ということにします．この定義に従えば，（定義 4 には陽には出現しなかった）共通ビュー，結合ビュー，商ビュー，外結合ビューなどは一般的ビューとして定義されることになります．ちなみに，R(<u>A</u>, B, C)，S(<u>B</u>, D) をリレーション（アンダーバーは主キーを表す）としたとき，連言問合せ（conjunctive query）として定義されるビュー V=<br />
π<sub>{R.A, R.B}</sub>(σ<sub>C=c</sub>(R)⨝<sub>R.B=S.B</sub>σ<sub>D=d</sub>(S)) は一般的ビューの典型です．なお，テーブルにタップルの重複<br />
出現を許している SQL では avg, sum, max, min, count といった集約（aggregation）が有効ですが，リレーションは重複タップルの出現を許していないので SQL ほどの有効性はないと考えて，リレーショナル代数表現としてビューを定義する際には集約関数は特段に考慮していません．</p>
<h4 style="margin-top: -00px;">■ ビューと一貫性制約</h4>
<p>リレーショナル代数を使ってビューを定義しているということは，リレーショナルデータベースに対する問合せの結果をビューと称し，それらを再帰的にリレーショナル代数演算のオペランドに使用することで，あらゆる問合せの結果をビューとすることができるという意味です．ここで注意しないといけないことは，たとえば，定義 4 の (1) 項より「実リレーション R はビュー V である」と定義できますが，<u>V と R は同一ではなく</u>，SQL の表現を用いれば，問合せ SELECT * FROM R の結果リレーションをビュー V と定義したということです．どういうことかというと，R(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) としたとき V(A<sub>1</sub>, A<sub>2</sub>, …, A<sub>n</sub>) と書けて，インスタンスとしての R と V は同一ではあるものの，R をインスタンスとするリレーションスキーマ <span style="font-style: italic;"><b>R</b></span>(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) に定義されている一貫性制約は V では定義されていないということです．あくまで，V は SQL で表現すれば CREATE VIEW V AS SELECT * FROM R と定義されるように，単に SELECT * FROM R の結果リレーションでしかないからです．実リレーションとビューとのこの差異は大きいと認識するべきで，すでに関連した議論を 2.3 節 (d) 項で行っていますが，ビューはあくまで更新の窓口であって，それが更新可能である場合，その更新がデータベースの一貫性制約に抵触するかしないかの検証はそのビューを定義するために使われた基底リレーションで行うということです．なお，更新時の一貫性制約の検証はビューに特有ではなく，一般にリレーショナルデータベースの実リレーションを更新した場合でも必ず行われないといけないわけで，これがビューの更新可能性を規定した定義1の条件から (d) 項を外した理由となったことは前述の通りです．<br />
以下，実リレーション R がビュー V であることを V=R と表示したり，実リレーション R と S の和ビュー V を V=R∪Sと 表示したりしますが，「=」（等号）の意味は上記のごとく，単に右辺での問合せの結果リレーションを左辺（＝ビュー）としたということで，リレーションスキーマとしての同一性を表現しているものではありません．この議論はバッグビューに対しても全く同様に成立します．</p>
<p style="margin-top: -12px;"><strong>3.2 基本的リレーショナルビューの更新可能性（スキーマレベル）</strong></p>
<p style="margin-top: -12px;"> <b>表 3</b> に「基本的リレーショナルビューの更新可能性（スキーマレベル）」の結果を示します（ここでは，コッドの定義した 8 つのリレーショナル代数演算で定義されるビューを基本的ビューとしています）．行列値の 〇 は更新可能，× は更新不可能を表します．†はキー保存という条件を表しています．</p>
<div style="text-align: center;"><img decoding="async" style="margin-top: -08px; width: 680px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2023/03/viewsupport-chart333.png" alt="表3　基本的リレーショナルビューの更新可能性（スキーマレベル）" /></div>
<p>&nbsp;</p>
<p>以下，表 3 が得られた論拠を示します．要点は，ビューの更新可能性をスキーマレベルで論じているので，更新可能であることを示すにはすべてのインスタンスに対して更新可能であることを示す必要があること，一方で更新不可能を示すにはそのようなインスタンスと更新の組合せを 1 例示せばよいということです．</p>
<p style="margin-top: -00px;"><strong>【1】和ビューは削除可能</strong></p>
<p style="margin-top: -12px;"> R と S を和両立なリレーション，V=R∪S を和ビューとする．<br />
V に対して削除 <b>d</b>=deleteσ<sub>φ</sub>(V) from V; が発行されたとする．ここに φ は探索条件である．削除の定義は V←V－σ<sub>φ</sub>(V) なので，この削除を表す論理式は次の通りである．<br />
∀t(t∈σ<sub>φ</sub>(V)⇒¬V(t))<br />
つまり，φ(t)=真となる V のタップル，つまり σ<sub>φ</sub>(V) のタップル，は（削除後は）V のタップルであってはいけないと言っている．<br />
一方，V=R∪S なので t∈σ<sub>φ</sub>(V)⇔t∈σ<sub>φ</sub>(R∪S)⇔t∈σ<sub>φ</sub>(R)∨t∈σ<sub>φ</sub>(S) である．したがって，<br />
t∉σ<sub>φ</sub>(V)⇔t∉σ<sub>φ</sub>(R)∧t∉σ<sub>φ</sub>(S) である．<br />
つまり，「<b>d</b> を実現するためには，R から探索条件 φ を満たすタップルをすべて削除しかつ S からも探索条件 φ を満たすタップルをすべて削除することが必要かつ十分である」と言っている．このとき，(R－σ<sub>φ</sub>(R))∪(S－σ<sub>φ</sub>(S))=(R∪S)－(σ<sub>φ</sub>(R)∪σ<sub>φ</sub>(S)) =V－σ<sub>φ</sub>(R∪S)=V－σ<sub>φ</sub>(V) が成り立つ．したがって，<b>d</b> を実現するための必要かつ十分条件は <b>d</b> を T(<b>d</b>) に変換することである．<br />
T(<b>d</b>)=begin; deleteσ<sub>φ</sub>(R) from R; deleteσ<sub>φ</sub>(S) from S; end;<br />
このことは，特定のR，S，φ に依存することなく成立するので，「和ビューは削除可能である」という命題がスキーマレベルで成立する．なお，T が定義 1 の条件 (a)～(c) を満たしていることはその定義から明らかである．</p>
<p><b>【例題１】</b>R(A, B), S(A, B), dom(A)=dom(B)={i|Integer(i)}, R={(1, 1), (2, 2)}, S={(2, 2), (3, 3)}, V=R∪S={(1, 1), (2, 2), (3, 3)}, φ=(A=2∧B=2) とする．このとき，σ<sub>φ</sub>(V)={(2, 2)} なので，V－σ<sub>φ</sub>(V)={(1, 1), (3, 3)} であり, 一方，R－σ<sub>φ</sub>(R)={(1, 1)}, S－σ<sub>φ</sub>(S)={(3, 3)} なので (R－σ<sub>φ</sub>(R))∪(S－σ<sub>φ</sub>(S))= {(1, 1)}∪{(3, 3)}={(1, 1), (3, 3)} となり，<b>d</b>=deleteσ<sub>φ</sub>(V) from V; が T(<b>d</b>)=begin; deleteσ<sub>φ</sub>(R) from R; deleteσ<sub>φ</sub>(S) from S; end; により実現できていることが確認できる．</p>
<p style="margin-top: -00px;"><strong>【2】和ビューは挿入不可能</strong></p>
<p style="margin-top: -12px;"> 和ビューは挿入不可能であるインスタンスレベルの反例を一つ示せばよい．たとえば，和両立な 2 つのリレーションを R(A, B)=∅, S(A, B)= ∅（ここに ∅ は空集合を表す）とすると，V=R∪S=∅ である．このとき，V に対する挿入 <b>i</b>=insert {(1, 1)} into V; が発行されたとする．挿入の定義は V←V∪{(1, 1)} なので，この挿入を表す論理式は次の通りである．<br />
∀t(t∈{(1, 1)}⇒V(t))<br />
一方，∀t(V(t)⇔R(t)∨S(t)) なので，<b>i</b> を実現する変換 T は 3 つ存在することが分かる．<br />
T<sub>1</sub>(<b>i</b>)= insert {(1, 1)} into R;<br />
T<sub>2</sub>(<b>i</b>)= insert {(1, 1)} into S;<br />
T<sub>3</sub>(<b>i</b>)= begin; insert {(1, 1)} into R; insert {(1, 1)} into S; end;<br />
しかしながら，これら 3 つの変換の存在は変換の一意性に反するので，定義 1 より V への挿入 <b>i</b> は変換不可能である．したがって，「和ビューは挿入不可能である」という命題がスキーマレベルで成立する．</p>
<p>したがって，「和ビューは書換不可能である」という命題がスキーマレベルで成立する．</p>
<p style="margin-top: -00px;"><strong>【3】差ビューは削除不可能</strong></p>
<p style="margin-top: -12px;"> 差ビューは削除不可能であるインスタンスレベルの反例を一つ示せばよい．たとえば，和両立な 2 つのリレーションを R(A, B)={(1, 1), (2, 2)}, S(A, B)={(1, 1), (3, 3)} とする．このとき，差ビュー V=R－S={(2, 2)} である．<br />
そこで，V に対する削除 <b>d</b>=deleteσ<sub>φ</sub>(V) from V; ここに φ=(A=2∧B=2)，つまり σ<sub>φ</sub>(V)= {(2, 2)}，が発行されたとする．<br />
削除の定義は V←V－σ<sub>φ</sub>(V) なので，この削除を表す論理式は次の通りである．<br />
∀t(t∈σ<sub>φ</sub>(V)⇒¬V(t))<br />
一方，¬V(t)⇔t∉V⇔t∉(R－S)⇔t∉R∨t∈S である．<br />
したがって，<b>d</b> を実現する変換 T が 3 つ存在することが分かる．<br />
T<sub>1</sub>(<b>d</b>)= delete {(2, 2)} from R;<br />
T<sub>2</sub>(<b>d</b>)= insert {(2, 2)} into S;<br />
T<sub>3</sub>(<b>d</b>)= begin; delete {(2, 2)} from R; insert {(2, 2)} into S; end;<br />
この 3 つの変換の存在は変換の一意性に反するので，定義 1 より V への削除 <b>d</b> は変換不可能である．したがって，「差ビューは削除不可能である」という命題がスキーマレベルで成立する．</p>
<p style="margin-top: -00px;"><strong>【4】差ビューは挿入可能</strong></p>
<p style="margin-top: -12px;"> R と S を和両立なリレーション，V=R－S を差ビューとする．<br />
V に対して挿入 <b>i</b>=insert X into V;　ここに X⊆dom(<span style="font-style: italic;"><b>R</b></span>)，が発行されたとする．挿入の定義は V←V∪X なので，この挿入を表す論理式は次の通りである．<br />
∀t(X(t)⇒V(t))<br />
一方，差ビューの定義より，∀t(V(t)⇔R(t)∧¬S(t)) である．<br />
したがって，挿入に関して次に示す論理式を得る．<br />
∀t(X(t)⇒R(t)∧¬S(t))<br />
つまり，「V に X を挿入するためには，R に X を挿入し S から X を削除しなさい」と言っている．このとき，(R∪X)－(S－X)=(R－S)∪X=V∪X が成り立つ．したがって，<b>i</b> を実現するための必要かつ十分条件は <b>i</b> を T(<b>i</b>) に変換することである．<br />
T(<b>i</b>)=begin; insert X into R; delete X from S; end;<br />
このことは，特定の R，S，X に依存することなく成立するので，「差ビューは挿入可能である」という命題がスキーマレベルで成立する．なお，T が定義 1 の条件 (a)～(c) を満たしていることはその定義から明らかである．</p>
<p>したがって，「差ビューは書換不可能である」という命題がスキーマレベルで成立する．</p>
<p style="margin-top: -00px;"><strong>【5】共通ビューは削除不可能</strong></p>
<p> 和両立なリレーション R と S の共通は R∩S=R－(R－S) であるので，一般的ビューとなる「差ビューは削除不可能である」という命題がスキーマレベルで成立しているので，「共通ビューは削除不可能である」という命題がスキーマレベルで成立する．</p>
<p style="margin-top: -00px;"><strong>【6】共通ビューは挿入可能</strong></p>
<p> R と S を和両立なリレーション，V=R∩S を共通ビューとするとき，それは次のように定義される．<br />
∀t(V(t)⇔(R(t)∧S(t)))<br />
そこで，V に対して挿入 <b>i</b>=insert X into V; ここに X⊆dom(R) が発行されたとする．挿入の定義はV←V∪Xなので，この挿入を表す論理式は次の通りである．<br />
∀t(X(t)⇒V(t))<br />
したがって，挿入に関して次に示す論理式を得る．<br />
∀t(X(t)⇒(R(t)∧S(t)))<br />
つまり，「V に X を挿入するためには，R に X を挿入しかつ S に X を挿入しなさい」と言っている．このとき，(R∪X)∩(S∪X)=(R∩S)∪X=V∪X である．したがって，<b>i</b> を実現するための必要かつ十分条件は <b>i</b> を T(<b>i</b>) に変換することである．<br />
T(<b>i</b>)=begin; insert X into R; insert X into S; end;<br />
このことは，特定の R，S，X に依存することなく成立するので，「共通ビューは挿入可能である」という命題がスキーマレベルで成立する．なお，T が定義 1 の条件 (a)～(c) を満たしていることはその定義から明らかである．</p>
<p>したがって，「共通ビューは書換不可能である」という命題がスキーマレベルで成立する．</p>
<p style="margin-top: -00px;"><strong>【7】直積ビューは削除不可能</strong></p>
<p> インスタンスレベルでの反例を一つ示す．2 つのリレーションを R(A, B)={(1, 1)}, S(C, D)={(1, 1)}，直積ビューを V=R×S={(1, 1, 1, 1)} とする．このとき，V に対して削除 <b>d</b>=delete σ<sub>φ</sub>(V) from V; ここに φ=(A=1∧B=1∧C=1∧D=1) が発行されたとする．<br />
削除の定義は V←V－σ<sub>φ</sub>(V) なので，この削除を表す論理式は次の通りである．<br />
∀t(t∈σ<sub>φ</sub>(V)⇒¬V(t))<br />
V=R×S={u*v|u∈R∧v∈S} なので，¬V(t)⇔t∉(R×S)⇔u∉R∨v∉S，ここに t=u*v とする，である．<br />
一方，σ<sub>φ</sub>(V)⇔σ<sub>φ</sub>(R×S)⇔σ<sub>φ1</sub>(R)×σ<sub>φ2</sub>(S)，ここに φ はΩ<sub>R×S</sub>=Ω<sub>R</sub>×Ω<sub>S</sub> 上の選択条件で，φ<sub>1</sub>=φ|Ω<sub>r</sub> と φ<sub>2</sub>=φ|Ω<sub>S</sub> はそれぞれ φ を Ω<sub>R</sub> とΩ<sub>S</sub> 上に制限した探索条件を表す．この例では φ<sub>1</sub>=(A=1∧B=1)，φ<sub>2</sub>=(C=1∧D=1) である．<br />
したがって，<b>d</b> を実現する変換 T が 3 つ存在することが分かる．<br />
T<sub>1</sub>(<b>d</b>)= delete σ<sub>φ1</sub>(R) from R; ここに φ<sub>1</sub>=(A=1∧B=1)<br />
T<sub>2</sub>(<b>d</b>)= delete σ<sub>φ2</sub>(S) from S; ここに φ<sub>2</sub>=(C=1∧D=1)<br />
T<sub>3</sub>(<b>d</b>)= begin; delete σ<sub>φ1</sub>(R) from R; delete σ<sub>φ2</sub>(S) from S; end;<br />
これは，変換の一意性に反するので，定義 1 より V への削除 <b>d</b> は変換不可能である．したがって，「直積ビューは削除不可能である」という命題がスキーマレベルで成立する．</p>
<p style="margin-top: -00px;"><strong>【8】直積ビューは挿入不可能</strong></p>
<p> インスタンスレベルで反例を一つ示す．2 つのリレーションを R(A, B)={(1, 1)}, S(C, D)={(1, 1)} とする．このとき，V=R×S={(1, 1, 1, 1)} を直積ビューとする．このとき，V に対して挿入 <b>i</b>=insert {(2, 2, 2, 2) } into V; が発行されたとする．このとき，<b>i</b> を実現するためには R に (2, 2) を挿入し S には (2, 2) を挿入しないといけない．しかしながら，それにより V={(1, 1, 1, 1), (2, 2, 2, 2), (1, 1, 2, 2), (2, 2, 1, 1) } となり副作用が生じる．したがって，「直積ビューは挿入不可能である」という命題がスキーマレベルで成立する．</p>
<p>したがって，「直積ビューは書換不可能である」という命題がスキーマレベルで成立する．</p>
<p style="margin-top: -00px;"><strong>【9】射影ビューは削除可能</strong></p>
<p> リレーション R の属性集合 X（X⊆Ω<sub>R</sub>）上の射影ビューを V=π<sub>X</sub>(R) とする．V に対して削除 <b>d</b>=delete σ<sub>φ</sub>(V) from V; が発行されたとする． ここに選択条件 φ は dom(V)（=dom(X)）の元を引数とする述語であるが，X⊆Ω<sub>R</sub> なのでdom(R) の元を引数とする述語ともなっている．<br />
このとき，σ<sub>φ</sub>(V)=σ<sub>φ</sub>(π<sub>X</sub>(R))= π<sub>X</sub>(σ<sub>φ</sub>(R)) である．<br />
<b>d</b> の定義は V←V－σ<sub>φ</sub>(V) であるので，V－σ<sub>φ</sub>(V)= π<sub>X</sub>(R)－π<sub>X</sub>(σ<sub>φ</sub>(R))=π<sub>X</sub>(R－σ<sub>φ</sub>(R)) となる．<br />
つまり，<b>d</b> を実現するためには，「R から σ<sub>φ</sub>(R) を削除して，その結果を X 上で射影しなさい」と言っている．このとき，φ は dom(R) の元を引数とする述語ともなっているので，<br />
π<sub>X</sub>(R－σ<sub>φ</sub>(R))=π<sub>X</sub>(R)－π<sub>X</sub> (σ<sub>φ</sub>(R))=π<sub>X</sub>(R)－σ<sub>φ</sub>(π<sub>X</sub>(R))=V－σ<sub>φ</sub>(V) が成立する．<br />
したがって，<b>d</b> が変換可能であるための必要かつ十分条件は <b>d</b> を T(<b>d</b>) に変換することである．<br />
T(<b>d</b>)=deleteσ<sub>φ</sub>(R) from R;<br />
このことは R と X と φ がどのような場合でも成り立つ．よって，「射影ビューは削除可能である」という命題はスキーマレベルで成立する．なお，T が定義 1 の条件 (a)～(c) を満たしていることはその定義から明らかである．</p>
<p><b>【例題２】</b>R(A, B)={(1, 1), (1, 2), (2, 1)}, V=π<sub>{B}</sub>(R)={(1), (2)} とし, V に対して削除 <b>d</b>=delete <sub>σB=1∨B=3</sub>(V) from V; が発行されたとする．T(<b>d</b>)=delete <sub>σB=1∨B=3</sub>(R) from R; に変換されるが，T(<b>d</b>) により B=1 の R のタップル (1, 1) と (2, 1) は R から削除される．B=3 のタップルは R に存在しないので R から削除されるタップルはない．したがって，R={(1, 2)} となるから，π<sub>{B}</sub>(R)={(2)}と 所望の結果となっている．</p>
<p style="margin-top: -00px;"><strong>【10】射影ビューはキー保存ならば挿入可能</strong><br />
リレーション R の属性集合 X⊆Ω<sub>R</sub> 上の射影ビューを V=π<sub>X</sub>(R) とするとき，射影ビュー V が<b>キー保存</b>（key preservation）であるとは，X がリレーション R の主キー K を含むときをいう．<br />
そこで，リレーション R の属性集合 X 上の射影ビューを V=π<sub>X</sub>(R) とすると，V の定義から次が成立する．<br />
∀u(V(u)⇔∃t(R(t)∧u=t[X]))<br />
V に対して挿入 <b>i</b>=insert W into V; ここに W⊆dom(V) が発行されたとする．この挿入を表す論理式は次の通りである．<br />
∀v(W(v)⇒V(v))<br />
したがって，次が成立する．<br />
∀v(W(v)⇒∃t(R(t)∧v=t[X]))<br />
このとき，挿入 <b>i</b>=insert W into V; の R への変換 T を次のように定義する．<br />
T(<b>i</b>)=insert <ruby>W<rt style="background-color: white;">～</rt></ruby> into R;<br />
ここに <ruby>W<rt style="background-color: white;">～</rt></ruby> は W から次のように定義されるタップル <ruby>w<rt style="background-color: white;">~</rt></ruby> の集合で，w∈W とした時，タップル <ruby>w<rt style="background-color: white;">~</rt></ruby> は次のように定義される．<br />
<ruby>w<rt style="background-color: white;">~</rt></ruby>[X]=w∧<ruby>w<rt style="background-color: white;">~</rt></ruby>[Ω<sub>R</sub>－X]=(null, null, <sub>…</sub>, null)<br />
さて，射影ビュー V がキー保存であるとすると，K を R の主キーとしたとき，K⊆X であるので，∀w, w’(W(w)∧W(w’)∧(w[K]≠w’[K]⇒w≠w’))が成立する．加えて，K は（候補キーではなく）主キーなので，キー制約からその属性が null をとることはないから，W と <ruby>W<rt style="background-color: white;">～</rt></ruby> の間には w<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2194.png" alt="↔" class="wp-smiley" style="height: 1em; max-height: 1em;" /><ruby>w<rt style="background-color: white;">~</rt></ruby> という 1 対 1 の対応が成立する．<br />
このとき，π<sub>X</sub>(R∪<ruby>W<rt style="background-color: white;">～</rt></ruby>)=π<sub>X</sub>(R)∪π<sub>X</sub>(<ruby>W<rt style="background-color: white;">～</rt></ruby>)=π<sub>X</sub>(R)∪W=V∪W が成立するので，<b>i</b> を実現するための必要かつ十分条件は <b>i</b> を T(<b>i</b>) に変換することであることが分かる．<br />
T(<b>i</b>)=insert <ruby>W<rt style="background-color: white;">～</rt></ruby> into R;<br />
したがって，「射影ビューはキー保存であれば挿入可能である」という命題がスキーマレベルで成立する．なお，T が定義 1 の条件 (a)～(c) を満たしていることはその定義から明らかである．</p>
<p>したがって，「射影ビューはキー保存ならば書換可能である」という命題がスキーマレベルで成立する．</p>
<p>なお，「キー保存」という条件自体は属性集合 X が主キー K を含んでいるかどうかという判定なのでスキーマレベルの検証であるので，定義 1 の条件 (a)～(c) をクリアして「射影ビューはキー保存ならば挿入可能である」という命題はスキーマレベルで成立することとなった．<br />
ただし，変換可能ならば基底リレーション R に <ruby>W<rt style="background-color: white;">～</rt></ruby> が挿入されることになるが，その挿入が R のキー制約に抵触するのかしないのかのチェックが必ず必要となってくることに注意したい．</p>
<p><b>【例題３】</b>R(A, B)={(1, 1), (2, 2), (3, 3)}, V=π<sub>{A}</sub>(R)={(1), (2), (3)}, <b>i</b>=insert {(4)} into V; が発行されたとする．<b>i</b> の変換 T(i)= insert {(4, null)} into R; とする．その結果，R(<u>A</u>, B)={(1, 1), (2, 2), (3, 3), (4, null)} となり，改めて π<sub>{A}</sub>(R)= {(1), (2), (3), (4)} となりなって，所望の挿入が実現していることがわかる．</p>
<p style="margin-top: -00px;"><strong>【11】選択ビューは削除可能</strong><br />
リレーション R の選択ビューを V=σ<sub>φ</sub>(R) とする．V に対して削除 <b>d</b>=deleteσ<sub>ψ</sub>(V) from V; が発行されたとする．<b>d</b> の定義は V←V－σ<sub>φ</sub>(V) であるが，V－σ<sub>φ</sub>(V)=σ<sub>φ</sub>(R)－σ<sub>ψ</sub>(σ<sub>φ</sub>(R))=σ<sub>φ</sub>(R)－σ<sub>φ</sub>(σ<sub>ψ</sub>(R))=σ<sub>φ</sub>(R－σ<sub>ψ</sub>(R)) となる．<br />
つまり，<b>d</b> を実現するためには，「R から σ<sub>ψ</sub>(R) を削除して，その結果に φ を施しなさい」，つまり，<b>d</b> を T(<b>d</b>) に変換しなさいと言っている．<br />
T(<b>d</b>)=deleteσ<sub>ψ</sub>(R) from R;<br />
このとき，上記のごとく σ<sub>φ</sub> (R－σ<sub>ψ</sub>(R))= V－σ<sub>φ</sub>(V) であるので，この変換は <b>d</b> が変換可能であるための必要かつ十分条件になっている．この性質は R と φ と ψ がどのような場合でも成り立つので，「選択ビューは削除可能である」という命題がスキーマレベルで成立する．なお，T が定義 1 の条件 (a)～(c) を満たしていることはその定義から明らかである．</p>
<p><b>【例題４】</b>社員(社員番号，給与)={(1, 10), (2, 20), (3, 30)} を実リレーション，ビューを貧乏社員=σ<sub>給与≦20</sub>(社員)={(1, 10), (2, 20)} とし，削除 <b>d</b>=delete σ<sub>給与≧10 </sub>(貧乏社員) from 貧乏社員; が発行されたとする．<b>d</b> は変換可能で次の通りである．<br />
T(<b>d</b>)=deleteσ<sub>給与≧10∧給与≦20</sub>(社員) from 社員;</p>
<p style="margin-top: -00px;"><strong>【12】選択ビューは挿入可能</strong><br />
リレーション R の選択ビューを V=σ<sub>φ</sub>(R)とする．V に対して挿入 <b>i</b>=insert X into V; が発行されたとする．<b>i</b> の定義は V←V∪X なので，この挿入を表す論理式は次の通りである．<br />
∀t(X(t)⇒V(t))<br />
一方，選択ビューの定義より，∀t(V(t)⇔R(t)∧<sub>φ</sub>(t)) である．したがって，次に示す論理式を得る．<br />
∀t(X(t)⇒(R(t)∧φ(t)))<br />
ところで，X⊆dom(V)=σ<sub>φ</sub>(dom(R)) なので，∀t(X(t)⇒<sub>φ</sub>(t))，つまり ∀t(t∉X(t)∨<sub>φ</sub>(t)) が成立している．したがって，<br />
∀t(X(t)⇒(R(t)∧φ(t)))⇔∀t(t∉X(t)∨(R(t)∧<sub>φ</sub>(t)))⇔∀t((t∉X(t)∨(R(t))∧(t∉X(t)∨<sub>φ</sub>(t)))⇔∀t(t∉X(t)∨(R(t)) ⇔∀t(X(t)⇒R(t)) となる．<br />
つまり，「<b>i</b>を実現するためには，R に X を挿入しなさい」と言っている．このとき，X⊆σ<sub>φ</sub>(dom(R))なので σ<sub>φ</sub>(X)=X となり，σ<sub>φ</sub>(R∪X) =σ<sub>φ</sub>(R)∪σ<sub>φ</sub>(X)=V∪X である．したがって，<b>i</b> を実現するための必要かつ十分条件は <b>i</b>を T(<b>i</b>) に変換することである．<br />
T(<b>i</b>)= insert X into R;<br />
このことは，特定の R，φ，X に依存することなく成立するので，「選択ビューは挿入可能」であるという命題がスキーマレベルで成立する．なお，T が定義 1 の条件 (a)～(c) を満たしていることはその定義から明らかである．</p>
<p>したがって，「選択ビューは書換可能である」という命題がスキーマレベルで成立する．</p>
<p><b>【例題５】</b>社員(社員番号，給与)={(1, 10), (2, 20), (3, 30)} を実リレーション，貧乏社員=σ<sub>給与≦20</sub>(社員)={(1, 10), (2, 20)} をビューとし，挿入 <b>i</b>=insert {(100, 10), (101, 15)} into 貧乏社員; が発行されたとする．<b>i</b> は変換可能で，その変換は次の通りである．<br />
T(<b>i</b>)=insert {(100, 10), (101, 15)} into社員;</p>
<p style="margin-top: -00px;"><strong>【13】結合ビューや商ビューは共に削除不可能，挿入不可能，書換不可能</strong><br />
これらを定義するためには直積演算が使われるので，それらの更新可能性に則して，共にスキーマレベルで削除不可能，挿入不可能，書換不可能である．</p>
<p style="margin-top: -00px;"><strong>3.3 一般的リレーショナルビューの更新可能性（スキーマレベル）</strong></p>
<p style="margin-top: -12px;"> 一般にリレーショナルビューはリレーショナル代数演算を「再帰的」に適用して定義されます．このようなビューを「一般的リレーショナルビュー」といいますが，そのようなビューの更新可能性はそのビュー定義に使われたリレーショナル代数演算で定義される中間ビューの更新可能性に依存することになります（このことは，後述する一般的バッグビューについても同様です）．<br />
ここではリレーショナルデータベースで最も典型的であるといわれている連言問合せ（conjunctive query）で定義されるビューを例として説明します．<br />
<b>【例題６】</b>（一般的リレーショナルビューの更新可能性判定）<br />
R(<u>A</u>, B, C)，S(<u>B</u>, D) をリレーション（アンダーバーは主キーを表す），V=π<sub>{R.A, R.B}</sub>(σ<sub>C=c</sub>(R)<br />
⨝<sub>R.B=S.B</sub>σ<sub>D=d</sub>(S)) を連言問合せビュー定義とする．このビューの定義木（＝構文解析木）を図 2 に示す．<br />
このとき，V へ更新 <b>u</b> が発行されると，V=π<sub>{R.A, R.B}</sub> 中間ビュー<sub>1</sub> なので，射影ビューに対する <b>u</b> の変換可能性をチェックする．表 3 を参照すると（table lookup），<b>u</b> が削除ならば変換可能，<b>u</b> が挿入ならばキー保存という条件付きで変換可能であることを知る．ともに，（挿入には条件が付くが）変換可能なので，V への更新 <b>u</b> の変換可能性は，中間ビュー<sub>1</sub> に対する更新の変換可能性のチェック結果に依ることとなる．ところが，中間ビュー<sub>1</sub> は結合ビューである．そこで，再び表 3 を参照すると，結合ビューは削除不可能，挿入不可能，書換不可能であることを知る．したがって，<b>u</b> は押し並べて変換不可能であることを知る．この時点で，ビュー V への更新 <b>u</b> が変換不可能であると判定される．</p>
<p>このように，一般的リレーショナルビューの更新可能性はそのビューの定義木をトップダウンに，たとえば幅優先探索（breadth first）で走査しながら，ノードごとでその更新可能性を表 3「基本的リレーショナルビューの更新可能性（スキーマレベル）」に参照していけば，その更新可能性をスキーマレベルで検証することができます．</p>
<div style="text-align: center;"><img decoding="async" style="margin-top: -08px; width: 380px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2023/03/viewsupport-figure22.png" alt="図2　連言問合せビューVの定義木" /></div>
<p>&nbsp;</p>
<h4>4. バッグビューの更新可能性（スキーマレベル）</h4>
<p style="margin-top: -12px;"><strong>4.1 バッグビューの定義</strong></p>
<p style="margin-top: -12px;"><strong>4.1.1 バッグ</strong></p>
<p style="margin-top: -12px;"> SQL のテーブルはリレーションと異なりタップルの重複出現を許します．タップルの重複出現を許すことで問合せの結果から重複タップルを削除する手間が省けるので（つまりソートや突合せなどの処理を省ける），問合せ処理がリレーションの場合に比べて高速になります．また，タップルの重複出現を許容することで集約関数を駆使できるという利点もあります．反面，SQL のテーブルを格納しておくためにはリレーションに比べて余計に記憶領域を必要とすることは明らかです．<br />
さて，一般に元（element）の重複出現を許す元の集まりを<b>マルチ集合</b>（multiset）あるいは<b>バッグ</b>（bag）といいます．数学ではマルチ集合，SQL ではバッグを用いることが多いので本稿ではバッグとします．タップルの重複出現を許さないリレーションとそれを許すバッグではデータの表現・操作・管理などで違いを生じますが，それはリレーショナルデータモデルは集合意味論（set semantics）に立脚し，SQL は<b>バッグ意味論</b>（bag semantics）に立脚しているからだと表現します．リレーショナルデータモデルでリレーショナル代数（relational algebra）が定義されたと同様に，バッグに対しては<b>バッグ代数</b>（bag algebra）が定義されます [8]．リレーショナル代数表現と同様に<b>バッグ代数表現</b>（bag algebra expression）を定義でき，リレーショナルビューがリレーショナル代数表現で定義されたのと同様に，バッグビュー（bag view）はバッグ代数表現として定義されます．まずはバッグを定義することから始めます．<br />
<b>【定義５】</b>（バッグ）</p>
<p style="margin-top: -20px;"> バッグ R(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, A<sub>n</sub>) は<b>潜在リレーション</b>（concealed relation）<u>R</u>(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, A<sub>n</sub>)と重複度関数 m: dom(<u>R</u>)→<span style="font-style: italic;"><b>Z</b></span><sup>+</sup>（<span style="font-style: italic;"><b>Z</b></span><sup>+</sup> は正の整数）の組である．ここに dom(<u>R</u>)=dom(A<sub>1</sub>)×dom(A<sub>2</sub>)×・・・×dom(A<sub>n</sub>)とする．</p>
<p>つまり，バッグは R(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, A<sub>n</sub>)=(<u>R</u>(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, An), <span style="font-style: italic;">m</span>) と定義されるということです．たとえば，バッグ R(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, A<sub>n</sub>) の潜在リレーションを <u>R</u>(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, A<sub>n</sub>)= {t<sub>1</sub>, t<sub>2</sub>, <sub>&#8230;</sub>, t<sub>p</sub>}，重複度関数を <span style="font-style: italic;">m</span>(t<sub>i</sub>)=k<sub>i</sub>（k<sub>i</sub>≧1）とするとき，バッグ R(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, A<sub>n</sub>)={t<sub>1</sub>(k<sub>1</sub>), t<sub>2</sub>(k<sub>2</sub>), <sub>&#8230;</sub>, t<sub>p</sub>(k<sub>p</sub>)} となります．ここに t<sub>i</sub>(k<sub>i</sub>) はタップル t<sub>i</sub> が丁度 k<sub>i</sub> 本あることを表すための記法で，k<sub>i</sub> はバッグ R 中に生起するタップル t<sub>i</sub> の<b>重複度</b>（multiplicity）です．t(k)∈R で重複度 k のタップル t がバッグ R の元であることを表すことにすると，t(k)∈R⇔t∈<u>R</u>∧k=<span style="font-style: italic;">m</span>(t) ということです．バッグ R(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, A<sub>n</sub>) ={t<sub>1</sub>(k<sub>1</sub>), t<sub>2</sub>(k<sub>2</sub>), <sub>&#8230;</sub>, t<sub>p</sub>(k<sub>p</sub>)} は (∀i=1,<sub>..</sub>,p)(k<sub>i</sub>=1) のときリレーション(＝集合)です．k<sub>i</sub>=1 のとき，t<sub>i</sub>(1) と書かずに，単に t<sub>i</sub> と書くことも多く，また t<sub>i</sub>(0) は t<sub>i</sub> が存在していないことを意味します．<br />
バッグ R(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, A<sub>n</sub>) のドメイン dom(R) は次のように定義されます．dom(R)=dom(<u>R</u>)×<br />
{k|PositiveInteger(k)}=dom(A<sub>1</sub>)×dom(A<sub>2</sub>)×・・・×dom(A<sub>n</sub>)×{k|PositiveInteger(k)}，ここに<br />
PositiveInteger(k) は k が正整数であるとき真となる命題です．ちなみに，(a<sub>1</sub>, a<sub>2</sub>, <sub>…</sub>, a<sub>n</sub>, k)∈<br />
dom(R)⇔(a<sub>1</sub>, a<sub>2</sub>, <sub>…</sub>, a<sub>n</sub>)(k)∈R と解釈します．</p>
<h4 style="margin-top: -00px;">■ 潜在キーと潜在キー制約</h4>
<p>バッグはリレーションと違って重複タップルの出現を許すので，バッグの全属性の組をとってきてもタップルの一意識別能力はなく，したがってリレーションのキー（key）に相当する概念はありません．しかしながら，バッグ　R(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, A<sub>n</sub>) を定義するために潜在リレーション <u>R</u>(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, A<sub>n</sub>) を導入しましたが，<u>R</u> は正真正銘のリレーションなので，<u>R</u> にはキーが存在します．そこで，<u>R</u> のキーを K とし，K をバッグ R の<b>潜在キー</b>（concealed key）と呼ぶことにします．リレーションの主キーと候補キーに対応して潜在主キーと潜在候補キーが定義できます．<br />
潜在キーは一見無秩序に重複タップルの出現を許しているように見えるバッグに「秩序」をもたらしていることになります．換言すれば，潜在キーが K であるバッグ R={t<sub>1</sub>(k<sub>1</sub>), t<sub>2</sub>(k<sub>2</sub>), <sub>&#8230;</sub>, t<sub>p</sub>(k<sub>p</sub>)} に重複行除去（δ）を施して得られるリレーション δ(R)={t<sub>1</sub>, t<sub>2</sub>, <sub>&#8230;</sub>, t<sub>p</sub>} のキーは K なので次が成り立ちます．<br />
∀t, t’(t∈δ(R)∧t’∈δ(R)∧t[K]=t’[K]⇒t=t’)<br />
つまり，バッグで重複して出現しているタップル同士のキー値が等しいならばタップルとしては同一だということになります．マルチ集合論では「重複元の識別不可能性」という原理が知られていますが [9]，上記はその原理のデータベース的解釈といえます．<br />
したがって，たとえば，潜在リレーションを<u>社員</u>(<u>社員番号</u>，氏名，所属，給与)，ここに社員番号が主キー，とするバッグ社員(社員番号，氏名，所属，給与) に (007, 山田太郎，K55，50) というタップルは何本出現しても構いませんが，たとえば，(007, 佐藤一郎，K41，50) というタップルがバッグ社員に (007, 山田太郎，K55，50) と共に出現するということはない，ということです．この制約を<b>潜在キー制約</b>（concealed key constraint）と呼ぶことにしますが，これはリレーションでのキー制約に相当する概念で，バッグあるいはバッグビュー更新時の一貫性制約の一つになります．</p>
<p style="margin-top: -00px;"><strong>4.1.2 バッグ代数</strong></p>
<p style="margin-top: -12px;"> バッグのデータ操作言語であるバッグ代数を定義しますが，以下に示す演算からなります．<br />
<b>【定義６】</b>（バッグ代数）</p>
<p style="margin-top: -20px;"> 一般に，R(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, A<sub>n</sub>)={t<sub>1</sub>(k<sub>1</sub>), t<sub>2</sub>(k<sub>2</sub>), <sub>&#8230;</sub>, t<sub>p</sub>(k<sub>p</sub>)} とS(B<sub>1</sub>, B<sub>2</sub>, <sub>&#8230;</sub>, B<sub>m</sub>)={u<sub>1</sub>(ℓ<sub>1</sub>), u<sub>2</sub>(ℓ<sub>2</sub>), <sub>&#8230;</sub>, u<sub>q</sub>(ℓ<sub>q</sub>)} をバッグとするとき，バッグ代数は次に示す演算子からなる．加法和（additive union），モーナス（monus），共通を定義するにあたり R と S は和両立とする．<br />
● 重複行除去（δ）<br />
● 加法和（⨄），モーナス（∸），共通（∩）<br />
● 直積（×）<br />
● 射影（π<sub>X</sub>(R)，ここに Ｘ⊆Ω<sub>R</sub>）<br />
● 選択（σ<sub>φ</sub> (R)，ここに φ は dom(R) 上の選択条件）<br />
● <span style="font-style: italic;">θ</span>-結合（R⨝<sub>AiθBj</sub>S，ここに R.A<sub>i</sub> と S.B<sub>j</sub> は θ-比較可能）</p>
<p>これらの演算子の定義を<b>表 4</b> で与えます．</p>
<p><img decoding="async" style="margin-top: -08px; width: 726px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2023/03/viewsupport-chart44.png" alt="表4　バッグ代数演算" align="middle" /></p>
<p>補足すれば，バッグ代数に特有な演算として，重複行削除演算（δ），モーナス（∸），加法和（⨄）をあげられます．モーナス（∸）はリレーショナル代数演算の差（－）に対応した演算ですが，タップルの重複度を考慮しています．マルチ集合論では和には加法和とは別に最大和（maximum union，∪）を定義することもできます．その定義は R∪S={t(k)|∃t(k<sub>i</sub>)∈R∧∃t(ℓ<sub>j</sub>)∈S∧k= max(k<sub>i</sub>, ℓ<sub>j</sub>)} で，リレーショナル代数の和（∪）はバッグ代数の最大和と両立する演算です．しかしながら，<br />
一般にタップルの重複出現を許す SQL のテーブルの UNION ALLを念頭においている和は加法和です．<br />
SQL との対応付けをすると，重複行削除演算は SQL の SELECT DISTINCT * FROM R に相当します．加法和，モーナス，共通はそれぞれ SQL の UNION ALL，EXCEPT ALL，INTERSECT ALL に相当します．直積，選択，射影，<span style="font-style: italic;">θ</span>-結合の演算結果から重複行は削除されず SQL の SELECT ALL の意味を持っています．上記の演算はお互いに独立ではなく，たとえば，重複行除去，加法和，差，直積，射影，選択の 6 つの演算は互いに独立です．独立でない演算子を許容しているのはその有用性によります．<br />
なお，R, S をバッグ，ψ, φ を述語としたとき，次の性質が成り立ちます [8]．このような性質はバッグ代数で成り立つので，リレーショナル代数でも成り立ちます．<br />
● σ<sub>ψ∨φ</sub>(R)=σ<sub>ψ</sub>(R) ⨄σ<sub>φ</sub>(R)<br />
● σ<sub>ψ∧φ</sub>(R)=σ<sub>ψ</sub>(R)∩σ<sub>φ</sub>(R)<br />
● σ<sub>¬φ</sub>(R)=R∸σ<sub>φ</sub>(R)<br />
● δ(σ<sub>φ</sub>(R))=σ<sub>φ</sub>(δ(R))</p>
<p>バッグ代数でもバッグのタップルの属性が null をとることがありうるので，バッグ代数演算もリレーショナル代数の時と同じように（3.1.1 項），3 値論理に拡張されて，推量 <span style="font-style: italic;">θ</span>-選択や推量 <span style="font-style: italic;">θ</span>-結合が定義できます．</p>
<p style="margin-top: -00px;"><strong>4.1.3 バッグ代数表現としてのバッグビュー</strong></p>
<p style="margin-top: -20px;"> リレーショナルデータベースに対する問合せがリレーショナル代数表現として記述できたのと同様に，バッグデータベースに対する問合せはバッグ代数表現として記述できます．したがって，定義 4 でリレーショナルビューを定義したのと同様に，バッグビューはバッグ代数表現として次のように定義できます．データベースに格納されているバッグを実バッグといいます．<br />
<b>【定義７】</b>（バッグビュー）</p>
<p style="margin-top: -20px;"> (1)</p>
<p>実バッグはバッグビューである．</p>
<p style="margin-top: -20px;"> (2)</p>
<p>V をバッグビューとし，δを重複行除去とするとき，δ(V) はバッグビューである（重複行除去ビュー）．</p>
<p style="margin-top: -20px;"> (3)</p>
<p>V<sub>1</sub> と V<sub>2</sub> を和両立なバッグビューとするとき，それらの加法和 V<sub>1</sub>⨄V<sub>2</sub> はバッグビューである（加法和ビュー）．</p>
<p style="margin-top: -20px;"> (4)</p>
<p>V<sub>1</sub> と V<sub>2</sub> を和両立なバッグビューとするとき，それらのモーナス V<sub>1</sub>∸V<sub>2</sub> はバッグビューである（モーナスビュー）．</p>
<p style="margin-top: -20px;"> (5)</p>
<p>V<sub>1</sub> と V<sub>2</sub> をバッグビューとするとき，それらの直積 V<sub>1</sub>×V<sub>2</sub> はバッグビューである（バッグ直積ビュー）．</p>
<p style="margin-top: -20px;"> (6)</p>
<p>V をバッグビューとするとき，その射影 π<sub>X</sub>(V) はバッグビューである（バッグ射影ビュー）．</p>
<p style="margin-top: -20px;"> (7)</p>
<p>V をバッグビューとするとき，その選択 σ<sub>φ</sub>(V) はバッグビューである（バッグ選択ビュー）．</p>
<p style="margin-top: -20px;"> (8)</p>
<p>(1)～(6) で定義されるもののみがバッグビューである．</p>
<p>基本的バッグビューと一般的バッグビューという用語も基本的リレーショナルビューと一般的リレーショナルビューに準じて使用します．以下，特に混乱が生じないと考えられる場合にはバッグビューを単にビューと記すこともあります．</p>
<p style="margin-top: -00px;"><strong>4.2 バッグビューの更新</strong></p>
<p style="margin-top: -20px;"> バッグビュー V に対する削除や挿入に対する形式や考え方はリレーショナルビューに対する削除や挿入と基本的には同一ですが，削除では差に代わりモーナスが，挿入では和に代わり加法和がその定義に用いられるところが異なります．書換を削除と挿入の系列と定義することや注意点はリレーショナルビューに対する場合と同様です．<br />
削除（<b>d</b>）：deleteσ<sub>φ</sub>(V) from V; ここに φ は dom(V) の元を引数とする述語である．<br />
挿入（<b>i</b>）：insert X into V; ここに X⊆dom(V) とする．<br />
● 削除の定義は V←V∸σ<sub>φ</sub>(V) です．モーナスが使われているとことに注意します．<br />
● 挿入の定義は V←V⨄X です．加法和が使われているとことに注意します．</p>
<p>ここで，バッグビューのドメインについて補足をします．</p>
<h4 style="margin-top: -20px;">■ バッグビューのドメインについて</h4>
<p>4.1.1 項で，バッグ R(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, A<sub>n</sub>) のドメインは dom(R)=dom(A<sub>1</sub>)×dom(A<sub>2</sub>)×・・・×dom(A<sub>n</sub>)×{k|PositiveInteger(k)} と定義されました．バッグビューのドメインもその延長線上にありますが，（リレーショナルビューのときと同様に）ビュー定義が勘案されます．つまり，バッグビューを V(A<sub>1’</sub>, A<sub>2’</sub>, <sub>…</sub>, A<sub>r’</sub>) としたとき，V のドメインは一般には dom(V)=dom(A<sub>1’</sub>)×dom(A<sub>2’</sub>)×・・・×dom(A<sub>r’</sub>)×{k|PositiveInteger(k)} とはならず，ビュー定義を満たすその部分集合になります．幾つか例題で見ていくと次の通りです．<br />
まず，バッグ R(A<sub>1</sub>, A<sub>2</sub>, <sub>&#8230;</sub>, A<sub>n</sub>) の重複行削除ビュー V=δ(R) のドメインは dom(V)= dom(A<sub>1</sub>)×<br />
dom(A<sub>2</sub>)×・・・×dom(A<sub>n</sub>)×{1} です．R と S を和両立とするとき加法和ビュー V=R⨄S やモーナスビュー V=R∸S のドメインは dom(V)=dom(R)×{k|PositiveInteger(k)} です．バッグ R と S の直積ビュー V=R×S のドメインは dom(V)=dom(R)×dom(S)×{k|PositiveInteger(k)} です．バッグ R(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) の属性集合 X（⊆Ω<sub>R</sub>），ここに Ω<sub>R</sub>={A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>}，上の射影ビュー V=π<sub>X</sub>(R) のドメインは，X={A<sub>1’</sub>, A<sub>2’</sub>, <sub>…</sub>, A<sub>r’</sub>}，ここに 1≦1’≦2’≦…≦r’≦n，として dom(V)=dom(A<sub>1’</sub>)×dom(A<sub>2’</sub>)×･･･×dom(A<sub>r’</sub>)×{k|PositiveInteger(k)} となります．バッグ R(A, B) のバッグ選択ビューを V=σ<sub>B≦b</sub>(R) としたとき，dom(V)=dom(A)×σ<sub>B≦b</sub>(dom(B))×{k|PositiveInteger(k)} となります．バッグ R(A, B) と S(B,C) の等結合ビュー V(A, R.B, S.B, C)=R⨝<sub>R.B=S.B</sub>S のドメインは dom(V)=σ<sub>R.B=S.B</sub>(dom(A)×<br />
dom(R.B)×dom(S.B)×dom(C))×{k|PositiveInteger(k)} となります．このようにビューのドメインはいずれもビュー定義が勘案されて定義されます．なお，クライアントにはビューの定義を考慮したうえでそれに抵触しない挿入を発行しなければならないという負担がかかることはリレーショナルビューの場合と同じです．</p>
<p style="margin-top: -00px;"><strong>4.3 基本的バッグビューの更新可能性（スキーマレベル）</strong></p>
<p style="margin-top: -12px;"> リレーショナルビューが集合意味論に立脚し，バッグビューはバッグ意味論に立脚している点は異なりますが，ビューの更新可能性は定義 1 で与えた通りです．つまり，バッグビュー V への更新 <b>u</b> は，(a) 一意で，(b) 副作用がなく，(c) 余計な更新がない変換 T が存在するとき更新可能であること定義されます．ただ，上述のように，削除にはモーナスが，挿入には加法和が用いられるところが異なります．また，バッグにはそれを定義するための潜在リレーションが存在する点もバッグビューの更新可能性に影響を与えます．なお，本稿ではスキーマレベルでビューの更新可能性を論じているので，リレーショナルビューの場合と同様な理由で，定義 1 の条件 (d) は不問に付しています．</p>
<p>さて，基本的バッグビューの更新可能性（スキーマレベル）をリレーショナル代数の場合と同様なアプローチで解明していきますが，ここで大事なことは次の命題が成立することです．</p>
<p style="margin-top: -20px;">
<p>「リレーション（＝集合）はバッグの特殊な場合なので，バッグで成り立つ性質はリレーションでも成り立つが，リレーションで成り立つ性質が必ずしもバッグで成り立つとは限らない」</p>
<p>したがって，<b>表 3</b> で〇（更新可能）となっている場合でも，それはリレーショナルビューに対する結果なので，それに対応するバッグ代数でのビューの更新可能性がまた〇になるかどうかは分かりません．一方，表3で×（更新不可能）となっている性質がバッグビューで〇となることはないわけですから，バッグビューの更新可能性はリレーショナルビューのそれに比べて限定的となります．<br />
以下，<b>表 5</b> にバッグビューの更新可能性を検証した結果を示すと共に，その論拠を示します．</p>
<p><img decoding="async" style="margin-top: -08px; width: 726px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2023/03/viewsupport-chart555.png" alt="表5　基本的バッグビューの更新可能性（スキーマレベル）" align="middle" /></p>
<p style="margin-top: -00px;"><strong>【1】重複行削除ビューは削除可能</strong></p>
<p style="margin-top: -12px;"> 一般にバッグ R={t<sub>1</sub>(k<sub>1</sub>), t<sub>2</sub>(k<sub>2</sub>), <sub>&#8230;</sub>, t<sub>p</sub>(k<sub>p</sub>)} の重複行除去ビュー δ(R)={t<sub>1</sub>, t<sub>2</sub>, <sub>&#8230;</sub>, t<sub>p</sub>} に対して，削除 <b>d</b>=delete σ<sub>φ</sub>(δ(R)) from δ(R); が発行されたとする．<br />
そこで，σ<sub>φ</sub>(δ(R)) ={t<sub>1’</sub>, t<sub>2’</sub>, <sub>&#8230;</sub>, t<sub>q’</sub>}，1≦1’＜2’＜<sub>&#8230;</sub>＜q’≦pとするとき，削除 <b>d</b> を R への削除 T(<b>d</b>)=delete {t<sub>1’</sub>(k<sub>1’</sub>), t<sub>2’</sub>(k<sub>2’</sub>), <sub>&#8230;</sub>, t<sub>q’</sub>(k<sub>q’</sub>)} from R; 変換する．このとき，δ(R∸{t<sub>1’</sub>(k<sub>1’</sub>), t<sub>2’</sub>(k<sub>2’</sub>), <sub>&#8230;</sub>, t<sub>q’</sub>(k<sub>q’</sub>)})=δ(R) ∸{t<sub>1’</sub>, t<sub>2’</sub>, <sub>&#8230;</sub>, t<sub>q’</sub>}=δ(R)∸σ<sub>φ</sub>(δ(R)) である．これはすべてのバッグ R と任意の削除 <b>d</b> に対して成立するので，「重複行削除ビューは削除可能である」という命題がスキーマレベルで成立する．なお，T が定義 1 の条件 (a)～(c) を満たしていることはその定義から明らかである．</p>
<p style="margin-top: -00px;"><strong>【2】重複行削除ビューは挿入不可能</strong></p>
<p style="margin-top: -12px;"> 挿入不可能な重複行削除ビューの例を示す．たとえば，バッグ R={(1)(3)} の重複行除去ビュー δ(R)={(1)} に対して，挿入 <b>i</b>=insert {(2)} into δ(R) が発行されたとする．すると，<b>i</b> の R への変換は次のように無数に存在し一意ではない．したがって，「重複行削除ビューは挿入不可能である」という命題がスキーマレベルで成立する．<br />
T<sub>k</sub>(<b>i</b>)=insert {(2)(k)} into R; ここに k=1, 2, 3, <sub>…</sub></p>
<p>したがって，「重複行削除ビューは書換不可能である」という命題がスキーマレベルで成立する．</p>
<p style="margin-top: -00px;"><strong>【3】加法和（⨄）ビューは削除可能</strong></p>
<p style="margin-top: -12px;"> 加法和ビューを V=R⨄S とし，削除 <b>d</b>=deleteσ<sub>φ</sub>(V) from V; が発行されたとき，削除の定義から次が成り立つ．<br />
V∸σ<sub>φ</sub>(V)= (R⨄S)∸σ<sub>φ</sub>(R⨄S)=σ<sub>¬φ</sub>(R⨄S)=σ<sub>¬φ</sub>(R)⨄σ<sub>¬φ</sub>(S) = (R∸σ<sub>φ</sub>(R)) ⨄ (S∸σ<sub>φ</sub>(S))．<br />
したがって，削除 <b>d</b>= deleteσ<sub>φ</sub>(V) from V; を実現するための必要かつ十分条件は <b>d</b> を T(<b>d</b>)に変換することである．<br />
T(<b>d</b>)=begin; deleteσ<sub>φ</sub>(R) from R; deleteσ<sub>φ</sub>(S) from S; end;<br />
このことはすべてのバッグ R, S, φ と任意の削除 <b>d</b> に対して成立するので，「加法和ビューは削除可能である」という命題がスキーマレベルで成立する．なお，T が定義 1 の条件 (a)～(c) を満たしていることはその定義から明らかである．</p>
<p>なお，σ<sub>φ</sub>(R⨄S)=σ<sub>φ</sub>(R) ⨄σ<sub>φ</sub>(S) の証明は次の通りである．<br />
<b>【命題１】</b>σ<sub>φ</sub>(R⨄S)=σ<sub>φ</sub>(R) ⨄σ<sub>φ</sub>(S) が成立する．<br />
（証明）t(k)∈σ<sub>φ</sub>(R⨄S) とすると，∃t(k<sub>i</sub>)∈R∧∃t(ℓ<sub>j</sub>)∈S∧k=k<sub>i</sub>＋ℓ<sub>j</sub>∧φ(t) が成り立つ．φ(t)=φ(t)∧φ(t) なので，(∃t(k<sub>i</sub>)∈R∧φ(t))∧(∃t(ℓ<sub>j</sub>)∈S∧φ(t))∧k= k<sub>i</sub>＋ℓ<sub>j</sub> が成り立つ．すなわち，∃t(k<sub>i</sub>)∈σ<sub>φ</sub>(R)∧∃t(ℓ<sub>j</sub>)∈σ<sub>φ</sub>(S)∧k= k<sub>i</sub>＋ℓ<sub>j</sub> が成り立つ．したがって，⨄ の定義により，<br />
t(k)∈σ<sub>φ</sub>(R) ⨄σ<sub>φ</sub>(S) が成り立つ．逆に t(k)∈σ<sub>φ</sub>(R) ⨄σ<sub>φ</sub>(S) とすると，上記の逆の推論をたどることで t(k)∈σ<sub>φ</sub>(R⨄S) であることを示せる．</p>
<p style="text-align: right;">Q.E.D.</p>
<p style="margin-top: -00px;"><strong>【4】加法和（⨄）ビューは挿入不可能</strong></p>
<p style="margin-top: -12px;"> 加法和ビューとそれに対して発行された挿入が変換不可能な一例を示す．<br />
たとえば，和両立なバッグ R と S を R={(1)(3)}, S={(1)(2)} とするとき，加法和ビュー V=R⨄SはV={(1)(5)} である．このとき，V に対して挿入 <b>i</b>=insert {(2)(1)} into V; が発行されたとする．すると，<b>i</b> の変換は次の 2 通り考えられる．<br />
T<sub>1</sub>(<b>i</b>)=insert {(2)(1)} into R;<br />
T<sub>2</sub>(<b>i</b>)=insert {(2)(1)} into S;<br />
このように変換に一意性がないので，「加法和ビューは挿入不可能である」という命題がスキーマレベルで成立する．</p>
<p>したがって，「加法和（⨄）ビューは書換不可能である」という命題がスキーマレベルで成立する．</p>
<p style="margin-top: -00px;"><strong>【5】モーナス（∸）ビューは挿入不可能</strong></p>
<p style="margin-top: -12px;"> モーナスビューとそれに対して発行された挿入が変換不可能な一例を示す．<br />
和両立なバッグ R と S を，たとえば R={(1)(3)}, S={(1)(2)} とするとき，モーナスビュー V=R∸S は V={(1)(1)} である．このとき，V に対して挿入 <b>i</b>=insert {(1)(2)} into V; が発行されたとする．すると，<b>i</b> の変換は次のように無数にあり一意ではない．<br />
T<sub>k</sub>(<b>i</b>)=begin; insert {(1)(2+k)} into R; insert {(1)(k)} into S; end; ここに k=0, 1, 2, 3, <sub>…</sub><br />
したがって，<b>i</b> は変換可能ではない．このように反例を示せるので，「モーナスビューは挿入不可能である」という命題がスキーマレベルで成立する．</p>
<p>したがって，「モーナスビューは書換不可能である」という命題がスキーマレベルで成立する．</p>
<p style="margin-top: -00px;"><strong>【6】バッグ共通ビューは挿入不可能</strong></p>
<p style="margin-top: -12px;"> バッグ共通ビューとそれに対して発行された挿入が変換不可能な一例を示す．<br />
和両立なバッグ R と S を，たとえば R={(1)(3)}, S={(1)(2)} とするとき，V=R∩S={(1)(2)} である．このとき，V に対して挿入 <b>i</b>=insert {(1)(1)} into V; が発行されたとすると，<b>i</b> の変換は次の 2 通り考えられる．<br />
T<sub>1</sub>(<b>i</b>)=insert {(1)(1)} into S;<br />
T<sub>2</sub>(<b>i</b>)=begin; insert {(1)(1)} into R; insert {(1)(1)} into S; end;<br />
つまり，変換は一意ではなく <b>i</b> は変換可能ではない．このように反例を示せるので，「バッグ共通ビューは挿入不可能である」という命題がスキーマレベルで成立する．</p>
<p>したがって，「バッグ共通ビューは書換不可能である」という命題がスキーマレベルで成立する．</p>
<p style="margin-top: -00px;"><strong>【7】バッグ射影ビューは削除可能</strong></p>
<p style="margin-top: -12px;"> バッグ R の属性集合 X 上のバッグ射影ビューを V=π<sub>X</sub>(R) とし，V へ削除 <b>d</b>= deleteσ<sub>φ</sub>(V) from V; が発行されたとする．このとき σ<sub>φ</sub>(V)=σ<sub>φ</sub>(π<sub>X</sub>(R)) である．<br />
ところで，σ<sub>φ</sub>(π<sub>X</sub>(R))= π<sub>X</sub>(σ<sub>φ</sub>(R)) が成立する．<br />
<b>d</b>: V←V∸σ<sub>φ</sub>(V) であるから，V=V∸σ<sub>φ</sub>(V)= π<sub>X</sub>(R)∸π<sub>X</sub>(σ<sub>φ</sub>(R))= π<sub>X</sub>(R∸σ<sub>φ</sub>(R)) が成立する．したがって，<b>d</b> を実現するための必要かつ十分条件はそれを T(<b>d</b>) に変換することである．<br />
T(<b>d</b>)=deleteσ<sub>φ</sub>(R) from R;<br />
このことはすべてのバッグ R, S, φ と任意の削除 <b>d</b> に対して成立するので，「バッグ射影ビューは削除可能である」という命題がスキーマレベルで成立する．なお，T が定義 1 の条件 (a)～(c) を満たしていることはその定義から明らかである．</p>
<p>バッグ射影ビューとそれに対して発行された削除が変換可能な一例を示す．<br />
<b>【例題７】</b><br />
バッグ　R(A, B)={(1, 1), (1, 2), (1, 3), (2, 1), (2, 2)}　とし，V=π<sub>{A}</sub>(R)={(1)(3), (2)(2)} を R の {A} 上のバッグ射影ビューとする．このとき，V へ削除 <b>d</b>=delete σ<sub>φ</sub>(V) from V; ここに φ=(A=1)，が発行されたとするとき，一意で副作用がなく余分な更新をしない <b>d</b> の変換は次の通りである．<br />
T(<b>d</b>)=delete σ<sub>A=1</sub>(R) from R;</p>
<p style="margin-top: -00px;"><strong>【8】バッグ射影ビューは潜在キー保存ならば挿入可能</strong></p>
<p style="margin-top: -12px;"> バッグ R の属性集合 X 上のバッグ射影ビューを V=π<sub>X</sub>(R) とするとき，バッグ射影ビュー V が<b>潜在キー保存</b>（concealed key preservation）であるとは，X がバッグ R の潜在主キー K を含むときをいう．<br />
バッグ R の属性集合 X 上のバッグ射影ビューを V=π<sub>X</sub>(R) とする．V への挿入 <b>i</b>=insert W into V; が発行されたとする．ここに W={w<sub>1</sub>(k<sub>1</sub>), w<sub>2</sub>(k<sub>2</sub>), <sub>…</sub>, w<sub>m</sub>(k<sub>m</sub>)}，∀i((w<sub>i</sub>, k<sub>i</sub>)∈dom(V)) とする．<br />
このとき，W からバッグ <ruby>W<rt style="background-color: white;">～</rt></ruby> を次のように生成する．ここに null は空を表す．<br />
<ruby>W<rt style="background-color: white;">～</rt></ruby>={<ruby>w<rt style="background-color: white;">~</rt></ruby><sub>1</sub>(k<sub>1</sub>), <ruby>w<rt style="background-color: white;">~</rt></ruby><sub>2</sub>(k<sub>2</sub>), <sub>…</sub>, <ruby>w<rt style="background-color: white;">~</rt></ruby><sub>m</sub>(k<sub>m</sub>)}，ここに <ruby>w<rt style="background-color: white;">~</rt></ruby><sub>i</sub>[X]=w<sub>i</sub> かつ <ruby>w<rt style="background-color: white;">~</rt></ruby><sub>i</sub>[ Ω<span style="font-style: italic;"><b><sub>R</sub></b></span>－X]=(null, null, <sub>&#8230;</sub>, null) とする．<br />
このとき，V が潜在キー保存であるとすると，X は R の潜在主キー K を含み，潜在主キー属性が null をとることはないから，W と <ruby>W<rt style="background-color: white;">～</rt></ruby> の間には w(k)<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2194.png" alt="↔" class="wp-smiley" style="height: 1em; max-height: 1em;" /><ruby>w<rt style="background-color: white;">~</rt></ruby>(k) という 1 対 1 の関係性が成立する．<br />
また，π<sub>X</sub>(R⨄<ruby>W<rt style="background-color: white;">～</rt></ruby>)=π<sub>X</sub>(R) ⨄π<sub>X</sub>(<ruby>W<rt style="background-color: white;">～</rt></ruby>)=π<sub>X</sub>(R) ⨄W=V⨄W が成立するので，<b>i</b> を実現するための必要かつ十分条件は <b>i</b> を T(<b>i</b>)に変換することであることが分かる．<br />
T(<b>i</b>)=insert <ruby>W<rt style="background-color: white;">～</rt></ruby> into R;<br />
これは全てのバッグ射影ビュー V と挿入 <b>i</b> に対して成立するので，「バッグ射影ビューは潜在キー保存であれば挿入可能である」という命題がスキーマレベルで成立する．なお，T が定義 1 の条件 (a)～(c) を満たしていることはその定義から明らかである．</p>
<p>したがって，「バッグ射影ビューは潜在キー保存ならば書換可能である」という命題がスキーマレベルで成立する．</p>
<p>なお，「潜在キー保存」という条件自体はスキーマレベルの検証であるが，この検証を通過しただけでは「潜在キー制約」に抵触してしまう可能性がある．そのためにはインスタンスレベルの検証が必須となることは，3.2 節【10】項「射影ビューはキー保存ならば更新可能」のところで指摘したことと同様である．</p>
<p style="margin-top: -00px;"><strong>【9】バッグ選択ビューは削除可能</strong></p>
<p style="margin-top: -12px;"> バッグ R のバッグ選択ビューを V=σ<sub>φ</sub> (R) とし，V への削除 <b>d</b>=deleteσ<sub>ψ</sub>(V) from V; が発行されたとする．ここに ψ は探索条件である．X=σ<sub>ψ</sub>(V) とすると，V=σ<sub>φ</sub> (R) なので，X=σ<sub>ψ</sub>(V)=σ<sub>ψ</sub>(σ<sub>φ</sub> (R))=σ<sub>ψ∧φ</sub> (R)となる．<br />
そこで，<b>d</b> を次に示す T(<b>d</b>) に変換する．<br />
T(<b>d</b>)=deleteσ<sub>ψ∧φ</sub>(R) from R;<br />
このとき，<br />
σ<sub>φ</sub>(R∸σ<sub>ψ∧φ</sub>(R))=σ<sub>φ</sub>(R)∸σ<sub>φ</sub>(σ<sub>ψ∧φ</sub>(R)))=σ<sub>φ</sub>(R)∸σ<sub>ψ∧φ</sub>(R)=σ<sub>φ</sub>(R)∸σ<sub>ψ</sub>(σ<sub>φ</sub>(R))=V∸σ<sub>ψ</sub>(V) が成立する．<br />
この性質は全てのバッグ選択ビュー V と削除 <b>d</b> に対して成立するので，「バッグ選択ビューは削除可能である」という命題がスキーマレベルで成立する．なお，T が定義 1 の条件 (a)～(c) を満たしていることはその定義から明らかである．</p>
<p style="margin-top: -00px;"><strong>【10】バッグ選択ビューは挿入可能</strong></p>
<p style="margin-top: -12px;"> バッグ R のバッグ選択ビューを V=σ<sub>φ</sub> (R) とし，V への挿入 <b>i</b>=insert X into V; ここに X⊆dom(V) が発行されたとする．dom(V)= dom(σ<sub>φ</sub>(R))=σ<sub>φ</sub>(dom(R)) なので，X⊆σ<sub>φ</sub>(dom(R)) である．このとき，σ<sub>φ</sub>(σ<sub>φ</sub>(dom(R)))=σ<sub>φ</sub>(dom(R)) なので，σ<sub>φ</sub> (X)=X である．<br />
そこで，<b>i</b> を T(<b>i</b>) に変換する．<br />
T(<b>i</b>)=insert X into R;<br />
このとき，σ<sub>φ</sub> (R ⨄X)=σ<sub>φ</sub> (R) ⨄σ<sub>φ</sub> (X)=V ⨄X が成立する．<br />
この性質は全てのバッグ選択ビュー V と挿入 <b>i</b> に対して成立するので，「バッグ選択ビューは挿入可能である」という命題がスキーマレベルで成立する．なお，T が定義 1 の条件 (a)～(c) を満たしていることはその定義から明らかである．</p>
<p>したがって，「バッグ選択ビューは書換可能である」という命題がスキーマレベルで成立する．</p>
<p style="margin-top: -00px;"><strong>【11】バッグ <span style="font-style: italic;"><b>θ</b></span>-結合ビューは削除・挿入・書換不可能</strong></p>
<p style="margin-top: -12px;"> バッグ <span style="font-style: italic;">θ</span>-結合ビューの更新可能性については，リレーショナル代数での <span style="font-style: italic;">θ</span>-結合ビューの更新可能性がスキーマレベルで削除，挿入，いずれも不可能なので，バッグビューのそれについても不可能となる．</p>
<p style="margin-top: -00px;"><strong>4.4 一般的バッグビューの更新可能性（スキーマレベル）</strong></p>
<p style="margin-top: -12px;"> 表 5「基本的バッグビューの更新可能性（スキーマレベル）」は 4.3 節の議論の結果をまとめたものです．一般的バッグビューの更新可能性の判定は，3.3 節で論じた一般的リレーショナルビューの更新判定と全く同じように，作成した一般的バッグビューの定義木をトップダウンに，たとえば幅優先探索で走査しながら，ノードごとでその更新可能性を表 5 に参照していけば，その更新可能性をスキーマレベルで検証することができます．</p>
<h4>5．おわりに</h4>
<p style="margin-top: -18px;"> 本稿ではリレーショナルビューとバッグビューの更新可能性をスキーマレベルで論じその全貌を明らかにしました．集合であればバッグですが，逆は成立しないので，当然のこととして，リレーショナルビューが更新可能であっても，それを潜在リレーションとするバッグビューが更新可能となる保証はありません．その違いは表 3 と表 5 を比較することで一目瞭然かと思います．<br />
末筆ながら，理論と実践のはざまに言及しておくと次のとおりです．SQL はバッグ意味論に基づいたリレーショナルデータベース言語なので，SQL でのビューの更新可能性は本稿の表 5 に示したバッグビューの更新可能性に基づき規格化されてしかるべきす．しかしながら，現実には SQL が理論に先行してしまいました．それには歴史的理由があって，バッグビューの更新可能性の理論的研究は 1990 年代に入ってから盛んになったのですが，ビューとその更新可能性の重要性をいち早く認識していた SQL はその初めての国際標準規格である SQL-87 を制定した 1987 年時点でその規格化の第一歩を踏み出していました．そこでの原則は極めて現実的で，SQL-87 を改正した SQL-92 に見るように「更新が可能なビューは，実表から選択または射影だけを行っており，ビュー表の行および列が基となる実表の行および列と 1 対 1 に対応している場合である」というものでした．SQL-87 は SQL-92, SQL:1999, SQL:2003, SQL:2008, SQL:2011 等を経て最新規格の SQL:2016 まで改正され続け，少しでも多様なビューを更新可能にしようとビューとその更新可能性の規格も改正され続けてきましたが，「1 対 1 の対応」という基本的考え方に変更はないようです．本稿で論じたように，バッグビューの更新可能性はあくまで理論的であってそのような呪縛とは無縁です．SQL:2023 が近々発表されるようですが，何か変化はあるのでしょうか，注目したいと思います．<br />
なお，本稿ではビューの更新可能性をスキーマレベルで論じましたが，その対極にある「インスタンスレベルアプローチ」や「SQL のビューサポート」については機会を得て報告できればと思います．</p>
<p><strong>【文献】</strong></p>
<p style="margin-top: -10px;">[1]</p>
<p>Edgar F. Codd. A Relational Model of Data for Large Shared Data Banks. Communications of the ACM, Vol.13, No.6, pp.377-387, 1970.</p>
<p style="margin-top: -22px;">[2]</p>
<p>Edgar F. Codd. Recent Investigations in Relational Database Systems. Information Processing 74, pp. 1017-1021, North-Holland, 1974.</p>
<p style="margin-top: -22px;">[3]</p>
<p>Michael Stonebraker, Eugene Wong, Peter Kreps, and Gerald Held. The Design and Implementation of INGRES. ACM Transactions on Database Systems, Vol. 1, No. 3, pp. 189-222, September 1976.</p>
<p style="margin-top: -22px;">[4]</p>
<p>Umeshwar Dayal and Philip A. Bernstein. On the Updatability of Relational Views. Proceeding of VLDB 1978, pp.368-377, 1978.</p>
<p style="margin-top: -22px;">[5]</p>
<p>Edgar F. Codd. Extending the Database Relational Model to Capture More Meaning. ACM TODS, Vol.4, No.4, pp.397-434, 1979.</p>
<p style="margin-top: -22px;">[6]</p>
<p>増永 良文，長田 悠吾，石井 達夫. 更新意図の外形的推測に基づいたビューの更新可能性とその PostgreSQL 上での実現可能性検証. 日本データベース学会和文論文誌 Vol.18-J, Article No.1, 2020 年 3 月．</p>
<p style="margin-top: -22px;">[7]</p>
<p>増永 良文，長田 悠吾，石井 達夫. 整合ラベリング問題としてのクロス結合ビューの更新可能性. 日本データベース学会和文論文誌 Vol.19-J, Article No.1, 2021 年 3 月．</p>
<p style="margin-top: -22px;">[8]</p>
<p>Joseph Albert. Algebraic Properties of Bag Data Types. Proceedings of the 17th International Conference on Very Large Databases, pp.211-219, 1991．</p>
<p style="margin-top: -22px;">[9]</p>
<p>Wayne D. Blizard. Multiset Thoery. Notre Dame Journal of Formal Logic, Vol.30, No.1. pp.36-66, Winter 1989.</p>
<p style="margin-top: -22px;">[10]</p>
<p>増永良文．リレーショナルデータベース入門[第3版]，サイエンス社，2017．</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>増永教授のDB特論⑪「結果整合性」</title>
		<link>https://www.sraoss.co.jp/tech-blog/db-special-lecture/masunaga-db-special-lecture-11/</link>
		
		<dc:creator><![CDATA[増永良文 (Yoshifumi Masunaga)]]></dc:creator>
		<pubDate>Wed, 14 Dec 2022 00:00:50 +0000</pubDate>
				<category><![CDATA[増永教授のDB特論]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[RDB]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[リレーショナルデータベース]]></category>
		<category><![CDATA[結果整合性]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=11869</guid>

					<description><![CDATA[&#160; 1. はじめに &#8195;ビッグデータの管理・運用で注目を浴びることとなった結果整合性（eventual consistency）ですが，賛否両論あるようです．否定的な意見は，たとえば，クレップマン（Ma ...]]></description>
										<content:encoded><![CDATA[<p>&nbsp;</p>
<h4>1. はじめに</h4>
<p style="margin-top: -14px;">
&emsp;ビッグデータの管理・運用で注目を浴びることとなった<strong>結果整合性</strong>（eventual consistency）ですが，賛否両論あるようです．否定的な意見は，たとえば，クレップマン（Martin Kleppmann）[1]の<br />
著作に見ることができます．この著作，結構多くの方々がお持ちかと思いますが，クレップマンは複<br />
製を行うデータベースのほとんどは，少なくとも結果整合性を提供しているとしながらも，これは非<br />
常に弱い保障であり，複製がいつ（最終値に）収束するのかについては何も語られていなく，収束す<br />
るときまで，読取りの結果が何になるのか，あるいはそもそも何も返さないのかは分からない，とク<br />
レームしています．さらに，CAP 定理の対象範囲は非常に狭く，考慮しているのは 1 つの一貫性モ<br />
デルと 1 種類のフォールト（つまり，ネットワーク分断）だけで，ネットワークの遅延，落ちている<br />
ノード，あるいは他のトレードオフについては何も語っていない．したがって，CAP 定理は歴史的<br />
には大きな影響力があったものの，システムの設計における実際的な価値はほとんどない，と述べて<br />
います（文献[1]の 9 章「一貫性と合意」）．</p>
<p><span id="more-11869"></span></p>
<p style="margin-top: -28px;">
&emsp;このクレップマンの否定的意見は，読取りの結果が何であるのか分からない，CAP 定理に実際的<br />
価値はない，の 2 つに集約されると思いますが，まず，最初のクレームについて考えてみましょう．<br />
確かに，結果整合性は，「非常に」かどうかは別にして，「弱い保証である」ことに間違いはあり<br />
ません．整合性には強い整合性と弱い整合性があり，結果整合性は弱い整合性の一種であることは，<br />
結果整合性の提案者であるフォーゲルス（Werner Vogels）自身も述べている通りです[2]．結果整<br />
合性は Amazon.com, Inc.（以下，Amazon）が開発した「高可用キー・バリューストア」Dynamo[3]<br />
で初めて実装されましたが，フォーゲルスはその開発プロジェクトの中心人物でした（この Dynamo <br />
は Amazon の自社用で，AWS の一環として提供されている Amazon DynamoDB とは別物）．複製<br />
が最終値に収束するまでの時間を<strong>不整合窓</strong>（inconsistent window）といいますが，フォーゲルスに<br />
よれば，不整合窓の最大サイズは，通信の遅延，システムの負荷，レプリケーションスキームに含ま<br />
れる複製の数などの要因に基づいて決定できるとのことです．したがって，これはシステムの負荷や<br />
ネットワーク環境が安定しているときは一定の値を保つかもしれませんが，それらが変動すれば当然<br />
変動するだろうことは想像に難くなく，クレップマンの最初のクレームを理不尽と決めつけるわけに<br />
はいきません．<br />
&emsp;では，実際に結果整合性を実装したシステムでは不整合窓の長さについてどのような評価がなされ<br />
ているのでしょうか？これに関して，次のような見解を見ることができます．<br />
&emsp;まず，N，W，R を次のように定めます．<br />
&emsp;&emsp;&emsp;N：データの複製を格納しているノードの数（＝複製数）<br />
&emsp;&emsp;&emsp;W：更新完了の返事を返してくるべき複製の数<br />
&emsp;&emsp;&emsp;R：検索結果を返してくるべき複製の数<br />
&emsp;N，W，R はいかようにも定められますが，結果整合性を念頭に，N=3，W=1，R=1 と設定したシステムでは，可用性と一貫性が共に満たされているとの報告が見受けられます．つまり，W=1，R=1 なので高可用性の実現はその通りですが，一貫性も評価される原因としては，N=3 と複製数が小さいことや，新鮮でないデータでもそんなに腐臭が漂っているわけではないとの見解です．また，不整合窓の長さについては，実測で数 ms（millisecond）という報告もあれば，数 1,000ms という報告も見受けられます．これらの値が許容範囲にあるのかそうでないのかは定かではありませんが，不整合窓が長くてシステムが稼働しないといった報告は見つかりません．したがって，クレップマンが「読取りの結果が何であるのか分からない」としたクレームは，観念的にはそうなのだけれども実際にはその非難は当たっていないのではないか，と言えそうです．<br />
&emsp;次に，クレップマンが「CAP 定理に実際的価値はない」とクレームしている点についてですが，<br />
CAP 定理の主張する CP あるいは AP の選択で（詳細は 4 章），可用性（A）とネットワークの分断<br />
耐性（P）を選択した Amazon の Dynamo が顧客から間断なく舞い込む注文をこれまで処理し続けてこられたという実績はクレップマンの否定的な意見を覆すに十分な反証となっているのではないかと思います．最近の統計によれば，Amazon 本体（サードパーティの販売者によるマーケットプレイスは除くという意味）が扱っている商品数は約 1,200 万，毎月の顧客数は約 1 億，1 分あたりに売れる商品の数は約 4,000 という状況のようです．それを結果整合性のもとで，Amazon の Dynamo は always-on で処理し続けているわけです．<br />
&emsp;本稿は，以上のような観点から，結果整合性の意義を <ruby>ACID<rt style="background-color: white;">アシッド</rt></ruby> vs. <ruby>BASE<rt style="background-color: white;">ベース</rt></ruby> という論点とも絡めながら再検討しておきたいと思います．</p>
<h4>2. 結果整合性誕生は時代の必然</h4>
<p style="margin-top: -16px; margin-left: 00px; " >
&emsp;筆者は結果整合性という概念の誕生は，分散型データベースシステムの概念がウェブそしてビッグデータの到来で根底から変化することになった所産だと捉えています．<br />
&emsp;歴史的には，分散型データベースシステムは 1970 年代後半から 1980 年代にかけて IBM <ruby>San<rt style="background-color: white;">サン</rt></ruby> <ruby>Jose<rt style="background-color: white;">ホゼ</rt></ruby> 研究所で研究・開発された System <ruby>R * <rt style="background-color: white;">アールスター</rt></ruby>[4]をもってその嚆矢とすると認識しています．この時代の分散型データベースシステムの使命は遠隔地に散在するビジネスデータ<font style="border-bottom:3px double blue">を</font>コンピュータネットワーク<font style="border-bottom:3px double blue">を</font>介して相互アクセスし，いかにして「単一サイトイメージ」を実現するかが設計指針でした．言い換えれば「分散の透明性」の達成です．したがって，分散型データベースシステムはトランザクション処理に関してもあたかも単一サイトのイメージでそれを処理するわけですから，結果整合性などという発想は一切湧かず，単一サイトのデータベースシステムと同様に ACID 特性を堅持することが大前提となっていたわけです．<br />
&emsp;しかしながら，ウェブの誕生以降状況は徐々に変化していきます．ウェブは 1991 年をもってその元年としますが，その後進化をとげて 2005 年にオライリー（Tim O’Reilly）により Web 2.0 が提唱されました[5]．これには経緯があって，その背景には「ドットコムバブルの崩壊」があります．つまり，ウェブ誕生後数年を経た 1995 年頃から 2000 年頃にかけて米国の株式市場はドットコムバブルに沸き返っていました．ドットコム（.com）とは営利企業を表す分野別トップレベルドメイン（generic TLD）で，（ハイテク中心の）ドットコムカンパニーの NASDAQ 指数は 2000 年 4 月 10 日に 5,048 で史上最高となったわけです．インターネット関連ベンチャー企業が株式を上場すれば，期待感から高値で取引されたといわれています．しかし，2000 年に入ると，次第にこれらのベンチャー企業の優勝劣敗が明らかになり，見込みのないベンチャー企業が次々と破たんするようになり，熱狂は一挙に冷めて株価は大暴落し，2001 年秋にバブルは崩壊しました．ドットコムバブルがはじけて，多くのウェブ関連ベンチャー企業が泡沫のごとくこの世から消え去ったのですが，その洗礼を受けつつもその後も成長し続けたベンチャー企業がありました．それらは泡沫のごとく消え去ったベンチャー企業とどこが違っていたのか？オライリーのチームは両者のビジネスモデルの違いに着目して，ブレインストーミングを重ね，その結果が <strong>Web 2.0</strong> としてまとめられたというわけですが，ドットコムバブルの荒波を越えて生き残った代表格が Amazon や Google というわけです．<br />
&emsp;その Amazon が自社のビジネスモデルを達成せんがために構築した<strong>分散型データストア</strong>（distributed data store, DDS）が Dynamo で，そこで実装されたトランザクション管理の原理が従来の ACID 特性ではなく，結果整合性に基づいた BASE 特性であったということです．いみじくも，Dynamo の開発責任者であったフォーゲルは “Building reliable distributed systems at a worldwide scale demands trade-offs—between consistency and availability.”[2]と結果整合性の意義を述べていますが，この一文が従来の分散型データベースシステムとビッグデータ時代の分散型データベースシステムの構築原理の違いを端的に表していると思います．</p>
<h4>3. 分散型データストア</h4>
<p style="margin-top: -16px; margin-left: 00px; " >
&emsp;3V（volume, velocity, variety）の性質を有するビッグデータをリレーショナル DBMS で管理・運用しようとすると，たとえばリレーションがとても疎（sparse）になるとか，さまざまな問題が生じて限界があることはよく知られているところです．したがってそのようなデータはビッグデータを扱う各組織体のビジネスモデルに一番合うような形で管理・運用されることが常となりました．たとえば，<br />
Amazon はキー・バリューデータストアを，Google は列ファミリデータストアを，大量の JSON 文書を管理・運用したい組織は文書データストアを，そして，たとえば大規模なソーシャルネットワークを管理・運用したい組織はグラフデータベースを開発するといった具合です．その具体例が，Amazon<br />
 の Dymano や Google の BigTable[6]ということになるわけですが，<strong>NoSQL</strong>（Not only SQL の意）とはこのようなシステムの総称です．<br />
&emsp;さて，いわゆる NoSQL を標榜するシステムですが，スケーラビリティを（スケールアップではなく）スケールアウトで達成すること，システムは大規模となり個々のコンポーネントにあまりお金は掛けられないこと，システムが大規模になっても可用性は損ないたくないことなどを勘案すると，<strong>図 1</strong> に示されるような疎結合クラスタ（shared nothing cluster）構成をとる<strong>分散型データストア</strong>とするのが一般的です．<br />
&emsp;少しく説明を加えると，1 台のマスタが複数のクライアントとスレーブを管理します．クライアントからの問合せ（query）や更新要求（insert, delete, update）はマスタに届けられ，マスタはマスタの判断でそれらをスレーブに配信し，その結果をクライアントに届けます．疎結合クラスタ構成をとっているので，データ量が増大するにつれてスレーブを増設していけばシステムのスケーラビリティを台数効果に基づき<strong>スケールアウト</strong>で達成できます．また，可用性やネットワークの分断耐性を向上させるためにデータは<strong>複製</strong>（replica，レプリカ）を作成してそれをスレーブに分散配置します．しかしながら，データが重複してスレーブに分散配置されることで，データの一貫性をどのようにして達成するのかが問われることになります．本稿で取り上げている結果整合性はそのために考案されたトランザクション管理のための新しい原理ということです．なお，図 1 ではクライアントがマスタやスレーブと同じネットワークに結合されているので，ネットワーク分断が発生したときにクライアントとマスタが通信できなくなりますが，ここではそれは何らかの手段で確保されていることとします．論点は，ネットワーク分断が発生した場合にマスタと一部のスレーブとの間の通信が不可能となりますが，それがデータベースの可用性と一貫性にどのような影響を与えるのかにあります．</p>
<p><img decoding="async" style="margin-top: -08px; width: 726px;" align="centre" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/12/drmasunaga-11-P04-01.png" alt="図 1　NoSQL のアーキテクチャ（疎結合クラスタ構成）[７]" /></p>
<h4>4. CAP 定理</h4>
<p style="margin-top: -16px; margin-left: 00px; " >
&emsp;分散型コンピューティングの<ruby>強靭<rt style="background-color: white;">きょうじん</rt></ruby>性に関して，Inktomi 社の創設者であったブルーワ（Eric Brewer）は次のような経験則を 2000 年に開催された国際会議で発表しました[8]．</p>
<p>&emsp;&emsp;「一貫性，可用性，そしてネットワークの分断耐性の間には基本的にトレードオフがある」</p>
<p>&emsp;改めて記しますが，<strong>一貫性</strong>（consistency）とは，書込み操作が完了したのちに読取り操作を発行すれば，その書込みの結果が返されないといけないということで，もしデータを複製して管理している場合には，複製間で更新の同期がとられていて，どの複製を読もうとも，同じ値が返ってこないといけないことを意味します．<strong>可用性</strong>（availability）とは，クライアントが依頼した読取りや書込みに対して，それが無視されることはなく，<font style="border-bottom:3px double blue">いづれ</font>応答があるということをいいます．<strong>ネットワークの分断耐性</strong>（tolerance to network partitions あるいは partition tolerance）とは，サーバ間でやり取りするメッセージがいくらでも失われうることを意味します．つまり，本来ネットワークは分断されてしまうかもしれないという性質を有するので，ネットワーク分断が発生した状況の中にあっても分散型コンピューティングはそれなりに機能しないといけないということを<ruby>謳<rt style="background-color: white;">うた</rt></ruby>っているものです．そして，ブルーワはこのトレードオフの意味するところを <strong>CAP 定理</strong>（CAP theorem）と名付けました．ここに，CAP の C は Consistency，A は Availability，P は Partition tolerance の頭文字です．この定理は，発表当初はあくまで推測（conjecture）にしか過ぎなかったのですが，2 年後にその証明が与えられました[9]．証明は拙著[7]でも与えられているので興味があれば参照してください．</p>
<p>【定理１】（CAP 定理）<sup>[8]</sup><br />
&emsp;共有データシステムにおいては，一貫性，可用性，分断耐性という 3 つの性質のうち，高々 2 つしか両立させることが出来ない．</p>
<p>&emsp;CAP 定理を図示すると<strong>図 2</strong> のように描けます．</p>
<p><img decoding="async" style="margin-top: -28px; width: 600px;" align="centre" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/12/drmasunaga-11-P06-01.png" alt="図 2　CAP 定理" /></p>
<p>&emsp;ネットワークは分断するものですから，つまりネットワークが絶対に故障しないという保証を与えることはできないので，共有データシステムはネットワーク分断を前提に，システムとして一貫性（C）の実現を選択しますか？それとも可用性（A）の実現を選択しますか？どちらを採りますか？という選択を迫られることになります．つまり，次に示す二者択一となるわけです．<br />
&emsp;&emsp;&emsp;<strong>●</strong>　CP：一貫性と分断耐性を実現する．<br />
&emsp;&emsp;&emsp;<strong>●</strong>　AP：可用性と分断耐性を実現する．<br />
&emsp;なお，念のために，両選択の違いを例題で見ておくと次の通りです（AP については第 6 章でさらに議論します）．</p>
<p><strong>【例題１】</strong>（CP vs. AP）<br />
&emsp;図 1 に示した構成でスレーブ <sub>i</sub> とスレーブ <sub>i+1</sub> 間のネットワークが分断されてしまったとき，CP と AP のもとでシステムがどのように振舞うのかを検証する（ここに，i≦n－1）．<br />
&emsp;<strong>●</strong>　CP を採用した場合</p>
<p style="margin-top: +22px;" >
<table style="border:none; margin-top: -34px; margin-left: 38px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
そのようなネットワークの分断が発生すると，スレーブ <sub>1</sub> ～スレーブ <sub>i</sub> 群とスレーブ <sub>i+1</sub> ～スレーブ <sub>n</sub> 群は通信不可となる，つまり両群にまたがり存在する同一データの複製間の一貫性を保証する手段がなくなるので，システムはネットワーク分断を検知した時点で停止し，読取り要求も書込み要求も受け付けず，ネットワーク分断の回復を待つ．
</td>
</tbody>
</table>
<p>&emsp;<strong>●</strong>　AP を採用した場合</p>
<p style="margin-top: +22px;" >
<table style="border:none; margin-top: -34px; margin-left: 38px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
マスタはスレーブ <sub>１</sub> ～スレーブ <sub>i</sub> にアクセスし，N（データの複製数），R（検索結果を返してくるべき複製の数）や W（更新完了の返事を返してくるべき複製の数）が定める定足数に従い行動する．読取り要求の場合，検索されたデータがスレーブ <sub>１</sub> ～スレーブ <sub>i</sub> にあり，その数が R 以上であればそれをクライアントに返す（複数見つかれば時刻印が最新のデータを返す）．書込み要求の場合，マスタはスレーブ <sub>１</sub> ～スレーブ <sub>i</sub> にその書込み要求を発行する．もし，書込み完了の返事の数が W 以上となれば書込みが完了した旨をクライアントに報告する．そうでなければ，書込み失敗をクライアントに報告する．前者の場合，複製の数は N（≧W）なので，報告時点で書込みが完了していない複製がスレーブ <sub>1</sub> ～スレーブ <sub>i</sub> 群とスレーブ <sub>i+1</sub> ～スレーブ <sub>n</sub> 群に存在する可能性がある．これらの複製の書込みは<strong>遅延複製</strong>（lazy replication）[2, 10]で行う．つまり，書込みが可能となり次第，順次更新していく．
</td>
</tbody>
</table>
<p>&emsp;このように，どちらを選択するかで，システムの振舞はがらりと変わってきます．具体的には，先述の通り，CP の選択肢を採ったのが Google の Bigtable であり，AP の選択肢を採ったのが Amazon の Dynamo ということです．Bigtable では分散したデータの複製の更新同期をとり一貫性を実現するために Paxos アルゴリズムが使われています．では，Dynamo は AP を実現するためにどのようなシステムアーキテクチャを開発したのでしょうか？それを以下に見てみます．</p>
<h4>5. BASE 特性</h4>
<p style="margin-top: -16px; margin-left: 00px; " >
&emsp;CAP 定理により，ネットワークの分断が発生しても，可用性を採るとマスタはアクセスできるスレーブから所望のデータを読み書きできます．しかしながら，読み書きの対象となったデータが最新のデータであるかどうか，つまり一貫性のあるデータであるか否かの保証はありません．つまり，可用性を採ると，ネットワーク分断によりデータには更新されて新値を採るデータと旧値のままのデータが混在することとなり，データベースが一貫している保証はありません．つまり，この状況下では従来のトランザクション管理が金科玉条のごとく信奉してきた ACID 特性という概念が無意味化しているといえます．<br />
&emsp;では，可用性とネットワークの分断耐性（AP）を採ったシステムは一体どういう特性を満たしているといえるのでしょうか？それが，結果整合性に基づいた <strong>BASE 特性</strong>であるわけです．ちなみに，<br />
BASE とは次の語群の頭文字です．</p>
<ul style="margin-top: -22px; margin-left: 60px; ">
<li>Basically Available</li>
<li>Soft-state</li>
<li>Eventual consistency</li>
</ul>
<p style="margin-top: -24px; margin-left: 00px; " >
&emsp;ここに，Basically Available（<strong>基本的に可用</strong>）とは，共有データシステムは CAP 定理のいう AP の下で可用ということです．Soft-state（<strong>ソフト状態</strong>）とは，システムの状態は入力が無くても時間の経過と共に変遷していくであろうということです．Eventual consistency（<strong>結果整合性</strong>）とは，現時点では一貫性のないデータでもそれに対して何の更新要求も無ければ，<ruby>何時<rt style="background-color: white;">いつ</rt></ruby>かは一貫するであろうということです．<br />
&emsp;なお，BASE という用語ですが，ACID vs. BASE という対比を際立たせるために特に考えられたとのことです．すなわち，ACID の英語での意味は「酸」ですが，BASE は「塩基」（＝アルカリ）を意味し，酸とアルカリで世界を 2 分するという意味を込めて，わざわざ BASE と命名されたという逸話が残っています．<br />
&emsp;では，BASE 特性の基となっている結果整合性をどのように実装するのか，次に見てみます．</p>
<h4>6. 結果整合性の実装</h4>
<p style="margin-top: -16px; margin-left: 00px; " >
&emsp;BASE 特性を裏打ちする結果整合性はどのようにして実装できるのでしょうか？それを見てみることにします[2]．<br />
&emsp;まず，整合性（一貫性と同義）には 2 つの観点があります．一つはクライアント側から見た場合の整合性です．これは，クライアントにとってデータ更新がどう見えるかということです．もう一つはサーバ側から見た場合で，どのように更新処理がなされるのか，更新する際にシステムとして何を保証することができるかという観点です．<br />
&emsp;まず，クライアント側から見れば，整合性は次のように大別されます．</p>
<p style="margin-top: -20px; margin-left: 00px; " >
&emsp;&emsp;&emsp;&emsp;<strong>●</strong> 強い整合性<br />
&emsp;&emsp;&emsp;&emsp;<strong>●</strong> 弱い整合性<br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;<strong>○</strong> 結果整合性<br />
&emsp;まず，<strong>強い整合性</strong>（strong consistency）は，データの更新が完了すると，その後どの複製にアクセスしても更新された値を返してくることをいいます．強い整合性でない場合を<strong>弱い整合性</strong>（weak consistency）といいます．弱い整合性では，データの更新が完了したとしても，その後のアクセスが更新された値を返すことを保証しません．値が返されるにあたっては，いくつかの条件を満たす必要があります．更新から，クライアントが更新された値を常に見ることが保証される瞬間までの期間を<strong>不整合窓</strong>（inconsistent window）といいます．<br />
&emsp;<strong>結果整合性</strong>（eventual consistency）は弱い整合性の一種です．ストレージシステムは，オブジェクトに対して新しい更新が行われない場合，最終的にすべてのアクセスが最後に更新された値を返すことを保証します．障害が発生しない場合，不整合窓の最大サイズは，通信の遅延，システムの負荷，レプリケーションスキームに含まれるレプリカの数などの要因に基づいて決定できるとされています．<br />
&emsp;次に，サーバ側から見た場合，結果整合性は次のように形式化することができます．そのために，<br />
N，W，R を次のように定めます．<br />
&emsp;→&emsp;N：データの複製を格納しているノードの数（＝複製数）<br />
&emsp;→&emsp;W：更新完了の返事を返してくるべき複製の数<br />
&emsp;→&emsp;R：検索結果を返してくるべき複製の数<br />
&emsp;つまり，マスタはクライアントからデータの更新要求を受け付けると，そのデータの複製を格納している N 個のスレーブにその更新要求を発送し更新が完了したかどうか，返事を待ちます．もし，少なくとも W 個のスレーブから更新完了の返事が来たら，その時点でマスタはクライアントに更新完了の返事を送ります．一方，クライアントからマスタにデータ検索要求が来たら，マスタはその複製を格納している N 個のスレーブにその検索要求を発送して結果を待ちます．もし少なくとも R 個のスレーブから結果が返ってくれば，その中から最新の結果を選択して（そのために，データには時刻印やバージョンを付けておく），それをクライアントに返します．つまり，W や R はマスタがアクションをとれるための定足数（quorum）を定めていることになります．まとめると次のようになります．<br />
&emsp;&emsp;&emsp;&emsp;(1)&emsp; W+R＞N の場合：強い整合性で対処する．<br />
&emsp;&emsp;&emsp;&emsp;(2)&emsp; W+R≦N の場合：結果整合性で対処する．<br />
&emsp;若干説明を追加すると，W+R＞N の場合，書込み集合と読取り集合の「共通集合」（intersection）<br />
は非空，つまり 2 つの集合は重なり合った部分があるということですから，強い整合性を保証できる<br />
ということです．一方，W+R≦N の場合，共通集合が空となりうるので，強い整合性は保証できず，<br />
この場合には結果整合性で対応しようということです．したがって，結果整合性を実装するというこ<br />
とは，上記（2）の状況となるようなＮ，Ｗ，R を設定して検索や更新要求に対処するということです．<br />
&emsp;第 1 章での説明と重複しますが，N=3，W=1，R=1 と設定することで可用性と一貫性が共に満た<br />
されているとの報告が見られます．W=1，R=1 なので高可用性の実現はその通りですが，一貫性も<br />
評価される原因としては，N=3 と複製の数が小さいことや，新鮮でないデータでもそんなに腐臭が<br />
漂っているわけではない，という見解も見られます．不整合窓の長さについては，実測で数 ms<br />
（millisecond）という報告もあれば，数 1,000ms という報告もあります．これらの値が許容範囲に<br />
あるのかそうでないのかは定かではありませんが，不整合窓が長くてシステムが稼働しないといった<br />
報告は見つかりません．<br />
&emsp;なお，N，W，R の設定の仕方でシステムの振る舞いは相当に変わってきます．N=2, W=1, R=1 では強い整合性とはならないので一貫性は保証されないことに注意します．高性能で高可用な分散型データストアでは通常 N≧３ といわれています．一方，耐故障性（fault tolerance）を謳うシステムは，強い整合性を実現できる N=3, W=2, R=2 をとることが多いとのことです．組合せはさまざまで，興味のある者は論文[2]にあたってみてください．<br />
&emsp;DNS (Domain Name System)は結果整合性を実装する最も一般的なシステムとして知られていますが，Dynamo がキー・バリューデータモデルの考案と共に，結果整合性を実装してトランザクション管理を行うことで，Amazon の顧客はいつでも待たされることなく（always-on），ショッピングカートに入れた商品の注文を確定することができているという事実の説得性をここで改めて強調しておきたいと思います．</p>
<h4>7．おわりに</h4>
<p style="margin-top: -18px; ">&emsp;分散型データストアを構築しようとしたとき，「ACID 特性 vs. BASE 特性」，あるいは「CP vs. AP」，あるいは「強い整合性 vs. 結果整合性」はきっと永遠のテーマだと思いますが，BASE・AP・結果整合性の採用は高可用性やスケーラビリティを達成したい分散型データストアの設計指針として，大変理に<ruby>適<rt style="background-color: white;">かな</rt></ruby>っている発想だと思います．結果整合性が世に出て早くも十数年の月日が流れました．改めて，結果整合性の意義を回顧する報告が出ています[11, 12, 13]．興味のある方には一読を勧めますが，いずれも結果整合性を肯定的に捉えています．<br />
&emsp;分散コンピューティングをデータベースの視点で捉えると，単一サイトイメージの達成が至上命令であった時代から数十年を経て，分散型データ管理は結果整合性で対応していこうという時代の流れになりました．この背景には，ビッグデータの管理・運用こそがビジネスモデルとする巨大な IT企業の誕生がありました．従来は基幹システムと称して OLTP がデータ処理の中核で，そこでは金科玉条のごとく ACID 特性への順守が叫ばれました．これは単一サイト，分散型を問わずということです．しかし，<br />
ACID 特性は 3V の特徴を有するビッグデータの管理．運用が求める原理・原則ではなかったということです．そして，その要求に応えるべく必然的に生まれたのが BASE 特性であり結果整合性であったということです．<br />
&emsp;筆者はかつて IBM San Jose 研究所の客員研究員として，分散型リレーショナルデータベース管理システム開発の草分けであった System R* プロジェクトのメンバーとしてそのアクティビティを 1 年間にわたり目の当たりにしましたが，隔世の感を禁じ得ません．
</p>
<p><strong>【文献】</strong></p>
<p style="margin-top: -10px;" >[1]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Martin Kleppmann. 斉藤太郎（監訳）．玉川竜司（訳）．データ指向アプリケーションデザイン　信頼性，拡張性，保守性の高い分散システム設計の原理．オライリー・ジャパン，634p., 2019．
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[2]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Werner Vogels. Eventually Consistent. ACM Queue, Vol. 6, Issue 6, pp 14–19, 2008. （同一内容の論文が，Werner Vogels. Eventually consistent. Communications of the ACM, Vol. 52, Issue 1, pp.40–44, 2009. として出版されている）
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[3]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
G. DeCandia, D. Hastorun, M. Jampani, G. Kakulapati, A. Lakshman, A. Pilchin, S. Sivasubramanian, P. Vosshall and W. Vogels. Dynamo: Amazon’s Highly Available Key-value Store. Proceedings of the 21st ACM Symposium on Operating Systems Principles (SOSP&#8217;07), pp.205-220, October 14–17, 2007.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[4]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
B.G. Lindsay, L.M. Haas, C. Mohan, P.F. Wilms and R.A. Yost. Computation and communication in R*: A distributed database manager. ACM Transactions on Computer Systems, Volume 2, Issue 1, pp 24–38, February 1984.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[5]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Tim O’Reilly. What Is Web 2.0: Design Patterns and Business Models for the Next Generation of Software. 2005.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[6]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Fay Chang, Jeffrey Dean, Sanjay Ghemawat, Wilson C. Hsieh, Deborah A. Wallach, Mike Burrows, Tushar Chandra, Andrew Fikes and Robert E. Gruber. Bigtable: A Distributed Storage System for Structured Data. Proceedings of the 7th USENIX Symposium on Operating Systems Design and Implementation (OSDI&#8217;06), pp.205-218, 2006.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[7]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
増永良文．リレーショナルデータベース入門[第３版]．サイエンス社，2017．
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[8]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Eric A. Brewer. Towards Robust Distributed Systems (abstract), (Invited Talk). Proceedings of the 19th ACM Symposium on Principles of Distributed Computing, p.7, Portland, Oregon, July 2000.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[9]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
S. Gilbert and N. Lynch. Brewer&#8217;s Conjecture and the Feasibility of Consistent, Available, Partition-tolerant Web Services. ACM SIGACT News Homepage Archive, Volume 33, Issue 2, pp.51-59, June 2002.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[10]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Rivka Ladin, Barbara Liskov, Liuba Shrira and Sanjay Ghemawat. Providing High Availability Using Lazy Replication. ACM Transactions on Computer Systems, Vol 10, No. 4, pp. 360–391, November 1992.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[11]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Dan Pritchett. BASE: An Acid Alternative: In partitioned databases, trading some consistency for availability can lead to dramatic improvements in scalability. ACM Queue, Vol. 6, Issue 3, pp 48–55, 2008.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[12]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Eric A. Brewer. CAP Twelve Years Later: How the &#8220;Rules&#8221; Have Changed. Computer, Vol.45, Issue 2, pp.23-29, IEEE Computer Society, 2012.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[13]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Peter Bailis and Ali Ghodsi. Eventual Consistency Today: Limitations, Extensions, and Beyond: How can applications be built on eventually consistent infrastructure given no guarantee of safety? ACM Queue, Vol.11, Issue 3, pp.20-32, 2013.
</td>
</tbody>
</table>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>増永教授のDB特論⑩「GEQO」</title>
		<link>https://www.sraoss.co.jp/tech-blog/db-special-lecture/masunaga-db-special-lecture-10/</link>
		
		<dc:creator><![CDATA[増永良文 (Yoshifumi Masunaga)]]></dc:creator>
		<pubDate>Wed, 09 Nov 2022 00:30:31 +0000</pubDate>
				<category><![CDATA[増永教授のDB特論]]></category>
		<category><![CDATA[GEQO]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[RDB]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[リレーショナルデータベース]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=11382</guid>

					<description><![CDATA[&#160; 1. はじめに &#8195;リレーショナル DBMS において質問処理の最適化はリレーショナル DBMS の開発が始まって以来，設計者が最も腐心するところでした．その嚆矢は 1970 年代に IBM San ...]]></description>
										<content:encoded><![CDATA[<p>&nbsp;</p>
<h4>1. はじめに</h4>
<p style="margin-top: -14px;">
&emsp;リレーショナル DBMS において質問処理の最適化はリレーショナル DBMS の開発が始まって以来，設計者が最も腐心するところでした．その嚆矢は 1970 年代に IBM <ruby>San<rt style="background-color: white;">サン</rt></ruby> <ruby>Jose<rt style="background-color: white;">ホゼ</rt></ruby> 研究所で開発された System R で提案・実装された<strong>コストベース</strong>（cost based approach）の最適化手法です[1]．System <br />
R は PostgreSQL の前身である INGRES と共にリレーショナル DBMS のプロトタイプとして名高い<br />
システムですが，そこで開発されたこの手法は現在もプロプライエタリや PostgreSQL を含む OSS <br />
のリレーショナル DBMS の質問処理最適化技法の基本となっています．</p>
<p><span id="more-11382"></span></p>
<p style="margin-top: -28px;">
&emsp;この手法は問合せの実行プランを策定するにあたり，問合せ最適化器（query optimizer, 単に<strong>オプティマイザ</strong>，あるいは<strong>プランナ</strong>）は，まず単一のリレーションについてコスト最小のアクセスプランを推定し，つぎに，その結果を使って 2 つのリレーションを結合する場合のコスト最小プランを推定し，さらに，3 つのリレーションの結合コストをコスト最小と推定された 2 つのリレーションの結合を使って推定していくので，動的計画法（dynamic programming, <strong>DP</strong>）の一つとも位置付けられています．<br />
&emsp;さて，人工知能の一分野である機械学習はさまざまな分野で取り入れられていますが，データベース分野も例外ではありません．データベース分野での機械学習の適用を考えてみると，まずはデータ活用への機械学習の適用でしょう．これに対しては，Oracle Database に一日の長の感があり，「Oracle Database で高性能の機械学習モデルを構築する」といったウェブページが立ち上がっています．データサイエンティストへの支援です（ <a href="https://www.oracle.com/jp/artificial-intelligence/database-machine-learning/" target="_blank" rel="noopener noreferrer">https://www.oracle.com/jp/artificial-intelligence/database-machine-learning/</a> ）．<br />
&emsp;もう一つは機械学習をオプティマイザに適用する研究・開発でしょう．PostgreSQL には早くからその動きがあり，PostgreSQL 6.1（1997 年 6 月リリース）で <strong>GEQO</strong> のサポートが始まり現在に至っています．GEQO はユーティッシュ（M. Utesch）[2]の考案により実装されましたが，GEQO はその名前の由来が <strong>GEnetic Query Optimization</strong> にあることから分かるように，<strong>遺伝的アルゴリズム</strong>（genetic algorithm, <strong>GA</strong>）を用いた結合質問処理最適化のための手法です．PostgreSQL に対する問合せ処理最適化への機械学習の適用を見てみると，PostgreSQL の世界会議である PGCon 2007 で Kovarik ら[3]が機械学習と質問処理最適化を論じています．PGCon 2010 では Urbański[4]が結合質問処理の最適化について GEQO に代わる手法として「焼きなまし法」（simulated annealing）を用いた提案をしています．また，PGCon 2017 では Ivanov[5]が Postgres Pro Enterprise の拡張機能として AQO (adaptive query optimization) を報告しています．AQO はコストベースの問合せ最適化のために，機械学習の手法として知られている「k-近傍法」を使用してカーディナリティ推定を改善することで実行計画を最適化しているとのことで，PostgreSQL 9.6 以降で稼働するとのことです．ここに，カーディナリティ推定とはサブプラン作成のために中間結果のリレーションのサイズを推定することをいい，強力なオプティマイザ設計のために欠かせない技術です．PGCon 以外では，オートマトン理論を基にして結合質問処理の最適化を行い GEQO と比較検証した結果が報告されています[6]．</p>
<tr>
<img decoding="async" style="margin-top: -48px; width: 200px;" align="right" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/11/drmasunaga-10-P02-01b.png" alt="GA の概要" /></p>
<p style="margin-top: -22px;">
また，機械学習で注目を集めている深層学習（deep learning）を質問処理の最適化に適用しようとする研究も報告されており，そこでは PostgreSQL が性能評価のために使用されています[7]．<br />
&emsp;本稿では GA をいち早く質問処理の最適化に導入した GEQO に着目をして，その基本的考え方やその効果を見てみたいと思います．</p>
<h4>2. 遺伝的アルゴリズム（GA）とは</h4>
<p style="margin-top: -10px;">
&emsp;GEQO を理解するにあたって，<strong>遺伝的アルゴリズム（GA）</strong>を理解しておくことが大前提となるので，その説明から始めます．<br />
&emsp;GA は 1975 年にミシガン大学のホーランド（J. H. Holland）により提案されました<font style="border-bottom:3px double blue">[8]．</font>GA をフローチャートで<strong>図 1</strong> に示します[9]．このアルゴリズムの概略は次の通りです．</P></p>
<p><strong>【GA のアルゴリズム】</strong><br />
&emsp;<strong>ステップ1. </strong></p>
<table style="border:none; margin-top: -62px; margin-left: 82px; margin-bottom: -00px;" >
<tbody style="border:none;">
<td style="border:none;">
&emsp;初期集団（＝初期個体群）を用意する（第 0 世代）．
</td>
</tbody>
</table>
<p>&emsp;<strong>ステップ2.</strong> </p>
<table style="border:none; margin-top: -62px; margin-left: 82px; margin-bottom: -00px;" >
<tbody style="border:none;">
<td style="border:none;">
&emsp;各個体について「適応度」（fitness），つまり，個体が<br />&emsp;環境に適応して子孫を残すことのできる能力の度合い，<br />&emsp;を計算する．
</td>
</tbody>
</table>
<p>&emsp;<strong>ステップ3.</strong> </p>
<table style="border:none; margin-top: -62px; margin-left: 82px; margin-bottom: -00px;" >
<tbody style="border:none;">
<td style="border:none;">
&emsp;選択をする．選択とは「両親」（parents）の選択を<br />&emsp;意味する．
</td>
</tbody>
</table>
<p>&emsp;<strong>ステップ4.</strong> </p>
<table style="border:none; margin-top: -62px; margin-left: 82px; margin-bottom: -00px;" >
<tbody style="border:none;">
<td style="border:none;">
&emsp;遺伝子の交叉（crossover）を起こさせる．
</td>
</tbody>
</table>
<p>&emsp;<strong>ステップ5.</strong> </p>
<table style="border:none; margin-top: -62px; margin-left: 82px; margin-bottom: -00px;" >
<tbody style="border:none;">
<td style="border:none;">
&emsp;遺伝子の突然異変（mutation）を起こさせる．
</td>
</tbody>
</table>
<p>&emsp;<strong>ステップ6.</strong> </p>
<table style="border:none; margin-top: -62px; margin-left: 82px; margin-bottom: -00px;" >
<tbody style="border:none;">
<td style="border:none;">
&emsp;各個体について適応度を計算する．
</td>
</tbody>
</table>
<p>&emsp;<strong>ステップ7.</strong> </p>
<table style="border:none; margin-top: -62px; margin-left: 82px; margin-bottom: -00px;" >
<tbody style="border:none;">
<td style="border:none;">
&emsp;停止条件を満たすか否かを検証する．もし満たしていな<br />&emsp;ければ，ステップ 3 に行く．満たしていれば，最も高い<br />&emsp;適応値を持つ個体を選択して終了する．
</td>
</tbody>
</table>
</tr>
<p style="margin-top: +28px;" >&emsp;いくつか補足すると次の通りです．</p>
<p style="margin-top: -20px;" >&emsp;●　</p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
初期集団（＝初期個体群）は遺伝子（gene）の集まりで，ランダムに何体か生成する．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;●　</p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
適応度とは，淘汰の度合いを示す因子で，適応度の高い遺伝子は生き残り，そうでない遺伝子は淘汰される．適応度は GA が適用される分野に合わせて設定される．なお，適応度の計算は個体ごとに行うので，同時に（concurrently）実行してよい．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;●　</p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
両親の選択であるが，最も受け入れられている方法が，個体は適応度に比例した確率で親になれるという選択法で，それを実装した<strong>ルーレット盤選択</strong>（roulette wheel selection）が良いとされている．これは，ルーレット盤を個体の適応度の大きさ順にその割合で分割しておき，回転したルーレット盤が停止した時に針の指している個体を第 1 の親，続けて第 2 の親を決めるという手法である．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;●　</p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
停止条件であるが，世代の最大数を決めておきそれに到達したら停止する，適応度の改善が見られなくなったので停止する，あらかじめ決めておいた時間をオーバー<font style="border-bottom:3px double blue">したり</font>資源（CPU やメモリ）を一定量消費したら停止する，などさまざまである．
</td>
</tbody>
</table>
<p style="margin-top: +80px;" >
&emsp;さらに，交叉，突然異変，エッジ再結合交叉について，もう少し詳しく補足すると次のようです．</p>
<p style="margin-top: -18px;" ><strong>■　交叉（crossover）</strong><br />
&emsp;たとえば，1, 2, 3, 4, 5, 6 はリレーション R<sub>1</sub>, R<sub>2</sub>,<sub> …</sub>, R<sub>6</sub> を表すとする．この時，親個体 A=1-2-3-4-5-6，親個体 B＝2-4-6-1-3-5 とした時（数字の並び順は対応するリレーションの結合順を表している），「一点交叉」により，子個体 C<sub>1</sub>=1-2-3-1-3-5，子個体 C<sub>2</sub>=2-4-6-4-5-6 が生まれる（この例では，交叉は中央で起こるとした）．しかしながら，子個体の遺伝子もリレーション R<sub>1</sub>, R<sub>2</sub>,<sub> …</sub>, R<sub>6</sub> の結合順を表しているとするならば，C<sub>1</sub> には 1 と 3 が 2 度出現し，4，6 が出現していないので，R<sub>1</sub>, R<sub>2</sub>,<sub> …</sub>, R<sub>6</sub> の結合プランとはなりえない．このような遺伝子を<strong>致死遺伝子</strong>という．C<sub>2</sub> も同じである．このような場合，「適応度は 0」ということになる．</P></p>
<p><strong>■　突然異変（mutation）</strong><br />
&emsp;通常の GA では，交叉と並び突然変異を利用して進化する．しかしながら，突然変異はそれだけでも最適解を探索し得る強力なオペレーションであり， GA の挙動に大きく影響を与えるため，状況によっては提案手法の有用性ないしは問題点を確認しにくくすると考えられる．したがって，そのような場合<font style="border-bottom:3px double blue">は</font>突然変異<font style="border-bottom:3px double blue">は</font>利用しないという選択肢がありうる．実際，GEQO では突然異変は考慮しないこととしている．</p>
<p>&emsp;続けて，GEQO の実装で採用された<strong>エッジ再結合交叉(edge recombination crossover, ERC)</strong>を例題と共に示しておきます．</p>
<p><strong>■　エッジ再結合交叉（ERC）</strong><br />
&emsp;エッジ再結合交叉とは，頂点ではなくエッジを見ることで，既存のパス（path, 経路）のセットに類似したパスを作成する演算子で，1989 年にホイットリー（D. Whitley）ら[10]によって導入され，<br />
GENITOR アルゴリズムと名付けられました．ちなみに，GENITOR とは GENetic ImplemenTOR の略称です．<strong>巡回セールスマン問題</strong>（travelling salesman problem, <strong>TSP</strong>）に対して他の手法よりも優れた手法であるとされています[11]．なお，TSP とは巡回セールスマンの最短ルートを見つける問題です．この際，巡回セールスマンは，本拠地から始めて，指定されたリストのすべての都市を正確に 1 回訪れ，その後本拠地に戻る必要があります．この問題の難しいところは，可能なツアーの数が非常に多いことで，n 都市に対して (n－1)!/2 となり，TSP は NP 困難な問題として知られています．</p>
<p>&emsp;さて，ERC は子個体生成のために現在の要素の次の要素を決める際、2 つの親個体においてその要素の両側に隣接した 4 つの要素を候補とする手法です．それを例題で説明します．</p>
<p><strong>【例題１】（エッジ再結合交叉，ERC）</strong><br />
&emsp;ERC を，たとえば上述の「交叉」と同じ例を用いて説明すると次のようになる．1, 2, 3, 4, 5, 6 は<br />
リレーション R<sub>1</sub>, R<sub>2</sub>,<sub> …</sub>, R<sub>6</sub> を表すとする．同様に，親個体 A=1-2-3-4-5-6，親個体 B＝2-4-6-1-3-5 <br />
とする．このとき，A では 6-1 とつながり，B では 5-2 とつながり巡回するとする．そこで，A と B <br />
の<strong>隣接行列</strong>（adjacency matrix）を作ると次のようである．</p>
<p>&emsp;&emsp;A　　　　　　　　　　　　　　　　　　B<br />
&emsp;&emsp;<font style="border-bottom:3px double blue">1:</font> 2, 6　　　　　　　　　　　　　　　　1: 3, 6<br />
&emsp;&emsp;2: 3, 1　　　　　　　　　　　　　　　　2: 4, 5<br />
&emsp;&emsp;3: 4, 2　　　　　　　　　　　　　　　　3: 5, 1<br />
&emsp;&emsp;4: 5, 3　　　　　　　　　　　　　　　　4: 6, 2<br />
&emsp;&emsp;5: 6, 4　　　　　　　　　　　　　　　　5: 2, 3<br />
&emsp;&emsp;6: 1, 5　　　　　　　　　　　　　　　　6: 1, 4</p>
<p>&emsp;続いて，A と B の隣接行列の和（union）をとる（重複は除去）と次のようである．<br />
&emsp;&emsp;A∪B<br />
&emsp;&emsp;1: 2, 3, 6<br />
&emsp;&emsp;2: 1, 3, 4, 5<br />
&emsp;&emsp;3: 1, 2, 4, 5<br />
&emsp;&emsp;4: 2, 3, 5, 6<br />
&emsp;&emsp;5: 2, 3, 4, 6<br />
&emsp;&emsp;6: 1, 4, 5</p>
<p>&emsp;このとき，交叉による新しい個体（＝遺伝子）を次のように生成する．<br />
&emsp;(1) 1～6 の数字をランダムに 1 つ選ぶ．ここでは，1 を選んだとする．<br />
&emsp;(2) 隣接集合から 1 を削除する．その結果，次の隣接行列を得る．<br />
&emsp;&emsp;A∪B<br />
&emsp;&emsp;2: 3, 4, 5<br />
&emsp;&emsp;3: 2, 4, 5<br />
&emsp;&emsp;4: 2, 3, 5, 6<br />
&emsp;&emsp;5: 2, 3, 4, 6<br />
&emsp;&emsp;6: 4, 5<br />
&emsp;(3) 1: 2, 3, 6 であったから，2, 3, 6 のうち，最も小さい集合を持つ 6: 4, 5 を選択する．<br />
&emsp;&emsp; 1-6 となる．<br />
&emsp;(4) 隣接集合から 6 を削除する．その結果，次の隣接行列を得る．<br />
&emsp;&emsp;A∪B<br />
&emsp;&emsp;2: 3, 4, 5<br />
&emsp;&emsp;3: 2, 4, 5<br />
&emsp;&emsp;4: 2, 3, 5<br />
&emsp;&emsp;5: 2, 3, 4<br />
&emsp;(5) 6: 4, 5 であったが，4 も 5，どちらの隣接点の数も同じなので，ランダムにどちらかを選択<br />
&emsp;&emsp; する．ここでは，4 を選んだとする．1-6-4 となる．<br />
&emsp;(6) 隣接集合から 4 を削除する．その結果，次の隣接行列を得る．<br />
&emsp;&emsp;A∪B<br />
&emsp;&emsp;2: 3, 5<br />
&emsp;&emsp;3: 2, 5<br />
&emsp;&emsp;5: 2, 3<br />
&emsp;(7) 4: 2, 3, 5 であったが，いずれも隣接点の数が 2 と同じなので，ランダムにどれかを選択する．<br />
&emsp;&emsp; ここでは，3 を選んだとする．1-6-4-3 となる．<br />
&emsp;(8) 隣接集合から 3 を削除する．その結果，次の隣接行列を得る．<br />
&emsp;&emsp;A∪B<br />
&emsp;&emsp;2: 5<br />
&emsp;&emsp;5: 2<br />
&emsp;(9) 3: 2, 5 あったが，いずれも隣接点の数が 1 と同じなので，ランダムにどれかを選択する．<br />
&emsp;&emsp; ここでは，5を選んだとする．1-6-4-3-5となる．<br />
&emsp;(10)隣接集合から 5 を削除する．その結果，次の隣接行列を得る．<br />
&emsp;&emsp;A∪B<br />
&emsp;&emsp;2: φ<br />
&emsp;(11)したがって，1-6-4-3-5-2 が親個体 A と B のエッジ再結合交叉により作成された子個体となる．<br />
&emsp;上記のアルゴリズムから「交叉」の項の説明で見られたような致死遺伝子は子個体として発生しないことが分かる．</p>
<tr>
<h4>3. GEQO</h4>
<p style="margin-top: -12px;" ><strong>3.1 結合質問処理の最適化と GA</strong></p>
<p><img decoding="async" style="margin-top: -54px; width: 320px;" align="right" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/11/drmasunaga-10-P06-01c.png" alt="n!の大きさ" /></p>
<p style="margin-top: -14px;">
&emsp;ユーティッシュが GEQO を発想した根底には，結合質問処理の最適化は，それを忠実に行えば，そのための処理に指数時間かかる扱いづらい問題であるとの認識があったと考えられます．このことは，多くのことを語らなくても，すぐに実感できます．一般に，n 個のリレーションの自然結合 R<sub>1</sub>⋈R<sub>2</sub>⋈<sub> … </sub>⋈R<sub>n</sub> をとるとき，それらの結合を，たとえば (<sub>…</sub>.((R<sub>1</sub>⋈R<sub>2</sub>)⋈R<sub>3</sub>)⋈<sub>…</sub>⋈ R<sub>n-1</sub>)⋈R<sub>n</sub>) という具合に結合を左から右へ順番にとっていくとしただけでもリレーションの並び順は n!（n の階乗）通りあります．<font style="border-bottom:3px double blue">n!が </font>n の増加と共に，どれほど大きくなるかを<strong>図 2</strong> に示される通りですが，見ての通り n が大きくなるにつれて n! は爆発的に大きくなります．たとえば n=10 では 360 万通りを越え，n=15 では 1 兆 3 千万通りを超えています．多数のリレーションの結合質問処理の最適プランを馬鹿正直に見つけようとすると，大変なことになるだろうとは容易に想像がつきます．<br />
&emsp;次に指摘しておきたいことは，ユーティッシュは最適なリレーションの結合順を見つける問題と<strong>巡回セールスマン問題</strong>（travelling salesman problem, <strong>TSP</strong>）とが同根であることに着眼したことです．GA は TSP のような NP 困難な「組合せ最適化問題の準最適解を与える」ために大変有効な手法であることが知られています．最適解ではなく準最適解になることは，得られる解が初期集団（＝初期個体群）をどう選ぶかによるということです．上述の<strong>エッジ再結合交叉</strong>（edge recombination crossover, <strong>ERC</strong>）は TSP の準最適解を求めるのに特に適していることが知られていますが，ユーティッシュが GA を PostgreSQL に実装するにあたって ERC を採用したことは十分に理解できることです．<br />
</tr>
<p style="margin-top: +36px;"><strong>3.2 左深層木</strong><br />
&emsp;結合質問処理の最適化に GA を適用しようと考えると，結合質問の処理に一つ大きな制約が課せられます．それが，リレーションの結合は<strong>左深層木</strong>（left-deep tree）で示される順番で行われなくてはならないということです．<br />
&emsp;これはどういうことかを例題で見てみます．そこで，リレーションを R<sub>1</sub>(A, B)，R<sub>2</sub>(B, C, D)，R<sub>3</sub>(C, E)，R<sub>4</sub>(D, F)，R<sub>5</sub>(E, G) とし，それらの自然結合（natural join）をとる問合せを考えてみます．</p>
<p><center><img decoding="async" style="margin-top: -10px; width: 500px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/11/drmasunaga-10-P07-01a.png" alt="natural join" /></center></p>
<p>&emsp;この結合質問(1)の<strong>結合グラフ</strong>（join graph）は<strong>図 3</strong> に示される通りです．</p>
<p><center><img decoding="async" style="margin-top: -20px; width: 350px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/11/drmasunaga-10-P07-02a.png" alt="自然結合質問(1)の結合グラフ" /></center><br />
<center></p>
<p style="margin-top: -48px; "><b>図 3　自然結合質問(1)の結合グラフ</b></p>
<p></center></p>
<p>&emsp;さて，この結合質問(1)を処理するための {R<sub>1</sub>, R<sub>2</sub>, R<sub>3</sub>, R<sub>4</sub>, R<sub>5</sub>} の結合順はさまざまです．たとえば，<br />
R<sub>1</sub>⋈((R<sub>2</sub>⋈R<sub>4</sub>)⋈(R<sub>3</sub>⋈R<sub>5</sub>)) という結合順で結合をとることもできますが，(((R<sub>1</sub>⋈R<sub>2</sub>)⋈R<sub>3</sub>)⋈R<sub>4</sub>)⋈R<sub>5</sub> という結合順で結合をとることもできます．それらを木（tree）で表現してみると，前者は図 4(a)のように，後者は同図(b)に示されるようになります．このとき，図 4(a)のように表される木を<strong>低木</strong>（bushy tree）といい，同図 (b) のように表される木を<strong>左深層木</strong>といいます．GEQO は結合質問処理の最適化<br />
問題をあたかもよく知られている巡回セールスマン問題（TSP）のように扱うので，候補となった<br />
{R<sub>1</sub>, R<sub>2</sub>, R<sub>3</sub>, R<sub>4</sub>, R<sub>5</sub>} の結合順は 1’-2’-3’-4’-5’ ，つまり (((R<sub>1’</sub>⋈R<sub>2’</sub>)⋈R<sub>3’</sub>)⋈R<sub>4’</sub>)⋈R<sub>5’</sub> と表され，これすなわち左深層木ということです（ここに，i’∈{1, 2, 3, 4, 5}∧1’≠2’≠3’≠4’≠5’）．<br />
&emsp;なお，結合順は左深層木となったことにより，最適プラン<font style="border-bottom:3px double blue">は</font>本当<font style="border-bottom:3px double blue">は</font>低木で表される結合順であった<br />
かもしれないが，GEQO ではそれは仕方のないことということです．</p>
<p><center><img decoding="async" style="margin-top: -10px; width: 500px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/11/drmasunaga-10-P08-01a.png" alt="低木と左深層木" /></center><br />
<center></p>
<p style="margin-top: -48px; "><b>図 4　低木と左深層木</b></p>
<p></center></p>
<p><strong>3.3 GEQO の実装</strong><br />
&emsp;GA に基づく GEQO 実装の基本方針は次のようです．</p>
<p style="margin-top: -20px;" >&emsp;① </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
世代全体を置換するのではなく，母集団に最も適応しない個体を置換して世代を進める．その結果，問合せプランの改善に向けた迅速な収束が可能になる．これは，妥当な時間で問合せを処理するため不可欠である．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;② </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
GA による TSP 解決のためのエッジ再結合交叉 (ERC) を使用する．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;③ </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
正当な TSP ツアーを生成するための修復メカニズムが必要ないように，遺伝子演算子としての<strong>突然変異</strong>は非推奨とする．
</td>
</tbody>
</table>
<p></p>
<p style="margin-top: +48px;" >&emsp;少しばかり補うと，① は 2 章で述べた一般的な GA の適応度の概念に同じです．②は実装に「TSP 用に設計された GA アルゴリズム」として知られる GENITOR を使用しているので，交叉を「エッジ再結合交叉」を用いて行うということです．③ は「突然異変」の項で述べたことに通じる判断と考えられますが，<u>GEQO では突然異変は考えない</u>ということです．</p>
<p>&emsp;この基本方針の下での，GEQO の実装は，基本的に図 2 に示した GA のアルゴリズムの流れに沿ってなされていますが，より細かくは次の通りです．</p>
<p style="margin-top: -20px;" >&emsp;(a) </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
GEQO は各リレーションのスキャンをするときのコードは標準のプランナコードを使用する．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;(b) </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
結合プランは遺伝的アプローチで作成される．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;(c) </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
各結合プランは実リレーションの結合順で表現される．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;(d) </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
<font style="border-bottom:3px double blue">一番最初</font>のステージでは，GEQO は結合順を幾つかランダムに与える．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;(e) </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
各結合シークエンスのコストを PostgreSQL の標準プランナで推定する（この時，入れ子型ループ結合法，マージ結合法，ハッシュ結合法という 3 つの結合ストラテジ全て，並びにすべての予め決められていたリレーションスキャンのプランが勘案され，その中で最安のコストが推定コストとなる）．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;(f) </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
推定コストの低い方が「より適している」．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;(g) </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
GEQO は「最も適していない候補」（the least fit candidates），すなわち最も適応度の低い候補，を捨てる．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;(h) </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
残った候補の遺伝子を組み合わせて新しい候補を作る．すなわち，既知の低コストの結合シーケンスからエッジ再結合交叉を使用して新しいシーケンスを検討のために作成する．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;(i) </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
このプロセスを結合シークエンスが予め設定された数になるまで繰り返し，続いて，最良の結合シーケンスを見つけてそれを最終プランとする．
</td>
</tbody>
</table>
<p style="margin-top: +60px;" ><strong>3.4 GEQO のパラメタ</strong></p>
<p style="margin-top: -20px;" >&emsp;GEQO のパラメタは PostgreSQL 14.5 Documentation[12]に基づけば<strong>表 1</strong> の通りです．</p>
<p><center></p>
<p style="margin-top: -08px; "><b>表 1　GEQO のパラメタ</b></p>
<p></center><br />
<center><img decoding="async" style="margin-top: -48px; width: 700px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/11/drmasunaga-10-P09-01.png" alt="GEQO のパラメタ" /></center></p>
<p>&emsp;なお，PostgreSQL 14.5 Documentation に「GEQO は，ヒューリスティック検索を使用して問合せプランニングを行うアルゴリズムです．これにより，複雑な問合せ（多くのリレーションを結合する問合せ）のプラニング時間（planning time）が短縮されますが，作成されるプランは，通常の網羅的検索アルゴリズムによって検出されるプランよりも劣ることがあります」との記載があります．これは（突然異変は考えていないので）geqo_seed パラメタの値の設定によっては，GEQO を使わない通常の場合より悪いプランを出力してしまう可能性のあることを言っているのだと考えられます．</p>
<h4>4. GEQO の評価</h4>
<p style="margin-top: -18px;" ><strong>4.1 GEQO の評価の観点</strong></p>
<p style="margin-top: -18px;" >&emsp;GEQO は PostgreSQL 6.1 以降，現在に至るまでサポートされていますが，上記の qeqo パラメタを見るとき，GEQO の性能評価について，様々な観点が浮かび上がってきます．たとえば，次の通りです．</p>
<p style="margin-top: -20px;" >&emsp;(a) </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
geqo_threshold については，geqo_threshold=12 がデフォルトと設定されていますが、その妥当性の検証．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;(b) </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
geqo_generations の数はどれほどに設定すればよいのか，その数の検証．
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;(c) </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
geqo_seed の値の設定．「さまざまな検索パスを試すには，geqo_seed を変更してみてください」とあるが，一体どれぐらい試せばよいのか？これは最初に与えるランダムな結合シークエンスを何個に指定するかということであるが，この数は結合するリレーションの数や各リレーションのアクセスパスなどにより変化するのではないか？
</td>
</tbody>
</table>
<p style="margin-top: -20px;" >&emsp;(d) </p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
GEQO の収束条件はどのように設定されているのか？
</td>
</tbody>
</table>
<p>&emsp;なお，geqo_threshold については，「FULL OUTER JOIN の生成子は，1 つの FROM 項目として計算することに注意してください」との注意書きが添えられています．これは， T1 FULL OUTER JOIN T2 を，まず T1 と T2 の内部結合を行い，その後，T2 のどの行の結合条件も満たさない T1 の各行については，T2 の列を NULL 値として結合行を追加し，さらに，T1 のどの行でも結合条件を満たさない T2 の各行に対して，T1 の列を NULL 値として結合行を追加して求めているという PostgreSQL の内部処理の事情を反映してのことでしょう．</p>
<p><strong>4.2 GEQO の性能評価</strong><br />
&emsp;かつて Petković[13]により GEQO の性能評価が報告されています．この報告は 2010 年になされており，性能評価に使用された PostgreSQL の version も 8.4 と古いので，最近の PostgreSQL の GEQO の性能を評価する参考になるのか不安になり調査したところ，次に示すように，当時の GEQO がほぼそのまま PostgreSQL 14 でも稼働しているようなので，Petković による報告には一顧の価値があると考え，それを紹介することとします．<br />
&emsp;その古き GEQO と最新の GEQO の比較調査の結果ですが，まず，PostgreSQL 8.4.22 文書（documentation）[14]にあたってみると，「49.3.2. PostgreSQL GEQO の今後の実装作業」という項目に“遺伝的アルゴリズムの<font style="border-bottom:3px double blue">パラメータ</font>設定を改善するためにはまだ課題が残っています”として当時の実装の問題点を記載しています．一方，最新の PostgreSQL 14.5 文書[12]にあたってみると，そこにも「60.3.2. PostgreSQL GEQO の今後の実装作業」という項目があり， PostgreSQL 8.4 当時と一字一句変わらぬ文が記載されています．つまり，（プランナ本体にはこれまで幾つか改善がなされてきたのでしょうが）GEQO 自体に PostgreSQL 8.4 で指摘された改善点がこれまで施された様子は見受けられません．なお，GEQO について PostgreSQL 8.4 と PostgreSQL 14.5 で唯一記述に変更のあった部分は，<br />
PostgreSQL 8.4 文書の「49.3.1. Generating Possible Plans with GEQO」の末尾の文 “Hence different plans may be selected from one run to the next, resulting in varying run time and varying output row order.” が，PostgreSQL 14.5 文書の「60.3.1. Generating Possible Plans with GEQO」では，“To avoid surprising changes of the selected plan, each run of the GEQO algorithm restarts its random number generator with the current geqo_seed parameter setting. <font style="border-bottom:3px dotted blue">As long as</font> geqo_seed and the other GEQO parameters are kept fixed, the same plan will be generated for a given query (and other planner inputs such as statistics). To experiment with different search paths, try changing geqo_seed.” と変更になっているだけです．ただ，これは上記 4.1 節の(c)項に関する記述変更で，<br />
GEQO 本体レベルの変更ではないと推察され，GEQO の実装は現在も当時のままのようです．<br />
&emsp;さて，その報告では，2 つの実験結果が示されており，それらは 4.1 節の(a)項と(b)項に対応して<br />
いるようです．一つは，geqo パラメタで，GEQO を有効としたときと無効としたときの結合質問の<br />
実行時間の比較です．PostgreSQL 8.4 では実行時間は total run time を意味するので，プランナが<br />
消費した時間と最適プランをエグゼキュータがその実行に消費した時間を個別に評価することは<br />
できず，2 つを足し合わせた時間です．もう一つは，GEQO を有効としたとき，GEQO アルゴリズムの反<font style="border-bottom:3px double blue">復数（geqo_generations）</font>，つまり世代数の変化が結合質問の処理時間に与える効果です．これは，世代数を大きくすれば，結合プランの質が高まり，その結果，結合質問の処理速度が向上するだろうことを期待した検証といえます．<br />
&emsp;まず，実験を行うには，結合数が 10 を超えるような結合質問を多数用意する必要がありますが，<br />
PostgreSQL 8.4 の元々のサンプルデータは 6 枚のテーブルしか持っていないので，大きな結合を試せず，MS SQL Server システムのサンプルデータである Adventure Works 2008 を PostgreSQL にインポートして使用したと報告しています．そこには 60 枚以上のテーブルがあるとのことで，そのうちの幾つかを<strong>表 2</strong> に示します．評価にどのようなテーブルが使われたのか，それをイメージしていただければよいかと思います．</p>
<p><center></p>
<p style="margin-top: -08px; "><b>表 2　実験に使われたテーブル（の一部）</b></p>
<p></center><br />
<center><img decoding="async" style="margin-top: -48px; width: 680px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/11/drmasunaga-10-P12-01a.png" alt="実験に使われたテーブル（の一部）" /></center></p>
<p>&emsp;テストのための問合せは<strong>表 3</strong> に示される “generic query”（一般的問合せ）を考え，それから他の問合せを導出し，最大 14 個の結合演算を含む 18 個の問合せを作成して走らせたと報告しています．</p>
<p><center></p>
<p style="margin-top: -08px; "><b>表 3　実験に使われた結合質問（一般的問合せ）</b></p>
<p></center><br />
<center><img decoding="async" style="margin-top: -48px; width: 680px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/11/drmasunaga-10-P13-01a.png" alt="実験に使われた結合質問（一般的問合せ）" /></center></p>
<p>&emsp;この内結合質問は 13 個のテーブルを使い，そこでは 12 個の結合演算が定義されています．ちなみに，この問合せの「結合グラフ」を作成してみると<strong>図 5</strong> のように描けます．</p>
<p><center><img decoding="async" style="margin-top: -12px; width: 450px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/11/drmasunaga-10-P13-02a.png" alt="実験に使われた結合質問の結合グラフ" /></center><br />
<center></p>
<p style="margin-top: -28px; "><b>図 5　実験に使われた結合質問の結合グラフ</b></p>
<p></center></p>
<p>&emsp;GEQO はこの結合グラフを基に，左深層木で表される線形順序の結合プランを幾つかランダムに生成して初期集団を作成し，GENITOR に入力しているということになります．幾つもの左深層木が定義できます．興味を抱いた読者は試してみてください．</p>
<p>&emsp;続いて，実験結果を紹介します．</p>
<p><strong>【実験結果１】GEQO モジュール vs. 全数探索</strong><br />
&emsp;PostgreSQL が GEQO を無効にして，つまり全数探索（exhausted search）にて結合質問処理の最適化を行った場合の問合せの実行時間と GEQO モジュールを有効にして結合質問処理の最適化を行った場合の問合せの実行時間の比較を行います．なお，全数探索（exhausted search）という用語を PostgreSQL 14.5 文書[12]も Petković[13]も用いていますが，プランナは n 個のテーブルの結合の<br />
コスト最小プランを見つけるために n! 個の結合順すべてにあたっているわけではなく，コストベー<br />
スアプローチ（＝DP アプローチ）でそれを行っているので，全数検索というよりはコストベース<br />
アプローチと表現するほうが適切でしょう．<br />
&emsp;さて，比較の対象とした問合せは，11，12，13，14 個のテーブル結合を有します．<strong>図 6</strong> はそれら<br />
の問合せ全てに対する平均実行時間を結合するべきテーブルの数でまとめています．各結合数に対し<br />
て，左側の縦棒は GEQO が有効，右側が無効のときを表します．図から分かるように，両者は結合<br />
演算の数が 12 までは互角です．しかしながら，12 を超えると，GEQO はコストベースアプローチ<br />
（＝GEQO が無効）に比べて約 15% 越えの効果を発揮しています．実験では，14 を超える場合を<br />
検証していませんが，同様な効果が期待できると報告しています．つまり，テーブルの結合数が 13<br />
以上の場合，GEQO を有効にすると，無効にしていた時と比べて少なくとも 15% 速く結合質問が<br />
処理されるであろう，ということです．PostgreSQL 14.5 文書は geqo_threshold=12 で GEQO に<br />
切り替わるとしていますが，geqo_threshold=13 でよいということになります．なお，この実験で<br />
は，世代数 geqo_generation を幾つに設定したのか記載がありませんが，もしデフォルトで実験を<br />
行ったとすれば geqo_generation=0 なので，その場合，表 1 に記されたように，geqo_pool_size <br />
に基づいて適切な値が選択されているということになります．</p>
<p><center><img decoding="async" style="margin-top: -20px; width: 620px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/11/drmasunaga-10-P15-01a.png" alt="GEQO モジュールとコストベースアプローチの比較[13]" /></center><br />
<center></p>
<p style="margin-top: -28px; "><b>図 6　GEQO モジュールとコストベースアプローチの比較<sup>[13]</sup></b></p>
<p></center></p>
<p><strong>【実験結果２】世代数を増していった時の効果</strong><br />
&emsp;GEQO を有効とした場合，結合質問の実行時間を GEQO アルゴリズムの反<font style="border-bottom:3px double blue">復数（geqo_generations）</font>，つまり世代数をパラメタに比較しています．geqo_generation パラメタを 1，すなわち世代数を 1 から始めて，13 まで検証した結果が<strong>図 7</strong> です．図が示しているように，世代数を大きくするにつれて，オプティマイザはより最適な実行プランを求めることができて，結合質問の実行時間は減少していくことを示しています．geqo_generation=1 では問合せ 1 個当たりの平均実行は最適の場合に比べて約 25％ 余計にかかっていることが示されています．世代数を 9 世代，すなわちgeqo_generation=9 で最適値に収束するようです．したがって，そのように設定しておくとよいのかもしれません．</p>
<p><center><img decoding="async" style="margin-top: -20px; width: 620px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/11/drmasunaga-10-P16-01a.png" alt="世代数の変更の効果[13]" /></center><br />
<center></p>
<p style="margin-top: -28px; "><b>図 7　世代数の変更の効果<sup>[13]</sup></b></p>
<p></center></p>
<h4>5．おわりに</h4>
<p style="margin-top: -18px; ">&emsp;PostgreSQL の結合質問処理の最適化モジュールである GEQO を概観しました．PostgreSQL 14.5 では geqo_threshold パラメタで GEQO を発動するリレーションの結合の数のデフォルトは 12 と定めていますが，紹介した実験結果によればその数は 13 のようです．あまり大した差ではありませんが，そこら辺が目安ということなのでしょう．<br />
&emsp;改めて言うまでもありませんが，リレーショナルデータベースの最大の特徴はデータベース言語 SQL が<strong>非手続き的</strong>（non-procedural）であるところにあり，それが故に質問処理の最適化は永遠の課題でもあります．質問処理最適化の研究・開発は機械学習の適用で一段と深まりを見せ，佳境に入った感があります．今後の理論展開と実践に注目し続けたいと思います．</p>
<p>　</p>
<p><strong>【文献】</strong></p>
<p style="margin-top: -10px;" >[1]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Patricia Selinger, M. Astrahan, D. Chamberlin, Raymond Lorie, and T. Price. “Access Path Selection in a Relational Database Management System.” <span style="font-style: italic;" >Proceedings of ACM SIGMOD (1979)</span>, pp. 23-34, 1979.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[2]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Martin Utesch. Chapter 60. Genetic Query Optimizer, PostgreSQL 14 Documentation, The PostgreSQL Global Development Group, 2022.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[3]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Tomas Kovarik and Julius Stroffek. Execution plan optimization techniques. <span style="font-style: italic;">PGcon 2007</span>.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[4]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Jan Urbański. Replacing GEQO &#8211; Join ordering via Simulated Annealing. <span style="font-style: italic;">PGCon 2010</span>.<br />
<a href="https://www.pgcon.org/2010/schedule/events/211.en.html" target="_blank" rel="noopener noreferrer">https://www.pgcon.org/2010/schedule/events/211.en.html</a>
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[5]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Oleg Ivanov. Adaptive query optimization in PostgreSQL. <span style="font-style: italic;">PGCon 2017</span>.<br />
<a href="https://www.pgcon.org/2017/schedule/events/1086.en.html" target="_blank" rel="noopener noreferrer">https://www.pgcon.org/2017/schedule/events/1086.en.html</a>
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[6]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Miguel Rodríguez, Daladier Jabba, Elias Niño, Carlos Ardila and Yi-Cheng Tu. Automata Theory based Approach to the Join Ordering Problem in Relational Database Systems. <span style="font-style: italic;">Proceedings of the 2nd International Conference on Data Technologies and Applications</span> (DATA-2013), pp.257-265, 2013.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[7]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Ryan Marcus, Parimarjan Negi, Hongzi Mao, Chi Zhang, Mohammad Alizadeh, Tim Kraska, Olga Papaemmanouil, Nesime Tatbul. Neo: A Learned Query Optimizer, <span style="font-style: italic;">Proceedings of the VLDB Endowment</span>, pp.1705-1718, 2019.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[8]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
John Henry Holland. Adaptation in Natural and Artificial Systems (book). MIT Press, 1975.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[9]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Eyal Wirsansky. Hands-On Genetic Algorithms with Python: Applying genetic algorithms to solve real-world deep learning and artificial intelligence problems, Packt Publishing, 2020.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[10]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Darrell Whitley. The <span style="font-style: italic;">GENITOR</span> Algorithm and Selection Pressure: Why Rank-Based Allocation of Reproductive Trials is Best. <span style="font-style: italic;">Proceedings of the Third International Conference on Genetic Algorithms (ICGA-89)</span>, pp. 116-121, Morgan Kaufmann Publishers Inc., San Francisco, 1989.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[11]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Wikipedia (en). Edge recombination crossover.<br />
<a href="https://en.wikipedia.org/wiki/Edge_recombination_operator" target="_blank" rel="noopener noreferrer">https://en.wikipedia.org/wiki/Edge_recombination_operator</a>
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[12]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
The PostgreSQL Global Development Group. PostgreSQL 14.5 Documentation.<br />
<a href="https://www.postgresql.org/files/documentation/pdf/14/postgresql-14-A4.pdf" target="_blank" rel="noopener noreferrer">https://www.postgresql.org/files/documentation/pdf/14/postgresql-14-A4.pdf</a>
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[13]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Dušan Petković. Comparison of Different Solutions for Solving the Optimization Problem of Large Join Queries. <span style="font-style: italic;">Proceedings of the 2010 Second International Conference on Advances in Databases, Knowledge, and Data Applications</span>, pp.51-55, 2010.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[14]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
PostgreSQL 8.4.22 Documentation. Chapter 49. Genetic Query Optimizer.  49.3. Genetic Query Optimization (GEQO) in PostgreSQL. 49.3.2. Future Implementation Tasks for PostgreSQL GEQO.<br />
<a href="https://www.postgresql.org/docs/8.4/geqo-pg-intro.html#GEQO-FUTURE" target="_blank" rel="noopener noreferrer">https://www.postgresql.org/docs/8.4/geqo-pg-intro.html#GEQO-FUTURE</a>
</td>
</tbody>
</table>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>増永教授のDB特論⑨「NULL」</title>
		<link>https://www.sraoss.co.jp/tech-blog/db-special-lecture/masunaga-db-special-lecture-9/</link>
		
		<dc:creator><![CDATA[増永良文 (Yoshifumi Masunaga)]]></dc:creator>
		<pubDate>Wed, 12 Oct 2022 04:00:04 +0000</pubDate>
				<category><![CDATA[増永教授のDB特論]]></category>
		<category><![CDATA[NULL]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[RDB]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[リレーショナルデータベース]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=11123</guid>

					<description><![CDATA[&#160; 1. はじめに &#8195;Null という語，データベースに携わっている人なら見たことないという人はいないと思いますが，なんと発音していますか？ &#8195;「ヌル」って言うのだよ，と誰が教えたのでしょう ...]]></description>
										<content:encoded><![CDATA[<p>&nbsp;</p>
<h4>1. はじめに</h4>
<p style="margin-top: -10px;">
&emsp;Null という語，データベースに携わっている人なら見たことないという人はいないと思いますが，なんと発音していますか？<br />
&emsp;「ヌル」って言うのだよ，と誰が教えたのでしょうか？結構，皆さん，ヌル，ヌル，って言っています．違う<font style="border-bottom:3px double blue">ん</font>ですねー．「<strong>ナル</strong>」って発音するのです．英語の発音記号は nʌ&#8217;l です．英語の発音を日本語で書き表すのは難しいですが，決してヌルではありません．英語を母国語とする人にヌルと言ったら，多分首を傾げると思いますよ．ナルって言いましょう．<br />
&emsp;さて，ナル（null）は「値がない」（having no value）という意味ですね．これに異議ありという方は多分いないと思います．では，リレーショナルデータベースでナルはどのような時にどのように使われているのでしょうか？なんで今さらそんなことを聞いているの？といぶかしげな読者の顔が浮かびますが，ナルに関しては<ruby>蘊蓄<rt style="background-color: white;">うんちく</rt></ruby>を傾ければきりがなく，理論面でも実践面でも不明確なところが多々あり，議論しだしたらきりがないのかなといった感じです．しばしナル談議に<ruby>耽<rt style="background-color: white;">ふけ</rt></ruby>ってみたいと思います．</p>
<p><span id="more-11123"></span></p>
<h4>2. NULL とは</h4>
<p style="margin-top: -10px;"><strong>2.1　ANSI/X3/SPARC によるナルの顕現</strong><br />
&emsp;皆さん，<ruby>ANSI<rt style="background-color: white;">アンシー</rt></ruby>/X3/<ruby>SPARC<rt style="background-color: white;">スパーク</rt></ruby>はご存じでしょうか？American National Standards Institute/Committee on Computers and Information Processing/Standards Planning And Requirements Committee の略称です．米国国家規格協会（ANSI）の下にあるこの委員会は 1975 年に DBMS の標準アーキテクチャとして名高い「3 層スキーマ構造」を提案した報告書[1]を世に出した団体としてとても有名ですが，その報告書の中で概念スキーマレベルのドメイン関連事項として，<Strong>ナルの意味</strong>は 14 種に上るという報告をしています．このように，ナルはデータベースに係る諸活動の極めて初期から関心が高かったわけです．原義を損ないたくないので，ナルの 14 種の意味を原文のまま引用すると下記の通りです．目を通してみると分かると思いますが，ナルが出現する状況を実にさまざまな観点からピックアップしています．興味を持った方はぜひ一つひとつにあたってみてください．最後の (14)項で，“Derived from null conceptual data (any of the above)”と締め括っているので，トータル 14 種ということです．</p>
<p><strong><u>Manifestation of null</u></strong>（ナルの顕現）</p>
<p style="margin-top: -10px;" >(1)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Not valid for this individual (e.g., maiden name of male employee).
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >(2)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
<font style="border-bottom:3px double blue">Valid, but</font> does not yet exist for this individual (e.g., married name of female unmarried employee).
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >(3)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Exists, but not permitted to be logically stored (e.g., religion of this employee).
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >(4)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Exists, but not knowable for this individual (e.g., last efficiency rating of an employee who worked for another company).
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >(5)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Exists, but not yet logically stored for this individual (e.g., medical history of newly hired employee).
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >(6)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Logically stored, but subsequently logically deleted.
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >(7)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Logically stored, but not yet available.
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >(8)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
<font style="border-bottom:3px double blue">Available, but</font> undergoing change (may be no longer valid).
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >(9)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Available, but of suspect validity (unreliable).
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >(10)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Available, but invalid.
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >(11)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Secured for this class of conceptual data.
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >(12)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Secured for this individual object.
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >(13)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Secured at this time.
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >(14)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Derived from null conceptual data (any of the above).
</td>
</tbody>
</table>
<p style="margin-top: -10px;"><strong>2.2　E.F. Codd によるナルと 3 値論理の導入</strong><br />
&emsp;では，リレーショナルデータモデルではナルはどのように定義されているのでしょうか？それはリレーショナルデータモデルの始祖コッド（Edgar F. Codd）の 1979 年の論文[2]に見ることができます．そこでは，<strong>ナル</strong>と<strong>ナル値</strong>（null value）という用語が出現しますが，それらは次のように与えられています．<br />
&emsp;まず，主キーの値はナルであってはいけないというルールの提唱があります．これはキー制約として知られていることで，もっともなことです．続いて，ナル値の最も重要なタイプは 2 つあって，それらは “<strong>value at present unknown</strong>”（値は現時点で未知）と“<strong>property inapplicable</strong>”（不適当なプロパティ）という意味を持つと述べています．そのうえで，ナル値を許すとリレーショナル代数を拡張しなければならないが，拡張のためには前者の “value at present unknown” に関心があるとし，それを “ω” で表して，いわゆる 3 値論理を展開しました．<br />
&emsp;本稿は，コッドは「ナル」をどう捉えたのかに焦点を当てて議論することが狙いなので 3 値論理や<br />
一般に多値論理の議論には深入りしませんが，リレーショナル代数を 3 値論理に拡張するにあたり，<br />
value at present unknown，すなわちナル（ω）を許したときに，リレーショナル代数を構成する 8 つの演算，つまり 4 つの集合演算（和，差，共通，直積）とリレーショナル代数に特有な 4 つの演算（射影，選択，結合，商）をどのように定義し直すべきかという問題だけは復習しておきたいと思います．これについて，まず，4 つの集合演算と射影は集合意味論のもとで素直に拡張できます．問題は，選択演算です．選択演算での “ω” の扱いが決まれば，結合は直積と選択，商は直積と射影と差を用いて定義できるので特段の問題は生じません．そこで，属性が ω をとる場合に選択演算がどのように拡張されることになるのか，それを見てみましょう．<br />
&emsp;そこで，<strong>値式</strong> x, y に対して，<strong>述語</strong> xθy，ここに θ は比較演算子（＝，＜，≦，＞，≧，≠），がどのような真理値をとるかを見ていきます．従来のリレーショナルデータモデルの 2 値論理の場合と同じく，x と y が共にナルでなければそれは真（true，T）か偽（false，F）をとります．では x または y ，あるいはその両方がナルとなる場合，述語 xθy はどのような真理値をとるのでしょうか？これに対してコッドは，<strong>不定</strong>（unknown）をとるとしました．そして，<strong>述語 xθy の真理値表（3 値論理）</strong>を<strong>表 1</strong> に示したように定義しました．表示されているように，コッドは，ω を「値は現時点で未知」を表すだけでなく「不定」という真理値を表すためにも使用しました．こうすることで，「不定」という真理値をデータベースに格納することができ，かつすべての「不定」や「値は現時点で未知」の処理を統一的に行えるとしました．</p>
<p><center></p>
<p style="margin-top: -10px;"><b>表 1　述語 xθy の真理値表（3 値論理）</b></p>
<p></center><br />
<center><img decoding="async" style="margin-top: -48px; width: 450px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P03-01.png" alt="述語 xθy の真理値表（3 値論理）" /></center><br />
<center></p>
<p style="margin-top: -48px; ">x, y は現実値（real value）．θ は比較演算子</p>
<p></center></p>
<p>&emsp;では，真（T）か偽（F）か不定（ω）をとる 3 値論理はどのような真理値表を有するのでしょうか？それが<strong>表 2</strong> に示される <strong>3 値論理の真理値表</strong>（NOT ブール演算子のための真理値表，AND ブー<br />
ル演算子のための真理値表，OR ブール演算子のための真理値表）です．一般に 3 値論理の定義は<br />
ただ一つというわけではありませんが，表 2 で与えられた定義はクリーネ（S. C. Kleene）の 3 値<br />
論理の真理値表と同一となっています．</p>
<p><center></p>
<p style="margin-top: -10px;"><b>表 2　3 値論理の真理値表</b><sup>[2]</sup></p>
<p></center><br />
<center><img decoding="async" style="margin-top: -48px; width: 660px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P03-02.png" alt="3 値論理の真理値表[2]" /></center></p>
<p>&emsp;以上の結果を使うと，NOT，AND，OR で結合された一般的な述語の真理値を求めることができます．たとえば， 5≦2 OR 5=ω の真理値は，述語 5≦2 の真理値が F，述語 5=ω の真理値が ω なので，OR ブール演算子のための真理値表を見ることで，5≦2 OR 5=ω の真理値は ω であることが分<br />
かります．<br />
&emsp;そうすると，<strong>表 3</strong> に示す <strong>IS ブール演算子真理値表</strong>を定義することができ，それにより探索条件が TRUE であるのか，FALSE であるのか，UNKNOWN であるのかを決定することが可能となります．<br />
たとえば，5≦2 OR 5=ω IS UNKNOWN という述語，すなわち探索条件，の真理値は 5≦2 AND 5=ω <br />
の真理値が ω なので真であるという具合です．</p>
<p><center></p>
<p style="margin-top: -10px;"><b>表 3　IS ブール演算子真理値表（3 値論理）</b></p>
<p></center><br />
<center><img decoding="async" style="margin-top: -48px; width: 550px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P04-01.png" alt="IS ブール演算子真理値表（3 値論理）" /></center></p>
<p>&emsp;以上の枠組みのもとで，コッドは従来のリレーショナルデータモデルが依って立つ 2 値論理のと<br />
きの θ -選択演算や θ -結合演算の自然な拡張として，3 値論理のための<strong>推量 θ-選択演算</strong>（maybe θ-selection operation）と<strong>推量 θ-結合演算</strong>（maybe θ-join operation）を定義しました（従来の<br />
演算は推量演算と区別するために真正（true）という接頭辞を付けられて区別されます）．ここに，<br />
maybe（推量）は「真理値が真でもなく偽でもなく，おそらく真でありおそらく偽であるのだが，<br />
DBMS はどちらが成立するのかは知らない」を意味します．推量 θ -選択演算の定義は次の通りで<br />
す．なお，推量 θ -結合演算の定義は直積と推量θ-選択演算の定義を使って与えることができますが，詳細に関心のある者は文献[2]や拙著[3]を参照してください．</p>
<p><strong>【定義１】（</strong>推量 θ -選択演算）<br />
&emsp;R(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) をリレーションとする．A<sub>i</sub> と A<sub>j</sub> を θ-比較可能とするとき，R の属性 A<sub>i</sub> と A<sub>j</sub> 上の推量 θ-選択，これを R[A<sub>i</sub>θω<sub> </sub>A<sub>j</sub>] と表す，は次にように定義されるリレーションである．<br />
&emsp;R[A<sub>i</sub>θω<sub> </sub>A<sub>j</sub>]={t|t∈R∧t[A<sub>i</sub>]θt[A<sub>j</sub>] IS UNKNOWN}</p>
<p><strong>【例題１】（</strong>推量 θ -選択演算）<br />
&emsp;リレーション R(A, B, C)={(1, 5, 3), (2, 3, 8), (3, 2, null), (4, null, 6), (5, null, null)} としたときの，<br />
R の B，C 上の真正大なり -選択 R[B＞C] と推量大なり -選択 R[B＞<sub>ω</sub>C] の結果は次のようになる．<br />
R[B＞<sub>ω</sub>C]の結果が下記のようになることは，5＞3=真（T），3＞8=偽（F），2＞null=不定（ω），<br />
null＞6=不定（ω），null＞null=不定（ω）であるので，2＞null，null＞6，null＞null の場合<br />
でのみ t[B] θ t[C] IS UNKNOW が真となることから分かる．<br />
&emsp;R[B＞C]={(1, 5, 3)}<br />
&emsp;R[B＞<sub>ω</sub>C]={(3, 2, null), (4, null,6), (5, null, null)}</p>
<p>&emsp;なお，この 3 値論理の議論で興味深いことは，コッドが value at present unknown を表す ω は<br />
いつでも<strong>非ナル値</strong>（nonnull value）をとれる<strong>プレースホルダ</strong>（placeholder）と考えるのがよいだ<br />
ろうとも述べていることです．ナルはあくまでナルであってナル値という概念はないのだよと日頃<br />
から言っている筆者にとっては，ここが大変微妙に感じられるところです．つまり，ω はナル<ruby>値<rt style="background-color: white;">・</rt></ruby>だ<br />
と言いながら一方でプレースホルダ，つまり値では<ruby>なく<rt style="background-color: white;">・・</rt></ruby>単なる「標識」だと言っているわけで，<br />
コッドがオックスフォード大学の数学科出身であることを考えるとき，数学的厳密さからは，<br />
彼自身，「ナルは値なの？そうではないの？」と，この相反する概念規定にいささかの葛藤が<br />
あったのではないか，と想像するわけです．</p>
<p><strong>2.3　E.F. Codd によるナルと 4 値論理の導入</strong><br />
&emsp;3 値論理の導入後，コッドはナルの意味をより豊富に捉えて，それをリレーショナル DBMS は<br />
サポートするべきであるとし，4 値論理を提案[4, 5]したことはよく知られている通りです．ただ，<br />
4 値論理の議論は時期尚早としてそれ以上の議論は行いませんでしたが，そこでは，真理値として，<br />
t (true)，i (missing and inapplicable)，a (missing and applicable)，f (false)の 4 つを導入し，<br />
<strong>表 4</strong> に示される <strong>4 値論理の真理値表</strong>を与えています[5]．</p>
<p><center></p>
<p style="margin-top: -10px;"><b>表 4　4 値論理の真理値表</b></p>
<p></center><br />
<center><img decoding="async" style="margin-top: -48px; width: 650px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P05-01.png" alt="4 値論理の真理値表" /></center></p>
<p>&emsp;この真理値表は一見すると表 2 に示した T，F，ω を擁する3値論理の真理値表の素直な拡張になっているように見えますが，注意深く見てみると OR ブール演算子のための真理値表の f 行 i 列，つまり f OR i の真理値が i ではなく f となっています（対称的に，i 行 f 列，つまり i OR f についても同様です）．このことについて，論文[5]に 4 値論理の真理値表を表 4 のように定義した論拠は一切示されていないのでその理由を知ることはできませんが，この真理値表の直下に，次のような注意書きを与えています（原義を損なわないために<font style="border-bottom:3px double blue">原文のママ引用します</font> ）．</p>
<p style="margin-top: -10px;" >&emsp;&emsp;&emsp;</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
“Note that we obtain the truth table of the TRI/EFC-4 three-valued logic<br />
by replacing i by m and a by m (where m simply stands for missing, and<br />
the reason for anything being missing is ignored).”
</td>
</tbody>
</table>
<p>
&emsp;TRI/EFC-4 とはコッドが立ち上げた研究機関 The Relational Institute (TRI) で E.F. Codd (EFC) が<br />
書いた 4 番目の論文 “Missing Information in Relational Databases: Applicable and Inapplicable”, February 21, 1986 を指しています．コッドはこの注意書きで，i と a を共に m に置き換えると，<br />
表 2 に示した 3 値論理の真理値表が得られるというのですが，実際それを行ってみると，3 値論<br />
理の NOT ブール演算子のための真理値表と AND ブール演算子のための真理値表は得られますが，<br />
OR ブール演算子のための真理値表は得られません（読者の皆さんも容易に確かめることができる<br />
と思います）．OR ブール演算子のための真理値表が i と a を共に m に置き換えることで得られる<br />
ためには，f 行 i 列，つまり f OR i の真理値は f ではなく i でないといけません（対称的に，i 行<br />
f 列，つまり i OR f についても同様です）．ただ，一般に多値論理の定義には多様性があり，たと<br />
えばベルナップ（Nuel D. Belnap, Jr.）の定義した 4 値論理 <strong>A4</strong> や <strong>L4</strong> の真理値表はコッドの定義<br />
した真理値表（表 4）とは異なります． 筆者は「i と a を共に m に置き換えると，云々」という<br />
箇所にこだわり，表 4 に疑問符を投げかけましたが，それにこだわらなければ表 4 でよいのかも<br />
しれません．コッドが没してしまった今となっては，本人にその真意を問うことはできませんが，<br />
もし 4 値論理をリレーショナルデータベースに実装しようとするのであれば，解決を迫られる避け<br />
ては通れない問題だろうと考えられます．</p>
<p><strong>2.4　SQL でのナル</strong><br />
&emsp;国際標準リレーショナルデータベース言語 SQL でのナルに対する立ち位置はどのようでしょうか？メルトン（J. Melton）らの著書[6]に次のような説明があります．ちなみに，メルトンは SQL-92 や SQL:1999 の編集者（editor）で，SQL の策定に多大な影響力を持っている人として知られています．ここで述べるナルに対する SQL のスタンスは最新規格SQL:2016[7]でも変わっていません．</p>
<p style="margin-top: -10px;" >&emsp;&emsp;&emsp;</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
『SQL ではデータ項目が現実値（real value）を持たない場合にフラグのようなもの<br />
（a sort of flag）を格納します．そして，現実値が提供されていないことを示す<br />
フラグが設定されているとき，そのデータ項目はナル値を持つといいます』
</td>
</tbody>
</table>
<p>
&emsp;若干補足すると，SQL ではデータ項目は非ナル値（non-null value）かナル値をとります．ナル値<br />
は “not available”（入手不可），“not applicable”（適用不可）,“unknown”（未知）を表すために使用<br />
され，キーワード NULL を導入してナル値を表します．ナル値はいかなるデータ型の値でもないので，<br />
もし NULL にあるデータ型を関連付けたいのであれば CAST(NULL AS datatype) 句で明示的にデータ<br />
型と関連付けます．<br />
&emsp;つまり，SQL ではデータ項目が現実値を持たないことを NULL で表すとしているわけですが，それをナル<ruby>値<rt style="background-color: white;">・</rt></ruby>と言ってしまったので，あたかもナルという値があるかのような表現になっています．したがって，ここでもコッドが直面したであろう葛藤が読み取れて，現実値が<ruby>ない<rt style="background-color: white;">・・</rt></ruby>のにあたかも「ナルという値」が<ruby>ある<rt style="background-color: white;">・・</rt></ruby>かのように言ってしまう．．．この<ruby>可笑<rt style="background-color: white;">おか</rt></ruby>しさについては SQL を策定した当事者自身もどうも気にしていたようで，メルトンらは上記の著書[6]で次のように釈明しています．言うまでもありませんが，this phrase とは上記の説明文のことです．<br />
</p>
<p style="margin-top: -10px;" >&emsp;&emsp;&emsp;</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
“This phrase is probably a misleading, because null means that there is no “real” value<br />
at all; nevertheless, it’s a convenient shorthand that you will often find in use.”
</td>
</tbody>
</table>
<p>
&emsp;こんな釈明をするぐらいならば，次のような一貫した姿勢をとった方がどれだけすっきりした体系となっただろうにと，筆者は常々思うわけです．</p>
<p style="margin-top: -10px;" >&emsp;&emsp;&emsp;</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
『値がないことを NULL で表す．あくまで NULL は標識であって，ナル値という概念はない』
</td>
</tbody>
</table>
<h4>3. ナルの意味の体系化</h4>
<p>&emsp;前章で示したごとく，ANSI/X3/SPARC はナルに対して 14 種の意味を，コッドはナル値に “value<br />
at present unknown” と “property inapplicable” という 2 つの意味を，SQL はナルに “not available”<br />
（入手不可），“not applicable”（適用不可）,“unknown”（未知）という 3 つの意味を与えています．<br />
&emsp;問題は，それぞれがそれぞれの思惑からナル（値）の定義を与えていますが，データベースでナルを中途半端ではなく<ruby>きちんと<rt style="background-color: white;">・・・・</rt></ruby>取り扱うためには，<strong>ナルの意味の健全かつ完全な体系化</strong>が必要となります．ここに，健全（sound）であるとは，その体系において構文論的に証明できる命題は意味論的に成り立つことをいい，完全（complete）であるとは意味論的に成り立つ命題は構文論的に証明できることを<br />
意味します．以下で議論するように，この意味で，ANSI/X3/SPARC，コッド，そして SQL のナルの<br />
取り扱いは不十分だということです．</p>
<p><strong>3.1　コッドによるナルの意味の体系</strong><br />
&emsp;さて，コッドが 4 値論理の議論で与えたナルの分類が完全なように見えるかもしれません．しかし，以下に示すようにそうではありません．コッドは，ナル値の最も重要なタイプは 2 つあって，それら<br />
は value at present unknown と property inapplicable であり，それに基づき，値がない場合，つま<br />
り missing の場合を missing and applicable と missing and inapplicable の 2 つに分類しました．<br />
Applicable と inapplicable で二律背反ですから，この分類に限れば完全です．しかしながら，コッド<br />
の分類で問題があると考えられるところは，<strong>そもそも値があるのかないのか，それが分からない</strong>とい<br />
う理由で missing の場合がフォーマライズされていないことです．確かに，コッドの論文[4]を丁寧に<br />
見ると，そこに掲載されている Fig.1 で missing values を分類して，applicable と inapplicable に<br />
加えて other という枝分かれを確認することができます（その結果，missing values は 3 種類という<br />
ことになります）．この other ですが，本文中に説明は見当たらず，Fig.1 中に記載があるだけなの<br />
ですが，その図を拠り所にしてコッドが考えた missing value の概念を<strong>分類木</strong>（classification tree）<br />
で表してみると<strong>図 1</strong> のように描けます．しかし，other がこのような位置づけでは，3.3 節の議論で<br />
明らかになるように，ナルの健全かつ完全な分類とはなっていないのです．</p>
<p><center><img decoding="async" style="margin-top: -20px; width: 480px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P08-01.png" alt="コッドのmissing values[4]の分類木" /></center><br />
<center></p>
<p style="margin-top: -40px;"><b>図 1　コッドの missing values<sup>[4]</sup>の分類木</b></p>
<p></center></p>
<p><strong>3.2　SQL によるナルの意味の体系</strong><br />
&emsp;SQL は，2.4 節で述べた通り，ナル値には次の3つがあるとしています[6]．</p>
<p><img decoding="async" style="margin-top: -18px; margin-left: +44px; width: 500px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P08-02b.png" alt="SQL によるナルの意味の体系" /><br />
&emsp;“not available” は何らかの理由で属性値が入手不可，“not applicable” はこのタップルがその属性で現実値をとることはありえず適用不可，“unknown” は属性値は存在するはずだが未知，を表しています．この分類ですが，コッドが与えた “missing and applicable”，“missing and inapplicable”，“other” という 3 分類とは異なるようです．個人的な感覚レベルでは，“not applicable” と “missing and inapplicable” が対応しているのだろうとは思いますが，他は漠然としていてよく分かりません．多分，対応付けしようとする方がおかしいのだろうと思います．SQL のナルの分類は属性が現実値をとれないと考えられる場合を3つピックアップしただけという感じで，場当たり的な分類の感はぬぐえず，ナルの健全かつ完全な分類からは遠い気がします．<br />
&emsp;なお，SQL はナル値には 3 つの意味があるとはしましたが，一律に NULL で表してしまうので，意味の違いを表現することはできません．</p>
<p><strong>3.3　SQL ナルの意味の健全かつ完全な体系化</strong><br />
&emsp;ナルの意味の体系化に対して何かすっきりした解決策はないものかと思案していたとき，かつて筆者の目に留まったのが，ナルの持つ「3 つの意味」に着目してそれを分類する考え方です[8]．ここに，ナルの持つ3つの意味とは次のとおりです．</p>
<p><img decoding="async" style="margin-top: -18px; margin-left: +40px; width: 440px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P09-01.png" alt="ナルの意味の健全かつ完全な体系化-1" /></p>
<p>このナルの意味付けは，対象とした属性がとりうる値の存在の有無に視点を置き，その可能性を分類すると，次に示す 4 つの場合になることに理論的根拠を置いています．</p>
<p><img decoding="async" style="margin-top: -18px; margin-left: +40px; width: 440px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P09-02.png" alt="ナルの意味の健全かつ完全な体系化-2" /></p>
<p>&emsp;確かに，属性値の存在を問うたときに，属性値が存在する，属性値が存在しない，属性値が存在するのかしないのか分からない，この 3 つに分類されますね，と言われればその通りです．さらに，属性値が存在するとしても，現時点で分かっている場合もあれば，分かっていない場合もありますね，と言われればそれも確かにその通りです．この分類則を分類木で表してみると<strong>図 2</strong> のようになります．この分類木の作り方から，属性値の存在に関してこの分類が健全かつ完全であることはほぼ明らかでしょう．</p>
<p><center><img decoding="async" style="margin-top: -12px; width: 400px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P09-03.png" alt="コッドのmissing values[4]の分類木" /></center><br />
<center></p>
<p style="margin-top: -36px;"><b>図 2　ナルの持つ「3つの意味」に着目した分類木</b></p>
<p></center></p>
<p>&emsp;補足ですが，この分類の下で，現実値，unk, dne, ni の違いをそれらが担っている情報量の違いで<br />
説明することができます．つまり，ナルを受け取る側からみると，ni は unk や dne に比べて情報量<br />
が少なく（less informative），unk は現実値が与えられることに比べれば情報量は少ないと言えま<br />
す．また，現実値と dne の情報量の多寡は less informative とも more informative とも言えないでしょう．同様なことが異なる 2 つの現実値同士についても言えると考えられます．したがって，現実<br />
値を d<sub>i</sub>（i=1, 2, …, n）とするとき，集合 {d<sub>1</sub>, d<sub>2</sub>, …, dn, unk, dne, ni} は情報量の多寡を半順序関係（partial order relation）とする<strong>下半束</strong>（lower semilattice）をなしていると表現することができます．その様子を<strong>図 3</strong> に示します．</p>
<p><center><img decoding="async" style="margin-top: -22px; width: 280px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P10-01.png" alt="コッドのmissing values[4]の分類木" /></center><br />
<center></p>
<p style="margin-top: -30px;"><b>図 3　ナルの持つ「3つの意味」のなす下半束<sup>[8]</sup></b></p>
<p></center></p>
<p><strong>【例題２】（unk，dne，ni の具体例）</strong><br />
&emsp;リレーション 社員(社員名＿姓，社員名＿名，配偶者名) を想定する．</p>
<ul style="margin-top: -22px;">
<li>unk の例：社員の属性として配偶者名があるとき，配偶者がいることは分かっているのだが，現時点でその名が分からないとき配偶者名欄に unk を記入する．</li>
<li>dne の例：社員の属性として配偶者名があるとき，配偶者がいない社員の配偶者名欄に dne を記入する．</li>
<li>ni の例：社員の属性として配偶者名があるとき，配偶者がいるのかいないのか分からない社員の配偶者名欄に ni を記入する．</li>
</ul>
<p>&emsp;ただし，次の注意が必要です．たしかに，上記の分類でナルの意味は過不足なく表現することができました．しかしながら，これは言わずもがなですが，もし unk，dne，ni すべてを一律に null で表してしまうとこの分類体系は無意味になってしまいます．たとえば，リレーション社員(社員名＿姓，社員名＿名，配偶者名)にタップル(鈴木，太郎，null)が存在した場合，null が unk を表しているのか，dne を表しているのか，あるいは ni を表しているのかは分からないということです．このようなことにならないためには，リレーショナル DBMS は unk，dne，ni をいかなるドメインにも属さない特別なプレースホルダとして扱える機能を備えていないといけないということになります．ただ，これも言わずもがなですが，現行のプロプライエタリあるいは OSS のリレーショナル DBMS に unk，dne，ni を個別にサポートするような機能は備わっていません．これは，SQL が not available，not applicable，<br />
unknown を一律に NULL と表し処理していることと同じです．</p>
<h4>4．NULL と空文字列</h4>
<p style="margin-top: -18px;" >
&emsp;ナルとは別に<strong>空文字列</strong>（zero-length string, <strong>ZLS</strong>，&#8221;で表す）という概念があります．これは長さが 0 の文字列を「値」として持つということで，ナルとは異なります．相違点は，理論上，ナルはいかなるドメインの元ではありませんが，空文字列はすべてのドメインの元であるということです．<br />
&emsp;さて，空文字列の意味ですが，どう考えたらよいのでしょうか？たとえば，リレーション 友人(氏名，住所，携帯電話番号)があり，タップル (鈴木太郎，横浜，&#8221; )があったとします．これは，もしタッ<br />
プルが(鈴木太郎，横浜，null)であった場合と何がどう違うのでしょうか，それを説明してほしいという問題です．もちろん，SQL で問合せを書き下すにあたって，空文字列と null ではその取扱いに違いのあることは十分に承知してのことです．つまり，ここでの関心事は意味の違いです．繰り返しますが，(鈴木太郎，横浜，&#8221; )と(鈴木太郎，横浜，null)では一体何がどのように違うのでしょうか？<br />
&emsp;もし，空文字列（&#8221;）で鈴木太郎が携帯電話を持っていないということを表したいというのであれば，携帯電話番号欄は null，正確には dne でしょう．もし，持っているのは分かっているのだけれど<br />
その番号が分からないというのであれば null，正確には unk でしょう．もし持っているのかいないの<br />か分からないのでということであれば null，正確には ni を記録するべきであって，空文字列ではないでしょう．そうすると，唯一考えられるのは，鈴木太郎の携帯番号が現実値として空文字列（&#8221;）であるということになってしまいますが，こんな携帯電話の番号ってありますか？マジ理解に苦しむ世界に落ち込んでしまいました．．．
</p>
<p><center></p>
<p style="margin-top: -0px;">『データベースは色即是空空即是色の世界観のもとで成り立っている』</p>
<p></center></p>
<p style="margin-top: -10px;">&emsp;ということでしょうか，奥深いことです．</p>
<h4>5．PostgreSQL と NULL および空文字列</h4>
<p>&emsp;OSS のリレーショナルDBMSとして普及している PostgreSQL では用語集（glossary）でナルを次のように定義しています[9]．</p>
<p style="margin-top: -00px; margin-left: +60px;">『Null－リレーショナルデータベース理論の中心的な信条である non-existence<br />（存在しない）という概念．明確な値がないことを表します』</p>
<p>&emsp;「明確な値がないことを表します」，原文では “It represents the absence of a definite value.” と書かれているわけですが「明確な値がない」とはどういうことか，ナルはナル値という “値”（value）であるのか単なる標識なのか，それについてはなにも言及されていません．なお，空文字列については特段の定義が与えられているわけではありません．</p>
<p>&emsp;そこで，念のため，null や空文字列が PostgreSQL で一体どのようにサポートされているのか，<br />
PostgreSQL 14 で検証しつつ気が付いたところを記してみたいと思います．</p>
<p><strong>【検証】</strong>（PostgreSQL 14 での NULL と空文字列の扱い）<br />
&emsp;テーブル test(name char(10), spouse char(10)) を作成し，タップル (&#8216;taro&#8217;, &#8216;hanako&#8217;), (&#8216;jiro&#8217;, &#8221;), (&#8216;saburo&#8217;, null) を挿入して，SQL で空文字列 &#8221; とナル値を表すキーワード null に関する問合せを発行して，PostgreSQL 14 はどのように振舞うのか，その結果を見てみます．なお，PostgreSQL の問合せでのナル値と空文字列の概念の違いはモムジャン（B. Momjian）の著書[10]で平易に説明されているので参考になるかもしれません．</p>
<p><img decoding="async" style="margin-top: -12px; margin-left: +10px; width: 640px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P12-01.png" alt="（PostgreSQL 14 での NULL と空文字列の扱い）" /></p>
<p><strong>・　検証事項１</strong><br />
&emsp;上記の select 文の結果ですが，jiro の spouse（配偶者）値は空文字列 &#8221; のはずですが，空白として表示されています．空文字列だからそうなのでしょう．一方，saburo の spouse 欄は 空文字列ではなく null のはずですが，これまた空白です．したがって，この問合せの結果からは，ユーザは jiro のタップルの spouse 値が空文字列 &#8221; でsaburo のタップルの spouse 欄は null であることを知ることはできません．筆者としては，この問合せに対する導出表は（2）式のように表示されるべきだと思います．導出表をなぜ（2）式のように表示してくれないのでしょか？筆者には謎です．</p>
<p><img decoding="async" style="margin-top: -12px; margin-left: +10px; width: 640px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P12-02.png" alt="検証事項1" /></p>
<p><strong>・　検証事項２</strong><br />
&emsp;上記の結果を受けて以下の 2 つの問合せを発行してみます．</p>
<p><img decoding="async" style="margin-top: -12px; margin-left: +10px; width: 640px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P13-01.png" alt="検証事項2-1" /></p>
<p>&emsp;この問合せの結果から，spouse 値が空文字列のタップルは jiro のタップルであることが分かります．つまり，空文字列を PostgreSQL は内部的にはちゃんと認識し，述語「 &#8221; = &#8221; 」は T（真）（表 1　述語 xθy の真理値（3 値論理））と認識しています．</p>
<p>&emsp;一方，次を発行してみます．</p>
<p><img decoding="async" style="margin-top: -12px; margin-left: +10px; width: 640px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P13-02.png" alt="検証事項2-2" /></p>
<p>&emsp;この問合せの結果から，spouse 欄が null のタップルは saburo のタップルであること，すなわち，null is null=T（真）（表 3　IS ブール演算子真理値表（3 値論理））と PostgreSQL はちゃんと認識しています．<br />
&emsp;（3）と（4）から分かるように，PostgreSQL は問合せの結果（1）からはユーザには見えませんでしたが，内部的には空文字列と null をきちんと認識しているわけです．決してごっちゃになっているわけではありません</p>
<p><strong>・　検証事項３</strong><br />
&emsp;ここでは，理論上，「spouse is null」は許されたが「spouse is &#8221;」は許されないこと，および「spouse = null」の処理を念のために検証することにします．</p>
<p>&emsp;まず，「spouse is &#8221;」 は許されないことは次のように確認されます．is true, is null, is false は IS ブール演算子として許されるが，is &#8221; は IS ブール演算子として許されていないので納得です．</p>
<p><img decoding="async" style="margin-top: -12px; margin-left: +10px; width: 480px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P14-01.png" alt="検証事項3-1" /></p>
<p>&emsp;では，「spouse = null」はどうでしょうか？</p>
<p><img decoding="async" style="margin-top: -12px; margin-left: +10px; width: 500px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P14-02.png" alt="検証事項3-2" /></p>
<p>&emsp;導出表は 0 行という表示ですから，リレーション test には探索条件 spouse = null にヒットするタップルがなかったというわけです．この問合せ処理にあたっては，探索条件 spouse = null に対して，具体的には 3 つの述語 &#8216;hanako&#8217;=null，&#8221;=null，null=null を検証しないといけないわけですが<br />
（= は比較演算子），表 1 に示した「述語 xθy の真理値（3 値論理）」から，&#8217;hanako&#8217;=null の真<br />
理値は ω，&#8221;=null の真理値も（ &#8221; が空文字列という現実値なので）その真理値は ω，null=null の<br />
真理値も ω ということで，いずれも真（T）ではないので，ヒットした行はなかったということです．<br />
なお，(&#8216;saburo&#8217;, null)∈test なので，&#8217;saburo&#8217; が導出表に現れるかと思うかもしれませんが，そのためには “spouse=null” ではなく，“spouse is null” を指定しなさいということです（検証事項 2）．</p>
<p><strong>・　検証事項４</strong><br />
&emsp;update 文では set 句で spouse=null という表現が許されますが，この場合は述語ではなく「代入」を表し，その簡単な例は次の通りです．ただ，更新結果を確認するためにselect文を発行しても，検証事項1でクレームしたと同様に，導出表からは，taro の spouse が空文字列（&#8221;）と更新されたのか，<br />
null と更新されたのかを読み解くことはできません．</p>
<p><img decoding="async" style="margin-top: -12px; margin-left: +10px; width: 550px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/10/drmasunaga-09-P14-03.png" alt="検証事項4" /></p>
<p>&emsp;なお，null や空文字列の扱いはプロプライエタリや OSS のリレーショナル DBMS ごとに異なっているようです．上で見たように PostgreSQL ではそれらを区別して扱っていましたが，Oracle Database では自動的に空文字列を null に変換するとの記事をよく見かけます．空文字列とナルの違いを意識したユースケースを Oracle Database は想定していないということなのでしょう．</p>
<h4>6．おわりに</h4>
<p>&emsp;ナル（null）に係わる話題をいくつか披露いたしました．ナルの意味の健全かつ完全な体系化には，属性は「現実値」に加えて，3 種類の意味の異なるナル，すなわち，unk（未知），ni（情報がない），dne（存在しない），をサポートする必要があることを論じました．そのためには，リレーショナルデータモデルとリレーショナル DBMS は 3 値論理を超える多値論理をモデル化し実装していくことが必要になりますが，一筋縄ではいかない難問と考えられます．機会があれば論じてみたいですね．<br />
&emsp;繰り返すまでもありませんが，本稿をお読みいただいた方々，これをご縁に以下のことお約束ください．</p>
<p>&emsp;&emsp;&emsp;<strong>● ヌルとは言わない，必ずナルと言う．</strong><br />
&emsp;&emsp;&emsp;<strong>● ナル値とか空値とは言わない，必ずナルあるいは空と言う．</strong></p>
<p><strong>【文献】</strong></p>
<p style="margin-top: -10px;" >[1]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
ANSI/X3/SPARC Study Group on Data Base Management Systems, Interim Report, ANSI, February 1975, pp. IV-28～IV-29.<br />
<a href="https://dl.acm.org/action/showFmPdf?doi=10.1145%2F984332" target="_blank" rel="noopener noreferrer">https://dl.acm.org/action/showFmPdf?doi=10.1145%2F984332</a>
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[2]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Edgar. F. Codd. Extending the Database Relational Model to Capture More Meaning. ACM TODS, Vol.4, No.4, pp.397-434, 1979
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[3]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
増永良文．リレーショナルデータベース入門[第3版]．サイエンス社，2017．
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[4]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Edgar. F. Codd. Missing Information (Applicable and Inapplicable) In Relational Databases&#8221;, ACM Sigmod Record, Vol 15, No. 4, pp.53-78, December 1986.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[5]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Edgar. F. Codd. More Commentary on Missing Information in Relational Databases (Applicable and Inapplicable Information). ACM Sigmod Record, Vol 16, No. 1, pp.42-50, March 1987.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[6]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Jim Melton and Alan R. Simon. SQL: 1999 : Understanding Relational Language Components. Morgan Kaufmann Publishers, 2002.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[7]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Information technology — Database languages — SQL — Part 2: Foundation (SQL/Foundation), Reference number ISO/IEC 9075-2:2016(E), ISO/IEC, 2016-12-15.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[8]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Mark A. Roth, Henry F. Korth and Abraham Silberschatz. Null Values in Nested Relational Databases. Acta Informatica 26, pp.615-642, 1989.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[9]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
The PostgreSQL Global Development Group. PostgreSQL 14.2 Documentation.<br />
<a href="https://www.postgresql.org/files/documentation/pdf/14/postgresql-14-A4.pdf" target="_blank" rel="noopener noreferrer">https://www.postgresql.org/files/documentation/pdf/14/postgresql-14-A4.pdf</a>
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[10]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
ブルース・モムジャン（著），日本ポストグレスユーザー会（翻訳）．はじめてのPostgreSQL　データベース問い合わせのコンセプト．ピアソン・エデュケーション，2001．
</td>
</tbody>
</table>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>増永教授のDB特論⑧「MVCC」</title>
		<link>https://www.sraoss.co.jp/tech-blog/db-special-lecture/masunaga-db-special-lecture-8/</link>
		
		<dc:creator><![CDATA[増永良文 (Yoshifumi Masunaga)]]></dc:creator>
		<pubDate>Wed, 14 Sep 2022 00:00:16 +0000</pubDate>
				<category><![CDATA[増永教授のDB特論]]></category>
		<category><![CDATA[MVCC]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[RDB]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[リレーショナルデータベース]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=10989</guid>

					<description><![CDATA[&#160; 1. はじめに &#8195;トランザクションの同時実行制御は障害時回復とならんでトランザクション管理には欠かせない機能であることは言うまでもないことです．そのために 2 相ロッキング（two phase l ...]]></description>
										<content:encoded><![CDATA[<p>&nbsp;</p>
<h4>1. はじめに</h4>
<p style="margin-top: -10px;">
&emsp;トランザクションの同時実行制御は障害時回復とならんでトランザクション管理には欠かせない機能であることは言うまでもないことです．そのために 2 相ロッキング（two phase locking, 2PL）プロトコルが考案され，伝統的に 2PL が多くのデータベース管理システム（DBMS）で実装されてきました．しかし，2PLでは同時実行されているトランザクションの直列化可能性を保証するために，トランザクションは読取りや更新の対象となるオブジェクトをロック（lock，施錠）することが必要で，それによる同時実行性（concurrency）の制約は古くから認識されるところでした．<br />
&emsp;<strong>多版同時実行制御</strong>（multiversion concurrency control, MVCC）は 2PL とは異なり，競合しているトランザクションの実行終了を待つのではなく，同じデータ項目の異なる<strong>版</strong>（version）を用意することによって，トランザクションの隔離性を向上させ，同時実行性を高めようとするアプローチです．データ項目の版という概念の導入は 1978 年に遡りますが[1]，その考え方はデータベース分野に直ちに入り込み，1980 年代初頭には MVCC の理論の礎が築かれました[2]．MVCC と一口に言ってもその実現法は <strong>MVTO</strong>（multiversion timestamp ordering），MV2PL，MVMM，MVOCC，SI（snapshot isolation，スナップショット隔離性），SSI（serializable snapshot isolation，直列化可能スナップショット隔離性）など多様です．現在 MVCC はこのようなさまざまな実現法を包括した用語として用いられると同時に，狭義には MVCC の原点である MVTO を指す言葉としても用いられます．現在，多くのプロプラィエタリ（proprietary）あるいは OSS のリレーショナル DBMS で MVCC が実装されています．<br />
&emsp;2PL と MVCC ではトランザクションの同時持実行制御の考え方が根本的に異なるので，2PL を念頭に制定された国際標準リレーショナルデータベース言語 SQL が定めた隔離性水準（isolation level）と MVCC の提供する隔離性水準との間には<ruby>齟齬<rt style="background-color: #dddddd;">そご</rt></ruby>が出ます．現在 PostgreSQL や Oracle で実装されている SI は ANSI SQL の隔離性水準を論評する過程で考案され，1995 年に公表されました[5]．<br />
&emsp;本稿では，MVTO と SI を中心において，MVCCと は何かを改めて議論しておきたいと考えます．</p>
<p><span id="more-10989"></span></p>
<h4>2. MVCC</h4>
<p style="margin-top: -10px;"><strong>2.1 MVCC とは</strong><br />
&emsp;<strong>MVCC</strong> という用語はとても一般的になっていますが，そもそも MVCC という概念は「更新可能なオブジェクトを不変な<strong>版</strong>（version）の系列と見なす」と発想した Reed の博士論文 “Naming and Synchronization in a Decentralized Computer Systems”[1] に見ることができます（1978 年 9 月にマサチューセッツ工科大学（MIT）に提出した学位請求論文）．この考え方は 1981 年に InterBase で実装されたということです（その後，Firebird としてオープンソース化されました）．<br />
&emsp;データベース分野で MVCC が本格的に論じられたのは Bernstein と Goodman が 1981 年に発表した論文 “Concurrency Control in Distributed Database Systems”[2]と考えられます．彼らはその論文で Reed の手法を “Multiversion Timestamp Ordering <strong>(MVTO)</strong>” として形式化し，その正当性の証明を与えて MVCC によるトランザクションの同時実行制御の時代の幕を切って落としました．MVCC の実現法はざまざまに考えられ，彼らはその論文で MVTO に加えて，従来の2PLに版の概念を導入して拡張した <strong>MV2PL</strong>，読みのみを発行するトランザクションを同期させるためには MVTO を使用し読み書きを行うトランザクションの同期には厳密な 2PL（strict 2PL）を使うMVMM（multiversion mixed method）を提案し，それらの正当性を証明しています．これら，初期の MVCC の手法は Bernstein らの一連の論文と著書に詳しく記載されています[2, 3, 4]．その後，MVCC の手法として Larson ら[6]により <strong>MVOCC</strong> が提案されています．これは，トランザクションの同時実行制御法として知られている楽観的同時実行制御法（optimistic concurrency control, OCC）[7]に多版（multiversion）の概念を導入した手法です．そして，ANSI SQL の隔離性水準を論評する過程で<strong>スナップショット隔離性</strong>（snapshot isolation， <strong>SI</strong>）が提案されました[5]．1995 年のことです．SI やそれを直列化可能とした<strong>直列化可能スナップショット隔離性</strong>（Serializable snapshot isolation，<strong>SSI</strong>）はシドニー大学（University of Sydney）の Fekete や Cahill ら[8, 9, 10]によりその性質や実装法が明らかにされましたが，それらも MVCC の一種です．このように MVCC は，広義には SI や SSI を含む多くの異形をカバーする用語ですが，狭義には MVTO を表す用語と理解するのが理にかなっているかと考えます．</p>
<p><strong>2.2 2PL vs. MVCC</strong><br />
&emsp;2PL ではなく，MVCC でトランザクションの同時実行を行うと何が嬉しいのか，それを単純ですが典型的な例で確認しておきたいと思います．以下，ここで想定している MVCC は，この概念の基礎となった MVTO をフォーマルに記述したものとします．なお，トランザクションの同時実行スケジュール，スケジュールのビュー等価（view equivalence）や相反等価（conflict equivalence）などの説明は省略しますが，参照されたい向きには拙著[11]を薦めます．<br />
&emsp;まず具体的に MVCC の意味するところを直観することにします．そこで，S<sub>1</sub> をトランザクション T<sub>1</sub> と T<sub>2</sub> の同時実行スケジュールとし，<strong>図 1(a)</strong>に示す通りとしましょう．すると，S<sub>1</sub> は相反直列化可能でない（従ってビュー直列化可能でもない）ことが確かめられますから，S<sub>1</sub> は 2PL では正しい実行を保証されないスケジュールであることが分かります．<br />
&emsp;ところが，MVCC のもとではこのスケジュールでトランザクションを実行しても正しい結果が得られます．それはどうしてでしょうか？そうなる仕組みはどのようなものなのでしょうか？それを見てみましょう．<br />
&emsp;まず，具体的に，なぜスケジュール S<sub>1</sub> は正しい結果を保証しないのでしょうか？それは，時刻5で発行された T<sub>1</sub>のデータ項目 y の読み，T<sub>1</sub>:read(y) は，T<sub>2</sub> が時刻 4 で y に書き出した T<sub>2</sub>:write(y) の結果を読んでしまうが，（トランザクションの隔離性という観点から考えれば）本来はデータ項目 y の初期値，これを y<sub>0</sub> と書く，を読みたかったはずなのに，スケジュール S<sub>1</sub> ではそれが叶わなかったということです．<br />
&emsp;しかし，もし T<sub>1</sub> と T<sub>2</sub> の同時実行スケジュールが<strong>図 1(b)</strong>に示した S<sub>2</sub> であったらどうでしょうか？このときは，容易に確かめられるように，S<sub>2</sub> は相反直列化可能スケジュールとなり，このスケジュールで T<sub>1</sub> と T<sub>2</sub> を同時実行すれば正しい結果が保証されます．</p>
<p><center><img decoding="async" style="margin-top: -12px; width: 550px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/09/drmasunaga-08-P03-01.png" alt="スケジュールS1とS2" /></center></p>
<p><center></p>
<p style="margin-top: -30px;"><b>図 1　スケジュール S<sub>1</sub> と S<sub>2</sub> </b></p>
<p></center></p>
<p>&emsp;さて，実は，MVCC のもとでは，スケジュール S<sub>1</sub> に従ってトランザクション T<sub>1</sub> と T<sub>2</sub> を同時実行しても，正しい結果を保証してくれます．これはどうしてかというと，MVCC では<strong>版</strong>の概念があるので，たとえスケジュール S<sub>1</sub> に従って T<sub>1</sub> と T<sub>2</sub> を同時実行しても，実質的にはスケジュール S<sub>2</sub> で T<sub>1</sub> と T<sub>2</sub> を実行したことになるからです．それが<ruby>正<rt style="background-color: #dddddd;">まさ</rt></ruby>しく MVCC の意図するところです．<br />
&emsp;そこで， MVCC アルゴリズムに従いトランザクションの同時実行をスケジュールする<strong>多版スケジューラ</strong>（mulitiversion scheduler）がどのようにトランザクションステップの実行を制御していくのか，そのアルゴリズムを示しますが，それを理解するための助けとなるかと考え，いくつか補足的説明を行います．</p>
<p style="margin-top: -10px;" > (1)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
トランザクション群 {T<sub>1</sub>,T<sub>2</sub>,・・・,T<sub>n</sub>}を同時実行するためのスケジュール S が与えられたとする．S に従いトランザクション T<sub>i</sub> が実行を開始したとき，その時の時刻を T<sub>i</sub> に<strong>時刻印</strong>（timestamp），これをts(T<sub>i</sub>)と書く，として付与する．一般に，時刻は単調に増加する識別子，例えばカウンタ，なら何でもよい（その意味で論理時刻ともいう）．トランザクションは並列（parallel）実行ではなく，同時（concurrent）実行なので，お互いの開始時間は異なるから，トランザクションが異なればそれらの時刻印は異なっていて，一意性が保証されている．つまり，時刻印を比較するとどちらが先発，あるいは後発のトランザクションであるかが分かる．
</td>
</tbody>
</table>
<p style="margin-top: -10px;" > (2)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
次に，データ項目 x を考える．多版スケジューラは x の<strong>版</strong>，これを x<sub>i</sub>, x<sub>j</sub>, x<sub>k</sub>, …という具合に書く，を保持する．版はトランザクションがデータ項目に対して書きを実行したときに生成される．例えば，トランザクション T<sub>i</sub> がデータ項目 x に対して write(x) を発行しそれが実行されれば，版 x<sub>i</sub> が生成される．このとき，x<sub>i</sub> にはそれが生成された時刻が時刻印として付与される．また，MVCC アルゴリズムはデータ項目の版に基づき作動するので，トランザクションの同時実行で使われるデータ項目 x については，その<strong>初期版</strong>（initial version）を設定しておく必要がある．そのために，各データ項目 x の初期版 x<sub>0</sub> を生成する擬似的なトランザクション T<sub>0</sub>，その時刻印は 0 とする，がすべてのトランザクションステップに先行して実行されることとする．
</td>
</tbody>
</table>
<p style="margin-top: -10px;" > (3)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
MVCC アルゴリズムを理解する上で大事なことは，データ項目 x の版の存在は多版スケジューラが把握していればよいことであって，ユーザが意識する必要はない．つまり，ユーザが発行するトランザクションはデータ項目の版を意識する必要はないということである．換言すれば，ユーザにとっては，データ項目 x の版はただ 1 つしかないといえる．したがって，トランザクション T<sub>i</sub> からデータ項目 x に対して読み（T<sub>i</sub>:read(x)）や書き（T<sub>i</sub>:write(x)）が発行された場合，多版スケジューラはそれらをデータマネジャが処理できるようにするために， データ項目 x の版，x<sub>i</sub>, x<sub>j</sub>, x<sub>k</sub>,…，に対する読み（r<sub>i</sub>[x<sub>k</sub>]，T<sub>i</sub> が版 x<sub>k</sub> を読むという意味）や書き（w<sub>i</sub>[x<sub>i</sub>]，T<sub>i</sub> が x に書込みをして版 x<Sub>i</sub> が生成される）に変換しないといけない．その変換によって，図 1 の例で説明すれば，スケジュール S<sub>1</sub> はあたかもスケジュール S<sub>2</sub> に従っているかのような実行を実現できたのである．
</td>
</tbody>
</table>
<p><strong>【MVCC アルゴリズム】</strong><br />
&emsp;MVCC アルゴリズムは次の規則に則り，トランザクションの読みや書きを版（version）への読込みや書込みに変換する．<br />
　(1)　T<sub>i</sub>:read(x) を r<sub>i</sub>[x<sub>k</sub>] に変換する．このとき x<sub>k</sub> は ts(T<sub>i</sub>) 以下で最大の時刻印を持つ x の<br />
　　　版を表す．<br />
　(2)　T<sub>i</sub>:write(x) は次の 2 つに場合分けされる．<br />
　　　　(i) もし，ts(T<sub>k</sub>)＜ts(T<sub>i</sub>)＜ts(T<sub>j</sub>)を満たす i, j, k に対して，r<sub>j</sub>[x<sub>k</sub>]なる処理が行われてい<br />
　　　　　 たならば，T<sub>i</sub>:write(x) は棄却される（従って，T<sub>i</sub> はアボートされる．）．<br />
　　　　(ii) そうでなければ，T<sub>i</sub>:write(x)をw<sub>i</sub>[x<sub>i</sub>] に変換する．</p>
<p>&emsp;補足すると，(2)(i) の言っていることは，自分（T<sub>i</sub>）より後発のトランザクション（T<sub>j</sub>）が自分より先発のトランザクション（T<sub>k</sub>）が書き出した結果を読んでしまっている（r<sub>j</sub>[x<sub>k</sub>]）なら，自分がそのデータ項目 x を書き換えるとことは許されない，ということである．</p>
<p>&emsp;さて，MVCC アルゴリズムに従った多版スケジューラが出力したスケジュールを<strong>多版スケジュール</strong>といいますが，この MVCC アルゴリズムに従って，図 1 (a) に示したスケジュール S<sub>1</sub> でトランザクション T<sub>1</sub> と T<sub>2</sub> を同時実行して得られた多版スケジュールを<strong>図 2</strong> に示します（<strong>←</strong>は代入を表す）．特に注目するべきところは，時刻 5 で，T<sub>1</sub>:read(x) は MVCC のもとでは，T<sub>2</sub> が直前に書き出した y<sub>2</sub> を読むのではなく，MVCC アルゴリズムの (1) により，y の初期値 y<sub>0</sub> を読んでいるところです．その結果，<br />
MVCC に従うとスケジュール S<sub>1</sub> で T<sub>1</sub> と T<sub>2</sub> を同時実行しても，その実行結果としての多版スケジュールは従来の相反直列化可能なスケジュール S<sub>2</sub> での実行と同じになっていて，従って，正しい実行であると考えることができるわけです．</p>
<p><center><img decoding="async" style="margin-top: -12px; width: 480px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/09/drmasunaga-08-P04-01.png" alt="スケジュール S1 の多版スケジュール" /></center></p>
<p><center></p>
<p style="margin-top: -30px;"><b>図 2　スケジュール S<sub>1</sub> の多版スケジュール</b></p>
<p></center></p>
<p>&emsp;このように，2PL の同時実行制御の考え方では相反直列化可能ではないスケジュール S<sub>1</sub> が，MVCC アルゴリズムのもとでは正しい実行を保証してくれるスケジュールと考えてよいことを示しましたが，この根底には MVCC アルゴリズムの正当性が示されていないといけません．つまり，このアルゴリズムに則って多版スケジューラが出力する多版スケジュールでトランザクションを同時実行することによってデータベースの一貫性が損なわれることはない，ということの証明が必要ということです．この証明の道筋は，多版スケジュールを単一版（single version, 1V）スケジュールに変換して（単一版とは版が 1 つしかないということだから，従来型のスケジュールということで，従って，従来型の同時実行制御の考え方が適用できる），その直列化可能性から多版スケジュールの正当性を示すのですが，この証明はいささか複雑すぎます．どうしてもそれを知りたいという読者は，文献[4]の第 5 章で与えられていますので，それに当たってください．ここでは，これ以上立ち入らず，MVCC アルゴリズムは正しいという結果を述べるに留めたいと思います．</p>
<h4>3. SI と SSI</h4>
<p style="margin-top: -10px;"><strong>3.1 SI の提案</strong><br />
&emsp;さて，1995 年に “A Critique of ANSI SQL Isolation Levels” と題した論文[5]が発表されました．この論文は，題目の通りANSI（American National Standards Institute，米国国家規格協会）が制定した SQL のトランザクションの隔離性水準の不備を指摘するとともに，「直列化可能ではないものの，<br />
ANSI SQL が指摘した現象，つまり<strong>汚読</strong>（dirty read），<strong>反復不可能な読み</strong>（unrepeatable read），<strong>幽霊</strong>（phantom）が発生しない多版同時実行メカニズム」を定義して，それを<strong>スナップショット隔離性</strong>（Snapshot Isolation，<strong>SI</strong>）と名付けました．そこでは，SI は MVMM（multiversion mixed method）の拡張であると紹介され，SI は ANSI の定義した READ COMMITTED よりは強く，<br />
REPEATABLE READ とは強弱が言えないことが述べられています．また，直列化可能ではないことの理由として<strong>書込みスキュー異状</strong>（write skew anomaly）の発生を挙げています．<br />
&emsp;SI は MVTO や MV2PL などと違ってトランザクションの同時実行の正しさ，つまりトランザクションの直列化可能性を保証するプロトコルではなく，書込みスキュー異状に加えて<strong>読取り専用トランザクション異状</strong>（read-only transaction anomaly）[8]の発生も許してしまうのですが，その特性はシドニー大学（University of Sydney）の研究者により深く研究されその性質や実装法が明らかにされました[8, 9, 10]．Fekete ら[9]は SI の下で TPC-C ベンチマークが異状を発生することなく実行可能であったことを実験的に示して，直列化可能性を保証できない SI ではあるが，ほとんどのトランザクションを問題なく同時実行できるのではないかということを強調しました．Cahill ら[10]は SI を直列化可能とする <strong>SSI</strong>（serializable snapshot isolation，直列化可能 SI）のアルゴリズムとその実装，ならびにその性能については様々なケースで 2PL より大幅に改善し，往々にして SI と同程度であったと報告しています．ただ，SSI では，現実的な実装法の制約から，本来は直列化可能なスケジュールなのにその実行が棄却されてしまうという<strong>擬陽性</strong>（false positive）が発生することは避けられないことには注意が必要です．これらの現象については，以下でより詳しく例題を挙げて説明します．<br />
&emsp;現在，SI は PostgreSQL，Oracle Database，MS SQL Server などで実装されています．SI は汚読，反復不可能な読み，幽霊を引き起こさないので，それを実装すれば SQL の隔離性水準である SERIALIZABLE を実現していることになります．Oracle Database はそれでもって SERIALIZABLE を実現，と<ruby>謳<rt style="background-color: #dddddd;">うた</rt></ruby>っているのですが，2PL に基づいた SERIALIZABLE の実現と違って SI では書込みスキュー異状や読取り専用トランザクション異状が発生するので，トランザクションの同時実行制御の理論が謳うところの真の意味での（あるいは完全な）直列化可能性を達成しているわけではないわけで，<br />
SERIALIZABLE と謳うのはいかがなものかと，この点で物議を<ruby>醸<rt style="background-color: #dddddd;">かも</rt></ruby>してきたことは本稿の読者であればどこかで耳にしていることでしょう．一方，PostgreSQL では REPEATABLE READ を SI で，<br />
SERIALIZABLE を SSI で，READ COMMITTED は SI を緩める，つまり，各読み<ruby>毎<rt style="background-color: #dddddd;">ごと</rt></ruby>にスナップショット（snapshot）を取り直す，ことで実装しています（READ UNCOMMITTED は実装されていなく，その隔離性水準を指定すると default の READ COMMITTED となります）．この詳細は Ports と Grittner [12]により報告されています．したがって，PostgreSQL では Oracle Database のような物議は<ruby>醸<rt style="background-color: #dddddd;">かも</rt></ruby>しませんが，前述のように SERIALIZABLE では擬陽性が発生することがあるので，それに注意する必要があります．</p>
<p><strong>3.2 SI</strong><br />
&emsp;さて，SI の定義を見てみることから始めましょう．<br />
<strong>【定義 1】(SI)</strong><br />
&emsp;SI の下で実行されるトランザクション T<sub>1</sub> は，それが開始された論理時刻，これを開始時刻印（start-timestamp）と呼ぶ，の時点で有効なコミット済みデータからなるスナップショットから常にデータを読み取る．T<sub>1</sub> の開始後にアクティブな他のトランザクションの更新は T<sub>1</sub> には見えない．T<sub>1</sub> がコミットの準備ができると，コミット時刻印（commit-timestamp）が割り当てられ，他の同時トランザクション T<sub>2</sub>（つまり，アクティブ期間 [開始時刻印, コミット時刻印] が T<sub>1</sub> の期間と重複するトランザクション）がすでに T<sub>1</sub> が書き込むことを意図しているデータに書込みをしていない場合にコミットが許可される．これは，遺失更新（lost update）を阻止するためで，<strong>First-Committer-Wins</strong> ルールと呼ばれる．</p>
<p>&emsp;実際には，ほとんどの実装では，更新された行に排他ロックが使用されるため，First-Committer-Wins の代わりに，First-Updater-Wins ルールが適用されています．共に，同時実行されている 2 つのトランザクションが同じデータ項目を更新することはできないというためのルールで，その差異は重要ではありません．これは遺失更新異状が発生しないことを意味しているわけです．同様に，トランザクション T のすべての読みは T が開始する前にコミットしたトランザクションの結果を見るので，不完全なトランザクションの影響がなく，これは SI では汚読の異状が発生しないことを意味します．<br />
&emsp;SI の定義と補足説明でほぼ明らかかと思われますが，トランザクションはその開始時点でのスナップショットを読み続けるので，汚読，反復不可能な読み，幽霊は発生のしようがなく，その結果として SI は SQL の規定している隔離性水準 SERIALIZABLE でのトランザクションの同時実行を保証してくれます．<br />
&emsp;しかしながら，トランザクションの同時実行制御の理論が謳うところの「真」の意味での直列化可能性（serializability）は満たしていないわけです．なぜならば，SI では書込みスキュー異状や読取り専用トランザクション異状が発生してしまうからです．このことを例題で説明しましょう．</p>
<p><strong>【書込みスキュー異状】（write skew anomaly）</strong><br />
&emsp;たとえば，データ項目 x，y の初期状態を，x<sub>0</sub>=50, y<sub>0</sub>=50 とします.また，データベースには一貫性制約が課せられていて，それは x+y≧0 であったとします．<br />
&emsp;このとき，SI のもとでトランザクション T<sub>1</sub> と T<sub>2</sub> が同時実行され，そのスケジュールが<strong>図 3</strong> に示されたようであったとします．論理時間は縦軸の上から下の方へ流れていっているとします．T<sub>1</sub> の読んだ x と y の初期値 <sub>x0</sub> と <sub>y0</sub> はそれぞれ 50 で，両者を足して 100 となります．このとき，T<sub>1</sub>が xを －20<br />
に書換えて x<sub>1</sub>=－20 としても（つまり，x<sub>0</sub>－70 を実行したということ），y<sub>0</sub>=50 なので，x<sub>1</sub>+y<sub>0</sub>=30<br />
となり一貫性制約には抵触しなく，T<sub>2</sub> はまだコミットしていないので，First Committer Wins ルールでコミットできます（それを c<sub>1</sub> で表しています）．一方，T<sub>1</sub> と同時実行されている T<sub>2</sub> は x<sub>0</sub> と y<sub>0</sub> を読み，y<sub>2</sub>=－30 と y を更新したとします．この更新も一貫性制約に抵触しないので許されます．さらに，T<sub>2</sub> は y を更新したのであって，x を更新したのではないので，First Committer Wins ルールによりコミットできます（これを c<sub>2</sub> で表しています）．<br />
&emsp;さて，T<sub>1</sub> と T<sub>2</sub> の同時実行により，データベースの状態はどのようになったでしょうか？データ項目 x の値は －20 となりました．一方，データ項目yの値は －30 となりました．両方を足すと，x+y の値は －50 になり，これはデータベースの一貫性制約 x+y≧0 に抵触していることになります．この問題は First-Committer-Wins ルールの適用時には検出されませんでした．なぜならば，2 つの異なるデータ項目は，それぞれが他方の状態が変化することなく元のままであることを前提として更新されているためです．それが，「ずれた書込み」（write skew）と名付けられた<ruby>所以<rt style="background-color: #dddddd;">ゆえん</rt></ruby>です．なお，図中，rw は rw-dependency （rw-従属性）の存在を示しています（rw-従属性の説明は 3.3 節）．</p>
<p><center><img decoding="async" style="margin-top: -12px; width: 360px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/09/drmasunaga-08-P09-01.png" alt="書込みスキュー異状が発生するトランザクションの同時実行例" /></center></p>
<p><center></p>
<p style="margin-top: -30px;"><b>図 3　書込みスキュー異状が発生するトランザクションの同時実行例</b></p>
<p></center></p>
<p><strong>【読取り専用トランザクション異状】(read-only transaction anomaly)</strong><br />
&emsp;3 つのトランザクション間に生起する異状で，そのうちの 2 つは更新トランザクションですが，1 つは読取り専用トランザクションで，この読取り専用トランザクションで発生する異状です．そこで，T<sub>1</sub>, T<sub>2</sub> を更新トランザクション, T<sub>3</sub> を読取り専用トランザクションとし，それらが SI の下で，<strong>図 4</strong> に示されたように同時実行されたとします．</p>
<p><center><img decoding="async" style="margin-top: -12px; width: 430px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/09/drmasunaga-08-P09-02.png" alt="読込み専用トランザクション異状が発生するトランザクションの同時実行例" /></center></p>
<p><center></p>
<p style="margin-top: -30px;"><b>図 4　読込み専用トランザクション異状が発生するトランザクションの同時実行例</b></p>
<p></center></p>
<p>&emsp;First-Committer-Wins ルールに従い，T<sub>1</sub> は y<sub>1</sub>=20 として問題なくコミットします（c<sub>1</sub>）．同様に T<sub>2</sub> は x<sub>2</sub>=－11 として問題なくコミットします（c<sub>2</sub>）．T<sub>3</sub> は読取り専用トランザクションなので，問題なくコミットします（c<sub>3</sub>）．<br />
&emsp;さて，このトランザクションの同時実行に問題はなかったのでしょうか？いや，実は，大きな問題があるのです．T<sub>3</sub> が返すデータ項目 x，y の値はそれぞれ 0 と 20 です．しかし，x=0, y=20 という結果は，T<sub>1</sub>, T<sub>2</sub>, T<sub>3</sub> をどのように直列実行しても得られる結果ではなく，意味不明です．このことについて付加的な説明を加えると，トランザクションが同時実行されたときに，その結果が正しいとはトランザクション群のある直列実行が存在して，その時に得られる結果になる，ということです．実際，T<sub>1</sub>, T<sub>2</sub>, T<sub>3</sub> の直列実行の仕方は3! (=6) 通りありますが，それらが返す x と y の値は次の通りです．ここで，例えば，T<sub>1</sub>→T<sub>2</sub>→T<sub>3</sub> はトランザクションが T<sub>1</sub>，T<sub>2</sub>，T<sub>3</sub> の順に直列実行されたことを表します．</p>
<p><center><img decoding="async" style="margin-top: -12px; width: 320px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/09/drmasunaga-08-P10-01.png" alt="直列実行" /></center> <br />
つまり，図 4 に示した T<sub>3</sub> は x=0, y=20 を返したのですが，これは T<sub>1</sub>, T<sub>2</sub>, T<sub>3</sub> のどのような直列実行の結果ともなっておらず，<ruby>おかしい<rt style="background-color: #dddddd;">・・・・</rt></ruby>というわけです．T<sub>3</sub> の返した結果は一体何だったのでしょうか？<br />
&emsp;なお，図中，wr は wr-dependency （wr-従属性）の存在を示しています（wr-従属性の説明は 3.3 節）．</p>
<p><strong>3.3 SII</strong><br />
&emsp;書込みスキュー異状や読込み専用トランザクション異状が発生するので，SI では真の意味での直列化可能性を保証できないということで，「SI を真の意味での直列化可能にする」ための研究が行われ，<strong>直列化可能スナップショット隔離性</strong>（serializable snapshot isolation，<strong>SSI</strong>）が Fekete ら[9]によって提案されました．まず，その定義を見てみたいと思いますが，鍵となる概念は SI の下でのデータ項目への書きや読みの間に観察される <strong>rw-従属性</strong>（rw-dependency）です．このような従属関係を基に<strong>直列化グラフ</strong>（serialization graph）を作成すると，SI の下で実行されるトランザクションの直列化可能性を規定することができ，SSI を定義できます．このことを，シドニー大学の研究者の論文 [8, 9, 10]を参考にして，少し詳しく見ていきましょう．<br />
&emsp;まず，一般に，MVCC や SI といった多版同時実行制御のもとで生成される多版スケジュールの直列化可能性は，<strong>多版直列化グラフ</strong>（multiversion serialization graph, <strong>MVSG</strong>）を用いて説明することができます．First-Committer-Wins ルールが，x の版を生成する 2 つのトランザクションの間では，一方が開始する前に他方がコミットしていることを保証している SI の下では，データ項目 x の版はそれらの版を作成したトランザクションの時系列に従って順序付けられるので，それに基づき MVSG を次のように定義できます．つまり，MVSG では，次の状況 (i)～(iii) のときに，あるコミット済みトランザクション T<sub>1</sub> から別のコミット済みトランザクション T<sub>2</sub> にエッジ（edge，辺）を設定します．</p>
<p style="margin-top: -10px;" >　(i)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
&emsp;T<sub>1</sub> は x の版を生成し，T<sub>2</sub> は x の新しい版を生成している（ww-従属性）．
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >&emsp;(ii)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
&emsp;T<sub>1</sub> は x の版を生成し，T<sub>2</sub> はこの（またはそれ以降の）版の x を読み取っている（wr-従属性）．
</td>
</tbody>
</table>
<p style="margin-top: -10px;" >&emsp;(iii)</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
&emsp;T<sub>1</sub> は x の版を読取り，T<sub>2</sub> は x の新しい版を生成している（rw-従属性）．
</td>
</tbody>
</table>
<p>&emsp;<strong>図 5</strong> に図 3 に示した書込みスキュー異状が生じたトランザクション T<sub>1</sub> と T<sub>2</sub> の同時実行の MVSG を示します．rw-従属性が点線の矢印で示されています．</p>
<p><center><img decoding="async" style="margin-top: -12px; width: 280px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/09/drmasunaga-08-P11-01.png" alt="書込みスキュー異状（図 3）のMVSG" /></center></p>
<p><center></p>
<p style="margin-top: -30px;"><b>図 5　書込みスキュー異状（図 3）のMVSG</b></p>
<p></center></p>
<p>&emsp;さて，トランザクション理論で知られているように[4]，一般に MVSG にサイクルがないことは，トランザクションの同時実行が直列化可能であることを保証します．したがって，同時実行制御に SI を使用するシステムでどのような種類の MVSG が発生する可能性があるかを理解することが重要になります．<br />
&emsp;このことについて，Fekete ら[9, 10]は，「どのサイクルにも隣接して発生する 2 つの rw-従属性エッジがあり，さらに，これらのエッジのそれぞれが 2 つの同時実行されているトランザクションの間にあること」を示しました．そこで，同時実行されているトランザクション間の rw-従属性を<strong>脆弱なエッジ</strong>（vulnerable edge）と呼ぶことにし，サイクル内で 2 つの連続した脆弱なエッジが発生する状況を<strong>危険な構造</strong>（dangerous structure）と呼ぶことにします．これを<strong>図 6</strong> に示します．2 つの連続する脆弱なエッジの接合部のトランザクションを<strong>ピボット</strong>（pivot）トランザクションと呼びます．図 6 では T<sub>1</sub> がピボットです．そのうえで，SI のもとで直列化可能とならない同時実行の MVSG には必ずピボットがあることを示しました．</p>
<p><center><img decoding="async" style="margin-top: -12px; width: 440px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/09/drmasunaga-08-P11-02.png" alt="MVSG における「危険な構造」の一般化" /></center></p>
<p><center></p>
<p style="margin-top: -30px;"><b>図 6　MVSG における「危険な構造」の一般化</b></p>
<p></center></p>
<p><strong>■　SI で書込みスキュー異状が発生することの説明</strong><br />
&emsp;図 3 を使って説明します．図 3 では rw-従属性を 2 つ確認できます．一つは T<sub>2</sub> がデータ項目 x を読んだ後に T<sub>1</sub> がデータ項目 x を更新しています．もう一つは，T<sub>1</sub> がデータ項目 y を読んだ後に T<sub>2</sub> がデータ項目 y を更新しています．では，これらのことは SI というトランザクションの同時実行環境下ではどういう意味を持つのでしょうか？<br />
&emsp;まず，前者の場合ですが，SI の定義を思い出してください，次のようになります．「T<sub>2</sub> は，それが開始された時点で有効なコミット済みデータからなるスナップショットから常にデータを読み取る．T<sub>2</sub> の開始後にアクティブな他のトランザクションの更新は，T<sub>2</sub> には見えない」ということです．これは何を意味するのでしょうか？明らかです．T<sub>1</sub> が T<sub>2</sub> より先に実行され T<sub>1</sub> が開始される以前にコミットされては困る，ということを表しています．（First-Committer-Wins ルールの場合．もし，First-Updater-Wins ルールの場合は，T<sub>1</sub> が開始される以前にデータ項目 x を更新されては困る，となります）つまり，このことを回避するには，T<sub>2</sub> の実行を T<sub>1</sub> に先行させればよいわけです．このことを rw-従属性 T<sub>2</sub> <ruby>⇢<rt style="background-color: #dddddd;">rw</rt></ruby> T<sub>1</sub> で表したわけです．データ項目 y に関する後者の場合も同様で，rw-従属性 T<sub>1</sub> <ruby>⇢<rt style="background-color: #dddddd;">rw</rt></ruby> T<sub>2</sub> が得られます．この 2 つの rw-従属性から図 5 に示した書込みスキュー異状の MVSG が得られたわけです．明らかに，このグラフには「危険な構造」があります．したがって，T<sub>1</sub> と T<sub>2</sub> のこのスケジュールでの同時実行は直列化可能ではなかったことが分かります．</p>
<p><strong>■　SI で読取り専用トランザクション異状が発生することの説明</strong><br />
&emsp;図 4 で示した読取り専用トランザクション異状の同時実行から MVSG を作成すると<strong>図 7</strong> のようになります．明らかにこのグラフには「危険な構造」があります．したがって，図 4 に示した同時実行のスケジュールは直列化可能でないことが分かります．</p>
<p><center><img decoding="async" style="margin-top: -12px; width: 400px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/09/drmasunaga-08-P12-01.png" alt="読取り専用トランザクション異状（図 4）のMVSG" /></center></p>
<p><center></p>
<p style="margin-top: -30px;"><b>図 7　読取り専用トランザクション異状（図 4）の MVSG</b></p>
<p></center></p>
<p>&emsp;さて，ここまで議論すると，SI の下で直列化可能を実現するための考え方は，ほぼ明らかになったと言えます．トランザクションを同時実行していく過程で MVSG を作り，そこに「危険な構造」を見つけたら，それを解消するために何らかのトランザクションをアボート（abort）すればよいわけです．しかしながら，危険な構造は「<ruby>サイクル<rt style="background-color: #dddddd;">・・・・</rt></ruby>内で 2 つの連続した脆弱なエッジが発生する状況」であったのですが，そのためには同時実行されているすべてのトランザクションの実行を監視してそれら間の rw/wr/ww-従属性からサイクルが発生していないかを見つけなければなりません．Cahill ら[10]はそのコストは尋常ではないと考え，サイクルが形成されているかどうかは無視して，<strong>2 つの連続した脆弱なエッジが発生する状況</strong>を検知することだけにしました．その代償として，SSI では<strong>擬陽性</strong>（false positive）が発生してしまうのです．</p>
<p><strong>【定義 2】(SSI)</strong><br />
&emsp;SI の下で実行されるトランザクションの同時実行において，「2 つの連続した脆弱なエッジが発生する状況」を検知した場合は，直列化可能ではないと判定する．そうでなければ，SI の下で，直列化可能なトランザクションの同時実行が保証される．</p>
<p>&emsp;この定義に基づく SSI の実装は，まず，T を同時実行しているトランザクションとして，2 つのブールフラッグ（boolean flag）T.inConflict と T.outConflict を定義します．T.inConflict は同時実行されている何らかのトランザクションから T に rw-従属性があるか否かを示します．一方，T.outConflict はTから同時実行している何らかのトランザクションに rw-従属性があるか否かを示します．さらに，これらの情報を繋いで「2 つの連続した脆弱なエッジが発生する状況」を検知するために，通常の WRITE ロックとこのために特別に用意した SIREAD ロックを導入して行います．詳細に興味のある読者は Cahill らの論文[10]にあたってください．</p>
<p><strong>【擬陽性】</strong><br />
&emsp;擬陽性を呈するトランザクションの同時実行例を<strong>図 8</strong> に示します．</p>
<p><center><img decoding="async" style="margin-top: -12px; width: 460px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/09/drmasunaga-08-P13-01.png" alt="擬陽性が発生するトランザクションの同時実行例" /></center></p>
<p><center></p>
<p style="margin-top: -30px;"><b>図 8　擬陽性が発生するトランザクションの同時実行例</b></p>
<p></center></p>
<p>&emsp;ちなみに，図 8 で示されたトランザクションの同時実行の MVSG を描くと<strong>図 9</strong> に示すとおりです．明らかに，そこには「危険な構造」があります．したがって，トランザクションの直列化可能性を損なう恐れがあるということで，ピボットの T<sub>1</sub> あるいは T<sub>2</sub> でも T<sub>3</sub> でも構いませんが，いずれかのトランザクションをアボートすることを SSI スケジューラは行うということです．</p>
<p><center><img decoding="async" style="margin-top: -12px; width: 340px;" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/09/drmasunaga-08-P14-01.png" alt="擬陽性が発生するトランザクションの同時実行例（図8）のMVSG" /></center></p>
<p><center></p>
<p style="margin-top: -30px;"><b>図 9　擬陽性が発生するトランザクションの同時実行例（図 8）の MVSG</b></p>
<p></center></p>
<p>&emsp;では，何が，問題だったのでしょうか？この原因は明らかです．図 6 に示したように，本来は危険な構造をその一部とする rw/wr/ww-従属性の「サイクル」が存在するときに初めて直列化可能ではないと言えるのですが，SSI ではサイクル検出には膨大なコストが掛かることを懸念して，「危険な構造」ではなく「2 つの連続した脆弱なエッジが発生する状況」を検出したら，それだけで直列化可能ではないと判定してしまったということです．ただ，これに関しては，擬陽性はめったに起こらないと釈明しています[10]．</p>
<h4>4. おわりに</h4>
<p style="margin-top: -10px;">
&emsp;MVCC とは多版の概念を持ち込むことによりトランザクションの同時実行性の向上を目指した技術です．本稿では，MVCC の原型であるMVTO にまず焦点を当てて，2PL では同時実行できないトランザクションが MVCC では同時実行できることを示して，その考え方の基本を示しました．続いて，MVCC の考え方に則った SI に焦点を当てて，その考え方と，それが SQL の隔離性水準である SERIALIZABLE を実現するが，書込みスキュー異状や読取り専用トランザクション異状が発生し，理論的な意味での真の直列化可能性を実現するものではないことに言及しました．SI は真の直列化可能性を実現できる SSI に進化しましたが，SSI の現実的な実装では擬陽性という異状が発生してしまう可能性のあることも紹介しました．SI 並びに SSI の性能評価については先に紹介した通り，SI の下で TPC-C ベンチマークが異状を発生することなく実行可能であること，SSI の性能は様々なケースで 2PL より大幅に改善し，往々にして SI と同程度であったとの報告があることを紹介しました．<br />
&emsp;PostgreSQL では隔離性水準を REPETABLE READ に設定すると SI が，SERIALIZABLE に設定すると SSI が駆動するように実装されています．また，PostgreSQL 14.1 Documentation（Chapter 13. Concurrency Control. 13.1 Introduction）[13] には次のような記載があります（アンダーラインは筆者による）．“Table- and row-level locking facilities are also available in PostgreSQL for applications which don&#8217;t generally need full transaction isolation and prefer to explicitly manage particular points of conflict. <u>However, proper use of MVCC will generally provide better performance than locks.</u>”このように，PostgreSQL はロック法ではなく MVCC の使用を推奨しているようです．<br />
&emsp;このような状況ですが，隔離性水準を READ COMMITTED に設定して（このレベルでは lost update，すなわち ww-conflict が発生することがある），表レベル及び行レベルのロック機能を使って特定の競合ポイントを明示的に管理することで，ちゃんとアプリケーション開発を行っている事例のあることは筆者の耳にするところです．ベンチマークテストの結果はもちろん参考になるとは思いますが，2PL vs. MVCC の議論の<ruby>要<rt style="background-color: #dddddd;">かなめ</rt></ruby>は，データベースアプリケーション開発の現場で発生するトランザクション群の同時実行制御にどちらが適しているのか，雰囲気や時代に流されるのではなく，それを見極める「力」が現場に求められているということではないでしょうか．</p>
<p><strong>【文献】</strong></p>
<p style="margin-top: -10px;" >[1]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
D.P. Reed. Naming and Synchronization in a Decentralized Computer System. MIT-LCS-TR-205, September, 1978.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[2]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
P.A. Bernstein and N. Goodman. Concurrency Control in Distributed Database Systems. ACM Computing Surveys, Vol.13, No.2, pp.185-221, 1981.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[3]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
P.A. Bernstein and N. Goodman. Multiversion concurrency control—theory and algorithms. ACM Transactions on Database Systems, Vol.8, No.4, pp.65-483, 1983.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[4]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
P.A. Bernstein, V. Hadzilacos and N. Goodman. Concurrency Control and Recovery in Database Systems (Book). Addison-Wesley Publishing Company, 1987.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[5]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
H. Berenson, P. Bernstein, J. Gray, J. Melton, E. O’Neil and P. O’Neil. A Critique of ANSI SQL Isolation Levels. Proceedings of the ACM SIGMOD International Symposium on Management of Data, pp.1-10, 1995.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[6]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
Per-Åke Larson, Spyros Blanas, Cristian Diaconu, Craig Freedman, Jignesh M. Patel and Mike Zwilling. High-Performance Concurrency Control Mechanisms for Main-Memory Databases. Proceedings of the VLDB Endowment, Vol. 5, No. 4, 298-309, 2012.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[7]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
H.-T. Kung and J.T. Robinson. On Optimistic Methods Concurrency Control. ACM Transactions on Database Systems, Vol.6, No.2, pp.213–226, 1981.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[8]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
A. Fekete, E. O’Neil and P. O’Neil. A Read-Only Transaction Anomaly Under Snapshot Isolation. ACM SIGMOD Record, Vol. 33, No. 3, pp.12–13, 2004.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[9]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
A. Fekete, D. Liarokapis, E. O’Neil, P. O’Neil and D. Shasha. Making Snapshot Isolation Serializable. ACM Transactions on Database Systems, Vol. 30, No. 2, pp.492–528, 2005.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[10]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
M.J. Cahill, U. Roehm and A. Fekete. Serializable Isolation for Snapshot Databases. Proceedings of the ACM SIGMOD International Symposium on Management of Data, pp.729-738, 2008.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[11]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
増永良文．リレーショナルデータベース入門[第3版]．サイエンス社，2017年．
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[12]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
D.R.K. Ports and K. Grittner. Serializable Snapshot Isolation in PostgreSQL. Proceedings of the International Conference on Very Large Data Bases, pp.1850-1861, 2012.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[13]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
PostgreSQL 14.1 Documentation.<br />
<a href="https://www.postgresql.org/docs/14/index.html" target="_blank" rel="noopener noreferrer">https://www.postgresql.org/docs/14/index.html</a>
</td>
</tbody>
</table>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>増永教授のDB特論⑥「RDB 設計のための分解的 vs. 合成的アプローチ」</title>
		<link>https://www.sraoss.co.jp/tech-blog/db-special-lecture/masunaga-db-special-lecture-6/</link>
		
		<dc:creator><![CDATA[増永良文 (Yoshifumi Masunaga)]]></dc:creator>
		<pubDate>Wed, 08 Jun 2022 04:00:52 +0000</pubDate>
				<category><![CDATA[増永教授のDB特論]]></category>
		<category><![CDATA[3NF]]></category>
		<category><![CDATA[RDB]]></category>
		<category><![CDATA[リレーショナルデータベース]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=10072</guid>

					<description><![CDATA[&#160; 1. はじめに &#8195;リレーショナルデータベース（RDB）設計には分解的アプローチと合成的アプローチの 2 つがあることは皆さんよくご存じのことと思います． &#8195;分解的アプローチ（decomp ...]]></description>
										<content:encoded><![CDATA[<p>&nbsp;<br />
<span id="more-10072"></span></p>
<h4>1. はじめに</h4>
<p style="margin-top: -10px;">
&emsp;リレーショナルデータベース（RDB）設計には分解的アプローチと合成的アプローチの 2 つがあることは皆さんよくご存じのことと思います．<br />
&emsp;<b>分解的アプローチ</b>（decomposition approach）はリレーショナルデータモデルを考案したコッド（E.F. Codd）により導入された「リレーションの正規化理論」[1, 2]に依って立つ RDBの設計法で，これまで多くの説明がなされているのでその認知度は大変高いと思います．このアプローチでは更新時異状（update anomaly）を解消するために，リレーションを関数従属性（FD）や多値従属性（MVD），<br />
あるいは結合従属性（JD）を使って情報無損失分解して，第 1 正規形（1NF）から第 2 正規形（2NF），第 3 正規形（3NF），ボイス‐コッド正規形（BCNF），第 4 正規形（4NF），第 5 正規形（5NF）へと正規度を高めていきます．しかしながら，情報無損失分解と関数従属性保存は独立した概念なので，正規化により関数従属性が保存されない場合が生じることに十分注意する必要があります[3]．<br />
&emsp;一方，<b>合成的アプローチ</b>（synthetic approach）はバーンシュタイン（P.A. Bernstein）によって提案された RDB の設計法 [4] で，RDB を設計するにあたり，データベース化の対象となった世界をリレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>)と所与の FD 集合 <span style="font-style: italic;">F</span> を指定して，それを基に「関数従属性保存・3NF・情報無損失分解」と三拍子揃った RDB を設計する手法です．このアプローチでは，<span style="font-style: italic;">F</span> を構成している FD は必ず設計された RDB を構成するいずれかのリレーションスキーマの FD として定義されるので，関数従属性保存となります．</p>
<p>&emsp;以下で見るように，データベース化の対象となった世界は同一でも，分解的アプローチにより設計された RDB と合成的アプローチにより設計された RDB は一般的には異なった構成となります．では，どう違うのでしょうか？また，その差異はどのように説明されるのでしょうか？本稿では，この 2 つに焦点を当てて<ruby>蘊蓄<rt style="background-color: #DDDDDD;">うんちく</rt></ruby>を傾けてみたいと思います．</p>
<h4>2. 基礎的事項</h4>
<p style="margin-top: -10px;">
&emsp;RDB 設計の分解的アプローチとそれに係る基礎的事項は本稿の読者には改めて説明する必要はないと考えられるので省略します．ここでは，合成的アプローチの理解に必要な事項のみを掻い摘んで説明します．</p>
<p>&emsp;まず，リレーションスキーマの定義とそれに関連する定義を示します．<br />
<strong>【定義 1】</strong>（リレーションスキーマ）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> とはリレーション名 R と属性集合 Ω<sub><b><span style="font-style: italic;">R</span></b></sub>={A<sub>1</sub>, A<sub>2</sub>,<sub> …</sub, A<sub>n</sub>} からなり，<b><span style="font-style: italic;">R</span></b>(A<sub>1</sub>, A<sub>2</sub>,<sub> …</sub>, A<sub>n</sub>)と表される．リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の FD 集合 <span style="font-style: italic;">F</span>={f<sub>1</sub>, f<sub>2</sub>,<sub> …</sub>, f<sub>p</sub>}を指定することができる．リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A<sub>1</sub>, A<sub>2</sub>,<sub> …</sub>, A<sub>n</sub>)に所与の FD 集合 <span style="font-style: italic;">F<sub>R</sub></span> が指定されていることを明示したいとき，<b><span style="font-style: italic;">R</span></b>=(Ω<sub><span style="font-style: italic;">R</sub></span>, <span style="font-style: italic;">F<sub>R</sub></span>)と表すこととする．ここに，Ω<sub><span style="font-style: italic;">R</sub></span> ={A<sub>1</sub>, A<sub>2</sub>,<sub> …</sub>, A<sub>n</sub>}，<span style="font-style: italic;">F<sub>R</sub></span>={f<sub>1</sub>, f<sub>2</sub>,<sub> …</sub>, f<sub>p</sub>}である．</p>
<p><strong>【定義 2】</strong>（リレーションスキーマタの等価）<br />
&emsp;<b><span style="font-style: italic;">R</span></b><sub>1</sub>=(Ω<sub><span style="font-style: italic;">R</sub></span><sub>1</sub>, <span style="font-style: italic;">F<sub>R</sub></span><sub>1</sub>)と<b><span style="font-style: italic;">R</span></b><sub>2</sub>=(Ω<sub><span style="font-style: italic;">R</sub></span><sub>2</sub>, <span style="font-style: italic;">F<sub>R</sub></span><sub>2</sub>)をリレーションスキーマタとする．<b><span style="font-style: italic;">R</span></b><sub>1</sub> と <b><span style="font-style: italic;">R</span></b><sub>2</sub> が<b>等価</b>（equivalent，同値ともいう）とは次の条件が成立するときとし，<b><span style="font-style: italic;">R</span></b><sub>1</sub>≡<b><span style="font-style: italic;">R</span></b><sub>2</sub> と表すこととする．ここに，∧は論理積，<span style="font-style: italic;">F<sub>R</sub></span><sub>1</sub><sup>+</sup> は <span style="font-style: italic;">F<sub>R</sub></span><sub>1</sub> の閉包（定義 3 参照）を表す（<span style="font-style: italic;">F<sub>R</sub></span><sub>2</sub><sup>+</sup> についても同様）．iff は if and only if を表す．<br />
&emsp;&emsp;&emsp;<b><span style="font-style: italic;">R</span></b><sub>1</sub>≡<b><span style="font-style: italic;">R</span></b><sub>2</sub> iff Ω<sub><span style="font-style: italic;">R</sub></span><sub>1</sub>=Ω<sub><span style="font-style: italic;">R</sub></span><sub>2</sub> ∧ <span style="font-style: italic;">F<sub>R</sub></span><sub>1</sub><sup>+</sup>= <span style="font-style: italic;">F<sub>R</sub></span><sub>2</sub><sup>+</sup></p>
<p><strong>【例題 1】</strong><br />
&emsp;例えば，<b><span style="font-style: italic;">R</span></b><sub>1</sub>=({A, B, C}, {A→B, B→C})，<b><span style="font-style: italic;">R</span></b><sub>2</sub>=({A, B, C}, {A→B, B→C, A→C})，<b><span style="font-style: italic;">R</span></b><sub>3</sub>=({A, B, C}, {A→B, A→C})があった時，<b><span style="font-style: italic;">R</span></b><sub>1</sub> と <b><span style="font-style: italic;">R</span></b><sub>2</sub> は属性集合が同じでかつ{A→B, B→C}<sup>+</sup>={A→B, B→C, A→C}<sup>+</sup> なので等価である（ <b><span style="font-style: italic;">R</span></b><sub>1</sub>≡<b><span style="font-style: italic;">R</span></b><sub>2</sub> ）が，<b><span style="font-style: italic;">R</span></b><sub>1</sub> と <b><span style="font-style: italic;">R</span></b><sub>3</sub> は属性集合は同じであるものの{A→B, B→C}<sup>+</sup>≠{A→B, A→C}<sup>+</sup>なので等価でない（<b><span style="font-style: italic;">R</span></b><sub>1</sub>&#x2262;<b><span style="font-style: italic;">R</span></b><sub>3</sub>）．</p>
<p>&emsp;この等価関係は反射律，推移律，対称律を満たします．リレーションスキーマタの等価関係に言及したのは，後段で，設計された RDB の関数従属性保存を議論するときに必用となるからです．</p>
<p><strong>■　関数従属性の集合 <span style="font-style: italic;">F</span> の極小被覆</strong><br />
&emsp;関数従属性の集合 <span style="font-style: italic;">F</span> が与えられたとき，その<strong>極小被覆</strong>（minimal cover）<span style="font-style: italic;">G</span> を求めるアルゴリズムを示します．このアルゴリズムの時間計算量は多項式時間であり，扱いやすい（tractable）問題です．この証明に興味を抱いた者は拙著 [5] を参照してください．<br />
&emsp;まず，FD の集合 <span style="font-style: italic;">F</span> の閉包 <span style="font-style: italic;">F</span><sup>+</sup> を定義する必要があります．<br />
<strong>【定義 3】</strong>（FD 集合の閉包）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) に所与の FD 集合 <span style="font-style: italic;">F</span> が指定されているとする．このとき，　<strong><b><span style="font-style: italic;">F</span></b> の閉包 <b><span style="font-style: italic;">F</span></b><sup>+</sup></strong> は次のように定義される．ここに，<span style="font-style: italic;">F</span> ⊨ X→Y は X→Y がアームストロングの公理系のもとで <span style="font-style: italic;">F</span> から導出されることを表す．</p>
<p>&emsp;&emsp;&emsp;<span style="font-style: italic;">F</span><sup>+</sup>={X→Y | X, Y⊆Ω<b><sub><span style="font-style: italic;">R</span></sub></b> ∧ F ⊨ X→Y}</p>
<p>&emsp;続いて，極小被覆を定義します．<br />
<strong>【定義 4】</strong>（FD 集合の極小被覆）<br />
&emsp;関数従属性の集合 <span style="font-style: italic;">G</span> が関数従属性の集合 <span style="font-style: italic;">F</span> の極小被覆（minimal cover）であるとは，次の条件を満たすときをいう．<br />
&emsp;&emsp;(a)　<span style="font-style: italic;">G</span> と <span style="font-style: italic;">F</span> は等価（equivalent，同値ともいう），すなわち，<span style="font-style: italic;">G</span><sup>＋</sup>＝<span style="font-style: italic;">F</span><sup>+</sup> である．<br />
&emsp;&emsp;(b)　<span style="font-style: italic;">G</span> の全ての関数従属性は X→A，ここに A は単一の属性，の形をしている．<br />
&emsp;&emsp;(c)　<span style="font-style: italic;">G</span> に，ある関数従属性 X→A と X の真部分集合 Z（Z⊂X）が存在して，<br />
&emsp;&emsp;&emsp;&emsp; <span style="font-style: italic;">G</span>−{X→A}∪{Z→A} と <span style="font-style: italic;">G</span> が等価になることはない．ここに，− は差集合演算である．<br />
&emsp;&emsp;(d)　<span style="font-style: italic;">G</span> に，ある関数従属性 g が存在して，<span style="font-style: italic;">G</span>−{g} と <span style="font-style: italic;">G</span> が等価になることはない．</p>
<p>&emsp;極小被覆を求めるアルゴリズムは次の通りです．<br />
<strong>【FD 集合 <span style="font-style: italic;">F</span> の極小被覆 <span style="font-style: italic;">G</span> を求めるアルゴリズム】</strong><br />
&emsp; (ステップ 1)　<span style="font-style: italic;">G</span> = <span style="font-style: italic;">F</span> とおく．<br />
&emsp; (ステップ 2)　<span style="font-style: italic;">G</span> 中の各関数従属性で右辺（＝被決定子（resultant））が単一の属性で<br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;ないものがあれば（これを X→{ A<sub>1</sub>, A<sub>2</sub>, · · ·, A<sub>p</sub> } とする），右辺が単一<br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;の属性である p 個の関数従属性 X→A<sub>1</sub>, X→A<sub>2</sub>, · · ·, X→A<sub>p</sub> で置き換える．<br />
&emsp; (ステップ 3)　<span style="font-style: italic;">G</span> 中の各関数従属性 X→A に対して，X を構成する各属性 B に対して，<br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;<span style="font-style: italic;">G</span>−{X→A}∪{{X−B}→A} と <span style="font-style: italic;">G</span> が等価ならば，<span style="font-style: italic;">G</span> の X→A を {X−B}→A<br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;で置き換える．<br />
&emsp; (ステップ 4)　<span style="font-style: italic;">G</span> の各関数従属性 X→A に対して，<span style="font-style: italic;">G</span>−{X→A} が <span style="font-style: italic;">G</span> と等価ならば，<br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;<span style="font-style: italic;">G</span> から X→A を取り除く．</p>
<p>&emsp;ステップ 3 とステップ 4 はこの順番で行う必要があります．例えば，リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C)に所与の FD 集合 <span style="font-style: italic;">F</span>={AB→C, C→B, A→B} が指定されているとき，もし，まずステップ 4 を，続いてステップ 3 を適用すると，結果として極小被覆もどきの集合 <span style="font-style: italic;">H</span>= {A→C, C→B, A→B} が得られますが，これは <span style="font-style: italic;">I</span>= <span style="font-style: italic;">H</span>－{ A→B } とすると，A→B は A→C と C→B に推移律を適用すると得られる関数従属性であることから分かるように，<span style="font-style: italic;">H</span><sup>+</sup> = <span style="font-style: italic;">I</span><sup>+</sup> であり，<span style="font-style: italic;">H</span> は極小被覆にはなっていません．</p>
<p>&emsp;ここで，極小被覆を求める簡単な例を示します．<br />
<strong>【例題 2】</strong>（極小被覆を求める）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C, D)に所与の FD 集合 <span style="font-style: italic;">F</span> = {AB→CD, C→D} が指定されているとする．<span style="font-style: italic;">F</span> の極小被覆を求めなさい．<br />
<b>(解答)</b><br />
&emsp;<span style="font-style: italic;">F</span> にステップ 1 とステップ 2 を適用することにより <span style="font-style: italic;">G</span> ={AB→C, AB→D, C→D} となる．ステップ 3 を行う．まず，AB→C の左辺に注目し，A あるいは B が余分ではないか検証する．そこで，A が余分であるかどうかを検証するために，H = G−{AB→C}∪{B→C} とし，<span style="font-style: italic;">H</span><sup>+</sup>= <span style="font-style: italic;">G</span><sup>+</sup> かどうかをチェックする．<span style="font-style: italic;">H</span><sup>+</sup> ⊇ <span style="font-style: italic;">G</span><sup>+</sup> は明らかなので，<span style="font-style: italic;">H</span><sup>+</sup>⊆<span style="font-style: italic;">G</span><sup>+</sup> かどうかをチェックする．そのため <span style="font-style: italic;">H</span> にあり <span style="font-style: italic;">G</span> にない関数従属性 B→C が <span style="font-style: italic;">G</span><sup>+</sup> の元かチェックするが，B の <span style="font-style: italic;">G</span> に関する閉包 B<sup>+</sup> を求めれば，適用する <span style="font-style: italic;">G</span> 中の関数従属性がないので B<sup>+</sup>= {B} である．明らかに，C⊆{B} ではないので，<span style="font-style: italic;">H</span><sup>+</sup>⊆<span style="font-style: italic;">G</span><sup>+</sup> ではなく，よって <span style="font-style: italic;">H</span><sup>+</sup>≠<span style="font-style: italic;">G</span><sup>+</sup> である．以下同様な論理でステップ 3 を実行した結果，置き換えられる <span style="font-style: italic;">G</span> の関数従属性はないことが分かる．続いてステップ 4 を行う．<span style="font-style: italic;">I</span> = <span style="font-style: italic;">G</span>−{AB→D} とし，<span style="font-style: italic;">I</span><sup>+</sup> = <span style="font-style: italic;">G</span><sup>+</sup> をチェックする．<span style="font-style: italic;">G</span> の関数従属性 AB→D について，{A, B} の <span style="font-style: italic;">I</span> に関する閉包を求めると，X<sup>(0)</sup> ={A, B}, X<sup>(1)</sup> = X<sup>(0)</sup>∪{C}, X<sup>(2)</sup> = X<sup>(1)</sup>∪{D} (= {A, B, C, D}) = X<sup>(3)</sup>となり，D∈X<sup>(3)</sup> である．したがって，<span style="font-style: italic;">I</span> = {AB→C, C→D} が <span style="font-style: italic;">F</span> の極小被覆となる．この例では <span style="font-style: italic;">I</span> 以外に <span style="font-style: italic;">F</span> の極小被覆はない．</p>
<p style="text-align: right; margin-top: -26px; "><b>(解答終)</b></p>
<p>&emsp;なお，一般に <span style="font-style: italic;">F</span> の極小被覆 <span style="font-style: italic;">G</span> はただ 1 つとは限りません．したがって，最小（minimum）とは言わずに極小（minimal）というわけです．一般に極小被覆が複数個ある簡単な例を示しておきます．</p>
<p><strong>【例題 3】</strong>（一般に極小被覆は複数個ある）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C)に所与の FD 集合 <span style="font-style: italic;">F</span> = {A→BC, B→AC, C→AB} が指定されているとする．<span style="font-style: italic;">F</span> の極小被覆を求めなさい．<br />
<b>(解答)</b><br />
&emsp;<span style="font-style: italic;">G</span>={A→B, A→C, B→A, B→C, C→A, C→B} として，極小被覆を求めるアルゴリズムを稼働すると次の 5 つを得る．<br />
&emsp;&emsp;①　A→B, A→C, B→A, C→A<br />
&emsp;&emsp;②　B→A, B→C, A→B, C→B<br />
&emsp;&emsp;③　C→A, C→B, A→C, B→C<br />
&emsp;&emsp;④　A→B, B→C, C→A<br />
&emsp;&emsp;⑤　A→C, B→A, C→B</p>
<p style="text-align: right; margin-top: -26px; "><b>(解答終)</b></p>
<p><strong>■　関数従属性保存</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> が情報無損失分解されたとき，<b><span style="font-style: italic;">R</span></b> 上で成立していた FD が定義できなくなくなることはない，つまり保存されているという概念が関数従属性保存です．そのためには，まず FD 集合の閉包の射影を定義することが必要です．</p>
<p><strong>【定義 5】</strong>（FD 集合の閉包の射影）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとする．このとき，一般に Z⊆Ω<sub><b><span style="font-style: italic;">R</span></b></sub> として，<b><span style="font-style: italic;">F</span><sup>+</sup>の Z 上の射影 <span style="font-style: italic;">F</span><sup>+</sup>[Z]</b>は次のように定義される．<br />
&emsp;&emsp;&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[Z]={X→Y|X→Y∈<span style="font-style: italic;">F</span><sup>+</sup> ∧ X∪Y⊆Z}</p>
<p>&emsp;&emsp;この定義を用いて関数従属性保存の定義を与えることができます．<br />
<strong>【定義 6】</strong>(関数従属性保存)<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとする．X→Y∈<span style="font-style: italic;">F</span><sup>+</sup>として，X→Yによる <b><span style="font-style: italic;">R</span></b> の <b><span style="font-style: italic;">R</span></b>[X, Y]と <b><span style="font-style: italic;">R</span></b>[Ω<sub><b><span style="font-style: italic;">R</span></b></sub>－Y]への情報無損失分解が関数従属性保存であるとは，次が成立するときをいう．<br />
&emsp;&emsp;&emsp;(<span style="font-style: italic;">F</span><sup>+</sup>[X∪Y]∪<span style="font-style: italic;">F</span><sup>+</sup>[Ω<sub><b><span style="font-style: italic;">R</span></b></sub>－Y])<sup>+</sup>=<span style="font-style: italic;">F</span><sup>+</sup></p>
<p>&emsp;以上で，基礎的事項の説明は終了です．<span style="font-style: italic;">F</span><sup>+</sup> を求める具体例や，リレーションスキーマを FD で情報無損失分解した場合に，どのようなときに関数従属性が保存されない状況が発生するのかなどの例題は SRA OSS Tech Blog に収録されている拙稿 [3]に掲載されているので，参照してください．<br />
&emsp;続いて，RDB 設計の合成的アプローチの説明に移りましょう．</p>
<h4>3. RDB 設計の合成的アプローチ</h4>
<p style="margin-top: -10px;">
&emsp;1976 年にバーンシュタイン（P.A. Bernstein）が提案した RDB 設計の<b>合成的アプローチ</b>（synthetic approach）[4] は，データベース化の対象となった世界を表すリレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A<sub>1</sub>, A<sub>2</sub>,<sub> …</sub>, A<sub>n</sub>)に所与の FD 集合 <span style="font-style: italic;">F</span> が指定されているとして，それを基に「関数従属性保存・3NF・情報無損失分解」と三拍子揃った RDB を設計するという手法です．そのアルゴリズムは次の通りです．<br />
<strong>【合成的アプローチによる RDB 設計アルゴリズム】</strong><br />
&emsp; リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとする．このとき，合成的アプローチによる RDB 設計のアルゴリズムは次の通りである．</p>
<p>(ステップ 1)　<span style="font-style: italic;">F</span> の極小被覆 <span style="font-style: italic;">G</span> を一つ見つける．<br />
(ステップ 2)　X を決定子（determinant）に持つ <span style="font-style: italic;">G</span> の全ての関数従属性 X→B<sub>1</sub>, X→B<sub>2</sub>, · · ·, X→B<sub>k</sub><br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;  に対して（<span style="font-style: italic;">G</span> が極小だから各 B<sub>i</sub> は単一属性），Y = {B<sub>1</sub>, B<sub>2</sub>, …, B<sub>k</sub>} とし，リレー<br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;  ションスキーマ <b><span style="font-style: italic;">R</span></b>(X, Y) を作る．この操作を <span style="font-style: italic;">G</span> の全ての関数従属性に対して行う．<br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;  その結果，リレーションスキーマタ <b><span style="font-style: italic;">R</span></b><sub>1</sub>(X<sub>1</sub>, Y<sub>1</sub>), <b><span style="font-style: italic;">R</span></b><sub>2</sub>(X<sub>2</sub>, Y<sub>2</sub>), · · · , <b><span style="font-style: italic;">R</span></b><sub>m</sub>(X<sub>m</sub>, Y<sub>m</sub>) を得る．<br />
 (ステップ 3)　もし，ステップ 2 で作ったリレーションスキーマタ <b><span style="font-style: italic;">R</span></b><sub>1</sub>, <b><span style="font-style: italic;">R</span></b><sub>2</sub>, · · · , <b><span style="font-style: italic;">R</span></b><sub>m</sub> の中に，<b><span style="font-style: italic;">R</span></b> の<br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;  候補キーを含むリレーションスキーマが存在すれば，{ <b><span style="font-style: italic;">R</span></b><sub>1</sub>, <b><span style="font-style: italic;">R</span></b><sub>2</sub>, · · · , <b><span style="font-style: italic;">R</span></b><sub>m</sub> } が所望の<br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;  分解であり，もしそうでなければ <b><span style="font-style: italic;">R</span></b> の候補キーのひとつを K として <b><span style="font-style: italic;">R</span></b><sup>’</sup> (K) を作る<br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;  と（作り方から，<b><span style="font-style: italic;">R</span></b><sup>’</sup> 上には自明でない関数従属性は存在していない），{<b><span style="font-style: italic;">R</span></b><sup>’</sup> (K), <b><span style="font-style: italic;">R</span></b><sub>1</sub>,<br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;  <b><span style="font-style: italic;">R</span></b><sub>2</sub>, · · · , <b><span style="font-style: italic;">R</span></b><sub>m</sub>} が所望の分解である．</p>
<p>&emsp;前述の通り，一般に <span style="font-style: italic;">F</span> の極小被覆 <span style="font-style: italic;">G</span> はただ 1 つとは限らないので，求められた <span style="font-style: italic;">G</span> の違いで，得られる RDB が異なってくる可能性があることに注意します．<br />
&emsp;また，このアルゴリズムの正しさ，つまりこのアルゴリズムにより <b><span style="font-style: italic;">R</span></b> の関数従属性保存で情報無損失な 3NF への分解が得られることは，ステップ 2 とステップ 3 で行った <b><span style="font-style: italic;">R</span></b> の分解が，(1) 関数従属性保存であること，続いて，(2) （各成分リレーションスキーマが）3NFであること，そして，(3) 情報無損失分解であることを証明することで示されます．特に(3)の証明は結構難易度が高いので，ここでは立ち入らないことにしますが，アルゴリズムの正しさの証明は拙著 [5] でも与えられているので，興味を抱いた読者はご参照ください．<br />
&emsp;なお，この手法が合成的と呼ばれるのは，ステップ 2 で同じ決定子を持つ関数従属性がまとめ上げられて 1 つの候補キーが合成されて（synthesized），その結果，1 つのリレーションスキーマが合成されることからきています．</p>
<p><strong>■　実は，3NF より正規度の高い BCNF であること</strong><br />
&emsp;1993年にビンセント（M.W. Vincent）らにより「重複する候補キーのペアがない 3NF リレーションスキーマは BCNF であること」が証明されました[6]．上記，合成的アプローチによる RDB 設計アルゴリズムのステップ 2 を見て分かるように，得られるリレーションスキーマ <b><span style="font-style: italic;">R</span></b>(X, Y)では X のみが候補キーで，<b><span style="font-style: italic;">R</span></b> に重複する候補キーのペアはあり得ません．したがって，合成的アプローチで設計された RDB は BCNF のリレーションスキーマタからなると言えます（もちろん，3NF です）．よって，合成的アプローチは「関数従属性保存・<b>BCNF</b>・情報無損失分解」と三拍子揃った RDB を設計する手法と言い換えた方が正確でしょう．3NF ではなく BCNF となっていることで，3NF ではあるが BCNF ではないリレーションで発生する更新時異状を合成的アプローチで RDB を設計することで抑制することが可能となってきます．このことについては，例題 6 でより具体的に論じます．なお，以下ではこのことを十分に承知したうえで「関数従属性保存・3NF・情報無損失分解」という伝統的な表現を使用します．</p>
<p>&emsp;次章では，上記のアルゴリズムの下で RDB がどのように設計されていくかについてその感触をつかんでいただくと共に，分解的アプローチと合成的アプローチでは，たとえ最初に与えられたリレーションスキーマが同一でも得られた RDB は一般には異なることを観察してみたいと思います．</p>
<h4>4. 分解的 vs. 合成的アプローチ―その差異の本質は？―</h4>
<p style="margin-top: -10px;">
&emsp;本章では，RDB を分解的アプローチと合成的アプローチで設計してみて，両アプローチの違いを観察することによって，特に合成的アプローチの持っている意味合いについて検証してみたいと思います．合成的アプローチの目標は「情報無損失・3NF・関数従属性保存」の RDB を設計することなので，それに合わせて分解的アプローチでの RDB 設計のゴールは「情報無損失・3NF」のリレーションスキーマタからなる RDB を設計することとします．分解的アプローチでは一般に関数従属性は保存されませんから[3]，両者を比較するには妥当な条件設定と考えられます．<br />
&emsp;それでは，幾つかの例題を通して両アプローチで得られた結果を比較し，その差異を検討してみましょう．</p>
<p><strong>【例題 4】</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C, D)に所与の FD 集合 <span style="font-style: italic;">F</span>={A→B,B→C} が指定されているとする．RDB を合成的アプローチと分解的アプローチで設計してみなさい．<br />
<b>(解答)</b><br />
&emsp;(1) 分解的アプローチで設計した RDB<br />
&emsp;&emsp;  <b><span style="font-style: italic;">R</span></b> の候補キーは{A, D}で，<b><span style="font-style: italic;">R</span></b> の非キー属性は B と C であり，B と C は A に関数従属している，<br />
&emsp;&emsp;  つまり{A, D}には完全関数従属していないので <b><span style="font-style: italic;">R</span></b> は 2NF ではない．そこで，B→C を使って<br />
&emsp;&emsp;  <b><span style="font-style: italic;">R</span></b> を <b><span style="font-style: italic;">R</span></b>[<u>B</u>,C] と <b><span style="font-style: italic;">R</span></b>[<u>A</u>, B, <u>D</u>] に情報無損失分解すると，<b><span style="font-style: italic;">R</span></b>[<u>A</u>, B, <u>D</u>]も 2NF ではないので，それを<br />
&emsp;&emsp;  A→B で <b><span style="font-style: italic;">R</span></b>[<u>A</u>, B]と <b><span style="font-style: italic;">R</span></b>[<u>A</u>, <u>D</u>]に情報無損失分解する．その結果，{<b><span style="font-style: italic;">R</span></b>[<u>A</u>, B], <b><span style="font-style: italic;">R</span></b>[<u>B</u>,C], <b><span style="font-style: italic;">R</span></b>[<u>A</u>, <u>D</u>]}が<br />
&emsp;&emsp;  所望の RDB となる．この場合，関数従属性保存であることは A→B が <b><span style="font-style: italic;">R</span></b>[<u>A</u>, B]で，B→C が<br />
&emsp;&emsp;  <b><span style="font-style: italic;">R</span></b>[<u>B</u>,C]で定義されていることから分かる．<br />
&emsp;(2) 合成的アプローチで設計した RDB<br />
&emsp;&emsp;  <span style="font-style: italic;">F</span> 自体が <span style="font-style: italic;">F</span> の極小被覆である(ステップ 1)．A→B の決定子 A と B→C の決定子 B は異<br />
&emsp;&emsp;  なるので，リレーションスキーマタ <b><span style="font-style: italic;">R</span></b><sub>1</sub>(<u>A</u>, B), <b><span style="font-style: italic;">R</span></b><sub>2</sub>(<u>B</u>, C) を得る（ステップ 2）．ところで，<br />
&emsp;&emsp;  <b><span style="font-style: italic;">R</span></b> の候補キーは {A, D} であるが，これは <b><span style="font-style: italic;">R</span></b><sub>1</sub> にも <b><span style="font-style: italic;">R</span></b><sub>2</sub> にも含まれないので，<b><span style="font-style: italic;">R</span></b><sup>’</sup>(<u>A</u>, <u>D</u>) を作<br />
&emsp;&emsp;  る(ステップ 3)．その結果，{<b><span style="font-style: italic;">R</span></b><sub>1</sub>(<u>A</u>, B), <b><span style="font-style: italic;">R</span></b><sub>2</sub>(<u>B</u>, C), <b><span style="font-style: italic;">R</span></b><sup>’</sup>(<u>A</u>, <u>D</u>)}が所望の RDB である．</p>
<p style="text-align: right; margin-top: -26px; "><b>(解答終)</b></p>
<p>&emsp;この例では，どちらのアプローチをとっても，設計された RDB は同一で，共に「情報無損失分解・3NF・関数従属性保存」となっていることが分かります．</p>
<p><strong>【例題 5】</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C, D)に所与の FD 集合 <span style="font-style: italic;">F</span>={A→B, B→C, A→D, D→C}が指定されているとする．RDB を分解的アプローチと合成的アプローチで設計してみなさい．<br />
<b>(解答)</b><br />
&emsp;(1) 分解的アプローチで設計した RDB<br />
&emsp;&emsp;  <b><span style="font-style: italic;">R</span></b> の候補キーは A で，<b><span style="font-style: italic;">R</span></b> の非キー属性 B, C, D は A に完全関数従属しているので，<b><span style="font-style: italic;">R</span></b> は 2NF<br />
&emsp;&emsp;  である．しかし，A→B→C と A→D→Cという推移的関数従属性が存在するので 3NF ではない．<br />
&emsp;&emsp;  そこで，A→B→C を解消するべく，<b><span style="font-style: italic;">R</span></b> を B→C を使って <b><span style="font-style: italic;">R</span></b>[<u>B</u>, C] と <b><span style="font-style: italic;">R</span></b>[<u>A</u>, B, D] に情報無損失<br />
&emsp;&emsp;  分解すると，それらは 3NF になるが D→C を保存できなく，この情報無損失分解は関数従属性<br />
&emsp;&emsp;  保存ではないことが分かる．同様に，A→D→C を解消するべく，<b><span style="font-style: italic;">R</span></b> を D→C を使って <b><span style="font-style: italic;">R</span></b>[<u>D</u>, C]<br />
&emsp;&emsp;  と <b><span style="font-style: italic;">R</span></b>[<u>A</u>, B, D] に情報無損失分解すると，それらは 3NF になるが B→C を保存できなく，この<br />
&emsp;&emsp;  情報無損失分解も関数従属性保存ではないことが分かる[3]．したがって，設計された RDB<br />
&emsp;&emsp;  {<b><span style="font-style: italic;">R</span></b>[<u>B</u>, C], <b><span style="font-style: italic;">R</span></b>[<u>A</u>, B, D]} と {<b><span style="font-style: italic;">R</span></b>[<u>D</u>, C], <b><span style="font-style: italic;">R</span></b>[<u>A</u>, B, D]} はいずれも「情報無損失分解・3NF」ではある<br />
&emsp;&emsp;  ものの関数従属性保存ではない．<br />
&emsp;(2) 合成的アプローチで設計した RDB<br />
&emsp;&emsp;  <span style="font-style: italic;">F</span> 自体が <span style="font-style: italic;">F</span> の極小被覆である(ステップ 1)．A→B，A→D であり，B→C，D→C であるので，<br />
&emsp;&emsp;  リレーションスキーマタ <b><span style="font-style: italic;">R</span></b><sub>1</sub>(<u>A</u>, B, D), <b><span style="font-style: italic;">R</span></b><sub>2</sub>(<u>B</u>, C), <b><span style="font-style: italic;">R</span></b><sub>3</sub>(<u>D</u>, C) を得る（ステップ 2）ところで，<b><span style="font-style: italic;">R</span></b><br />
&emsp;&emsp;  の候補キーは A であるが，A は <b><span style="font-style: italic;">R</span></b><sub>1</sub> に含まれているので，{<b><span style="font-style: italic;">R</span></b><sub>1</sub>(<u>A</u>, B, D), <b><span style="font-style: italic;">R</span></b><sub>2</sub>(<u>B</u>, C) , <b><span style="font-style: italic;">R</span></b><sub>3</sub>(<u>D</u>, C)}<br />
&emsp;&emsp;  が所望の RDB である(ステップ 3)．合成的アプローチをとったことにより，得られた RDB<br />
&emsp;&emsp;  は「情報無損失分解・3NF・関数従属性保存」である．</p>
<p style="text-align: right; margin-top: -26px; "><b>(解答終)</b></p>
<p>&emsp;では，この例で、もう少し詳しく両アプローチを比較・検討してみましょう．両アプローチの下で設計された RDB は次のようでした．</p>
<p>&emsp;&emsp;分解的アプローチ：{<b><span style="font-style: italic;">R</span></b>[<u>B</u>, C], <b><span style="font-style: italic;">R</span></b>[<u>A</u>, B, D]}，あるいは{<b><span style="font-style: italic;">R</span></b>[<u>D</u>, C], <b><span style="font-style: italic;">R</span></b>[<u>A</u>, B, D]}<br />
&emsp;&emsp;合成的アプローチ：{<b><span style="font-style: italic;">R</span></b><sub>1</sub>(<u>A</u>, B, D), <b><span style="font-style: italic;">R</span></b><sub>2</sub>(<u>B</u>, C), <b><span style="font-style: italic;">R</span></b><sub>3</sub>(<u>D</u>, C)}</p>
<p>&emsp;以下，一般性を失うことなく，分解的アプローチで設計された RDB は{<b><span style="font-style: italic;">R</span></b>[<u>B</u>, C], <b><span style="font-style: italic;">R</span></b>[<u>A</u>, B, D]} であるとして議論を進めます．<br />
&emsp;そこで，両者の違いを理解するために，具体的にリレーション R へのタップルの挿入を想定して，その時に観察される現象を見てみることにします．分かり易さのため，<b><span style="font-style: italic;">R</span></b> のインスタンス R は単純に 1 本のタップル (a, b, c, d) からなっている，すなわち R={(a, b, c, d)}，とします．すると，(a, b, c, d) は分解的アプローチでは R[<u>B</u>, C] ={(b, c)}, R[<u>A</u>, B, D] ={(a, b, d)}} と格納され，合成的アプローチでは R<sub>1</sub>(<u>A</u>, B, D) ={(a, b, d)}, R<sub>2</sub>(<u>B</u>, C) ={(b, c)}, R<sub>3</sub>(<u>D</u>, C) ={(d, c)} と格納されます．そこで，R に D→C に抵触するタップル(a’, b’, c’, d)，ここに a’≠a, b≠’b, c≠’c，を挿入しようと<ruby>目論<rt style="background-color: #DDDDDD;">もくろく</rt></ruby>んだ場合，何が起こるのか観察してみます（もちろん，R では D→C が成立していますから (a’, b’, c’, d) を挿入することはできません）．両アプローチの下で設計された RDB で発生する現象は次の通りです．<br />
&emsp;(1) 分解的アプローチで観察される現象</p>
<p style="margin-top: -30px;" >
<table style="border:none; margin-top: -0px; margin-left: 30px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
&emsp;R[<u>B</u>, C] への (b’, c’) の挿入は既存の (b, c) と抵触しないので行えます．また，R[<u>A</u>, B, D] への (a’, b’, d) の挿入は既存の (a, b, d) と抵触しないので行えます．したがって，R[<u>B</u>, C]={(b, c), (b’, c’)}，R[<u>A</u>, B, D]={(a, b, d), (a’, b’, d)} となります．そこで，R[<u>B</u>, C]*R[<u>A</u>, B, D] をとってみると，R[<u>B</u>, C]*R[<u>A</u>, B, D]={(a, b, c, d), (a’, b’, c’, d)} となります．R[<u>B</u>, C] と R[<u>A</u>, B, D] は R の B→C による情報無損失分解なので，これは R= R[<u>B</u>, C]*R[<u>A</u>, B, D]={(a, b, c, d), (a’, b’, c’, d)} を意味することになりますが，R に所与の D→C に抵触することは明らかです．これが B→C による <b><span style="font-style: italic;">R</span></b> の{<b><span style="font-style: italic;">R</span></b>[<u>B</u>, C], <b><span style="font-style: italic;">R</span></b>[<u>A</u>, B, D]} への情報無損失分解が関数従属性保存でないことによる結果なわけです．<br />
&emsp;この現象はよりフォーマルに次のように説明できるでしょう．<br />
&emsp;まず，リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C, D) の B→C による分解は情報無損失分解ですが，それは次式を意味します．ここに，(∀R∈<b><span style="font-style: italic;">R</span></b>)は R は <b><span style="font-style: italic;">R</span></b> の任意のインスタンスを表します．<br />
&emsp;(∀R∈<b><span style="font-style: italic;">R</span></b>)(R=R[B, C]*R[A, B, D])<br />
&emsp;次に，リレーションスキーマ <b><span style="font-style: italic;">R</span></b> の定義は次の通りです．<br />
&emsp;<b><span style="font-style: italic;">R</span></b>=(Ω<sub><b><span style="font-style: italic;">R</span></b></sub>, <span style="font-style: italic;">F</span><sub><b><span style="font-style: italic;">R</span></b></sub>)，ここに，Ω<sub><b><span style="font-style: italic;">R</span></b></sub> ={A, B, C, D}，<span style="font-style: italic;">F</span><sub><b><span style="font-style: italic;">R</span></b></sub>={A→B, B→C, A→D, D→C}．<br />
&emsp;一方，<b><span style="font-style: italic;">R</span></b>[<u>B</u>, C]*<b><span style="font-style: italic;">R</span></b>[<u>A</u>, B, D] のリレーションスキーマとしての定義は次の通りとなります．<br />
&emsp;<b><span style="font-style: italic;">R’</span></b>=<b><span style="font-style: italic;">R</span></b>[<u>B</u>, C]*<b><span style="font-style: italic;">R</span></b>[<u>A</u>, B, D]= (Ω<sub><b><span style="font-style: italic;">R’</span></b></sub>, F<sub><b><span style="font-style: italic;">R’</span></b></sub>)，ここに，Ω<sub><b><span style="font-style: italic;">R’</span></b></sub> ={A, B, C, D}，<span style="font-style: italic;">F</span><sub><b><span style="font-style: italic;">R’</span></b></sub> ={A→B, B→C, A→D}．<br />
&emsp;そこで，<b><span style="font-style: italic;">R</span></b>=(Ω<sub><b><span style="font-style: italic;">R</span></b></sub>, F<sub><b><span style="font-style: italic;">R</span></b></sub>) と <b><span style="font-style: italic;">R’</span></b> =(Ω<sub><b><span style="font-style: italic;">R’</span></b></sub>, F<sub><b><span style="font-style: italic;">R’</span></b></sub>)を比較してみると，Ω<sub><b><span style="font-style: italic;">R</span></b></sub>=Ω<sub><b><span style="font-style: italic;">R’</span></b></sub> ですが，<span style="font-style: italic;">F</span><sub><b><span style="font-style: italic;">R</span></b></sub><sup>+</sup>≠<span style="font-style: italic;">F</span><sub><b><span style="font-style: italic;">R’</span></b></sub><sup>+</sup>です．つまり，<b><span style="font-style: italic;">R</span></b> と <b><span style="font-style: italic;">R’</span></b> はリレーションスキーマとして等価でないことが分かります．<br />
&emsp;従って，分解的アプローチで得られた RDB については，次が成立しているといえます．</p>
<p>&emsp;&emsp;&emsp;(∀R∈<b><span style="font-style: italic;">R</span></b>)(R=R[B, C]*R[A, B, C]) ∧<br />
&emsp;&emsp;&emsp;<b><span style="font-style: italic;">R</span></b> ≢<b><span style="font-style: italic;">R</span></b>[<u>B</u>, C]*R[<u>A</u>, B, D]&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;・・・・・・・・・・(1)
</td>
</tbody>
</table>
<p>&emsp;(2) 合成的アプローチで観察される現象</p>
<p style="margin-top: -30px;" >
<table style="border:none; margin-top: -0px; margin-left: 30px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
&emsp;R<sub>2</sub>(<u>B</u>, C) への (b’, c’) の挿入は既存の (b, c) と抵触しないので行えます．また，R<sub>1</sub>(<u>A</u>, B, D) への (a’, b’, d) の挿入は既存の (a, b, d) と抵触しないので行えます．これらは分解的アプローチでの R[<u>B</u>, C] への (b’, c’) の挿入と R[<u>A</u>, B, D] への (a’, b’, d) の挿入に対応しています．しかし，<br />R<sub>3</sub>(D,C)への (d, c’) の挿入は R<sub>3</sub> (D,C) で D→C が成立しているので既存の (d, c) と抵触しそれを行えません．したがって，よしんば R<sub>2</sub> と R<sub>1</sub> へそれぞれ (b’, c’) と (a’, b’, d) が挿入され，R<sub>2</sub>(<u>B</u>, C)={(b, c), (b’, c’)}，R<sub>1</sub>(<u>A</u>, B, D)={(a, b, d), (a’, b’, d)}となったとしても，R<sub>3</sub> には (d, c’) の挿入は許されずに R<sub>3</sub>(<u>D</u>, C)={(d, c)}のままなので，R=R<sub>2</sub>(<u>B</u>, C)*R<sub>1</sub>(<u>A</u>, B, D)*R<sub>3</sub>(<u>D</u>, C)={(a, b, c, d)}となり，R に D→C に抵触するようなタップルの挿入は許されない仕組みとなっています．つまり，<b><span style="font-style: italic;">R</span></b> の {<b><span style="font-style: italic;">R</span></b><sub>1</sub>(<u>A</u>, B, D), <b><span style="font-style: italic;">R</span></b><sub>2</sub>(<u>B</u>, C), <b><span style="font-style: italic;">R</span></b><sub>3</sub>(<u>D</u>, C)}への分解は情報無損失でかつ関数従属性保存の分解となっています．そして，この現象はよりフォーマルに次のように説明できます．<br />
&emsp;<b><span style="font-style: italic;">R”</span></b>=<b><span style="font-style: italic;">R</span></b><sub>2</sub>(<u>B</u>, C)*<b><span style="font-style: italic;">R</span></b><sub>1</sub>(<u>A</u>, B, D)*<b><span style="font-style: italic;">R</span></b><sub>3</sub>(<u>D</u>, C)= (Ω<sub><b><span style="font-style: italic;">R”</span></b></sub>, <span style="font-style: italic;">F</span><sub><b><span style="font-style: italic;">R”</span></b></sub>) とすると，Ω<sub><b><span style="font-style: italic;">R”</span></b></sub>={A, B, C, D}，<span style="font-style: italic;">F</span><sub><b><span style="font-style: italic;">R”</span></b></sub>={A→B, B→C, A→D, D→C} となり，<b><span style="font-style: italic;">R</span></b> と <b><span style="font-style: italic;">R”</span></b> は等価です．つまり，合成的アプローチで得られた RDB については，次が成立していることとなります．</p>
<p>&emsp;&emsp;&emsp;(∀R∈<b><span style="font-style: italic;">R</span></b>)( R=R<sub>1</sub>(<u>A</u>, B, D)* R<sub>2</sub>(<u>B</u>, C)*R<sub>3</sub>(<u>D</u>, C)) ∧<br />
&emsp;&emsp;&emsp;<b><span style="font-style: italic;">R</span></b>≡<b><span style="font-style: italic;">R</span></b><sub>1</sub>(<u>A</u>, B, D)*<b><span style="font-style: italic;">R</span></b><sub>2</sub>(<u>B</u>, C)*<b><span style="font-style: italic;">R</span></b><sub>3</sub>(<u>D</u>, C) ・・・・・・・・・・(2)
</td>
</tbody>
</table>
<p>&emsp;(1)式と(2)式は分解的アプローチと合成的アプローチの差異をフォーマルに表現していることになります．繰り返しになりますが，両アプローチで設計された RDB は共に情報無損失分解であることは保証されてはいますが，(1)式により分解的アプローチで設計された RDB はリレーションスキーマタの等価関係の不成立により関数従属性保存ではないことを，一方，(2)式により合成的アプローチで設計された RDB はリレーションスキーマタの等価関係の成立により関数従属性保存であることが明確に読み取れます．</p>
<p>&emsp;さて，分解的アプローチで設計された RDB と合成的アプローチで設計された RDB を見比べると，<b><span style="font-style: italic;">R</span></b>[<u>B</u>, C]≡<b><span style="font-style: italic;">R</span></b><sub>2</sub>(<u>B</u>, C), <b><span style="font-style: italic;">R</span></b>[<u>A</u>, B, D]≡<b><span style="font-style: italic;">R</span></b><sub>1</sub>(<u>A</u>, B, D) なので，合成的アプローチで設計された RDB では，分解的アプローチにより設計された RDB と比べて <b><span style="font-style: italic;">R</span></b><sub>3</sub>(<u>D</u>, C) だけ余計（？）に設計されている，と感じるかもしれません．実際，リレーションを RDB に格納するとなると，その分だけ余計にメモリを食うことになります．しかし，上で見た通り，これが関数従属性保存を保証する代償であったわけです．</p>
<p>&emsp;RDB の設計にあたっては，設計者は分解的アプローチを採用するべきか，合成的アプローチを採用するべきか，その選択を迫られます．少し乱暴な表現をすれば，「（データを格納するための）メモリは食わないが関数従属性保存の確約はない分解的アプローチ」を選ぶか，「分解的アプローチに比べれば，一般にはメモリを食うものの関数従属性保存を保証してくれる合成的アプローチ」を選ぶか，その決断を RDB 設計者は行わなくてはならないということです．これが分解的 vs. 合成的アプローチのpros and cons（利点と問題点）の一面です．</p>
<p><strong>■　合成的アプローチでは BCNF にまでなっていることの恩恵</strong><br />
&emsp;ところで，3 章で述べた通り，<u>合成的アプローチで設計された RDB のリレーションスキーマタは 3NF より正規度の高い BCNF となっています</u>．このことが，両アプローチの pros and cons と大いに関係することになります．議論は RDB の更新時異状と絡みます．例題を挙げて論じてみましょう．</p>
<p><strong>【例題 6】</strong><br />
&emsp;ある学校での，学生（学生名で一意識別），学生が履修する科目（科目名で一意識別），そしてその科目を教授する教員（教員名で一意識別）の関係を表すリレーションスキーマを <b><span style="font-style: italic;">SCT</span></b>=(Ω<sub><span style="font-style: italic;">SCT</span></sub>, <span style="font-style: italic;">F</span><sub><span style="font-style: italic;">SCT</span></sub>)，ここに，Ω<sub><span style="font-style: italic;">SCT</span></sub> ={学生，科目名，教員名}，<span style="font-style: italic;">F</span><sub><span style="font-style: italic;">SCT</span></sub> ={{学生名, 科目名}→教員名，教員名→科目名}とする．RDB を分解的アプローチと合成的アプローチで設計してみなさい．<br />
<b>(解答)</b><br />
&emsp;(1) 分解的アプローチで設計した RDB<br />
&emsp;&emsp;  リレーションスキーマ <b><span style="font-style: italic;">SCT</span></b> の候補キーは{学生名, 科目名}と{学生名, 教員名} と 2 つある．<br />
&emsp;&emsp;  したがって，非キー属性は存在しないので 3NF である．そこで，一般性を失うことなく，<br />
&emsp;&emsp;  たとえば，{学生名, 科目名} を主キーとすれば，<b><span style="font-style: italic;">SCT</span></b>(<u>学生名</u>, <u>科目名</u>，教員名)が所望の<br />
&emsp;&emsp;  RDB である．<br />
&emsp;(2) 合成的アプローチで設計した RDB<br />
&emsp;&emsp;  <span style="font-style: italic;">F</span><sub><span style="font-style: italic;">SCT</span></sub> 自体がその極小被覆である(ステップ 1)．{学生名, 科目名}→教員名，教員名→科目名<br />
&emsp;&emsp;  なので，<b><span style="font-style: italic;">R</span></b><sub>1</sub>(<u>学生名</u>, <u>科目名</u>，教員名)と <b><span style="font-style: italic;">R</span></b><sub>2</sub> (<u>教員名</u>，科目名)が得られる(ステップ 2)．<b><span style="font-style: italic;">SCT</span></b><br />
&emsp;&emsp; の候補キーは{学生名, 科目名}と{学生名, 教員名}であるが，<b><span style="font-style: italic;">R</span></b><sub>1</sub> は候補キー{学生名, 科目名}<br />
&emsp;&emsp; を含んでいるので，<b><span style="font-style: italic;">R</span></b><sub>1</sub>(<u>学生名</u>, <u>科目名</u>，教員名)と <b><span style="font-style: italic;">R</span></b><sub>2</sub>(<u>教員名</u>，科目名)が所望の RDB の<br />
&emsp;&emsp; 設計結果となる(ステップ 3)．</p>
<p style="text-align: right; margin-top: -26px; "><b>(解答終)</b></p>
<p>&emsp;さて，両アプローチを比較・検討してみましょう．両アプローチの下で設計された RDB は次のようです．</p>
<p>&emsp;&emsp;&emsp;分解的アプローチ：<b><span style="font-style: italic;">SCT</span></b>(<u>学生名</u>, <u>科目名</u>，教員名)<br />
&emsp;&emsp;&emsp;合成的アプローチ：<b><span style="font-style: italic;">R</span></b><sub>1</sub>(<u>学生名</u>, <u>科目名</u>，教員名), <b><span style="font-style: italic;">R</span></b><sub>2</sub>(<u>教員名</u>，科目名)</p>
<p>この結果で注意しておくべき点は，<b><span style="font-style: italic;">SCT</span></b> と <b><span style="font-style: italic;">R</span></b><sub>1</sub> の属性集合は等しいものの，リレーションスキーマとしてきちんと表現すれば，<b><span style="font-style: italic;">SCT</span></b>=({学生名, 科目名，教員名}, {{学生名, 科目名}→教員名，教員名→科目名})，<b><span style="font-style: italic;">R</span></b><sub>1</sub>=({<u>学生名</u>, <u>科目名</u>，教員名}, {{学生名, 科目名}→教員名})であり，{{学生名, 科目名}→教員名，教員名→科目名}<sup>+</sup>≠{{学生名, 科目名}→教員名}<sup>+</sup>なので，<b><span style="font-style: italic;">SCT</span></b> ≢<b><span style="font-style: italic;">R</span></b><sub>1</sub> であること，もう一つは，<b><span style="font-style: italic;">R</span></b><sub>1</sub> では定義されていない 教員名→科目名 が <b><span style="font-style: italic;">R</span></b><sub>2</sub> で定義されていることです．</p>
<p>&emsp;さて，分解的アプローチではリレーションスキーマ <b><span style="font-style: italic;">SCT</span></b> そのものが RDB の設計ゴールとなり，この場合「情報無損失分解・3NF・関数従属性保存」となっています．一見，めでたしめでたし，と映りますが，よく知られているように，<b><span style="font-style: italic;">SCT</span></b> は 3NF であるが BCNF ではありません．なぜならば，重複する候補キーのペア {学生名, 科目名} と {学生名, 教員名} が存在するからです．したがって，BCNF ではないことによる「更新時異状が発生する」ことになります[5]．これらの異状は，「タップル挿入時異状」，「タップル削除時異状」，「タップル修正時異状」として現れますが，たとえばリレーション SCT が図 1 に示すようであったとすると，以下に示すような現象として観察されます．</p>
<p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; SCT</p>
<p style="margin-top: -430px;" >
<center></p>
<table border=thick>
<tr>
<td style="solid; border-width: 3px; "><center>　　　<u>学生名</u>　　　</center></td>
<p>　　 </p>
<td style="solid; border-width: 3px; "><center>　　<u>科目名</u>　　</center></td>
<td style="solid; border-width: 3px; "><center>　　　教員名　　　</center></td>
</tr>
<tr>
<td style="solid; border-width: 3px; "><center>伊藤</center></td>
<p>　　</p>
<td style="solid; border-width: 3px; "><center>データベース</center></td>
<td style="solid; border-width: 3px; "><center>増永</center></td>
</tr>
<tr>　              </p>
<td style="solid; border-width: 3px; "><center>伊藤</center></td>
<p>　　</p>
<td style="solid; border-width: 3px; "><center>ソフトウェア</center></td>
<td style="solid; border-width: 3px; "><center>西川</center></td>
</tr>
<tr>　              </p>
<td style="solid; border-width: 3px; "><center>中村</center></td>
<p>　　</p>
<td style="solid; border-width: 3px; "><center>データベース</center></td>
<td style="solid; border-width: 3px; "><center>大林</center></td>
</tr>
<tr>　              </p>
<td style="solid; border-width: 3px; "><center>山本</center></td>
<p>　　</p>
<td style="solid; border-width: 3px; "><center>ハードウェア</center></td>
<td style="solid; border-width: 3px; "><center>北川</center></td>
</tr>
</table>
<p></center></p>
<p><center></p>
<p style="margin-top: -30px;" ><b>図 1　分解的アプローチで得られた RDB</b></p>
<p></center></p>
<p>&emsp;<u>タップル挿入時異状</u>：たとえば，新任教員の佐藤が赴任しプログラミングを担当することになったとします．まだ，佐藤先生のプログラミングを履修登録した学生がいないと，タップル(―，プログラミング，佐藤)はキー制約に抵触するので，リレーション SCT には挿入できません．ここに ― はナル（null）を表します．<br />
&emsp;<u>タップル削除時異状</u>：たとえば，学生の伊藤が西川先生の教えるソフトウェアが難しそうなので履修を取りやめたとすると，タップル(伊藤，ソフトウェア，西川)を削除することになりますが，西川先生の教えるソフトウェアを履修している学生が伊藤一人だったので，西川先生がソフトウェアを教えているという事実を SCT に保存できなくなります．もちろん，(―，ソフトウェア，西川)はキー制約に抵触するので挿入できません．<br />
&emsp;<u>タップル修正時異状</u>：たとえば，学生の伊藤がソフトウェアではなく北川先生のハードウェアに履修を変更すると，タップル(伊藤，ソフトウェア，西川)を(伊藤，ハードウェア，北川)に修正するのは良いが，同時に西川先生がソフトウェアを教えているという事実を SCT に保存できなくなります．この更新時異状を解消するために，分解的アプローチでは，SCT を SCT[<u>教員名</u>，科目名]と SCT[<u>学生名</u>，<u>教員名</u>]に情報無損失分解することになりますが，そうすると関数従属性 {学生名, 科目名}→教員名 が保存できなくなるという新たな異状に直面することになります．</p>
<p>&emsp;一方，合成的アプローチではどのような現象が観察されるのか見てみましょう．図 2 に合成的アプローチにより得られた RDB を示します．</p>
<p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; R<sub>1</sub></p>
<p style="margin-top: -430px;" >
<center></p>
<table border=thick>
<tr>
<td style="solid; border-width: 3px; "><center>　　　<u>学生名</u>　　　</center></td>
<p>　　 </p>
<td style="solid; border-width: 3px; "><center>　　<u>科目名</u>　　</center></td>
<td style="solid; border-width: 3px; "><center>　　　教員名　　　</center></td>
</tr>
<tr>
<td style="solid; border-width: 3px; "><center>伊藤</center></td>
<p>　　</p>
<td style="solid; border-width: 3px; "><center>データベース</center></td>
<td style="solid; border-width: 3px; "><center>増永</center></td>
</tr>
<tr>　              </p>
<td style="solid; border-width: 3px; "><center>伊藤</center></td>
<p>　　</p>
<td style="solid; border-width: 3px; "><center>ソフトウェア</center></td>
<td style="solid; border-width: 3px; "><center>西川</center></td>
</tr>
<tr>　              </p>
<td style="solid; border-width: 3px; "><center>中村</center></td>
<p>　　</p>
<td style="solid; border-width: 3px; "><center>データベース</center></td>
<td style="solid; border-width: 3px; "><center>大林</center></td>
</tr>
<tr>　              </p>
<td style="solid; border-width: 3px; "><center>山本</center></td>
<p>　　</p>
<td style="solid; border-width: 3px; "><center>ハードウェア</center></td>
<td style="solid; border-width: 3px; "><center>北川</center></td>
</tr>
</table>
<p></center></p>
<p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; R<sub>2</sub></p>
<p style="margin-top: -430px;" >
<center></p>
<table border=thick>
<tr>
<td style="solid; border-width: 3px; "><center>　　　<u>教員名</u>　　　</center></td>
<p>　　 </p>
<td style="solid; border-width: 3px; "><center>　　科目名　　</center></td>
</tr>
<tr>
<td style="solid; border-width: 3px; "><center>増永</center></td>
<p>                       　</p>
<td style="solid; border-width: 3px; "><center>データベース</center></td>
</tr>
<tr>　              </p>
<td style="solid; border-width: 3px; "><center>西川</center></td>
<p>　</p>
<td style="solid; border-width: 3px; "><center>ソフトウェア</center></td>
</tr>
<tr>　              </p>
<td style="solid; border-width: 3px; "><center>大林</center></td>
<p>　</p>
<td style="solid; border-width: 3px; "><center>データベース</center></td>
</tr>
<tr>　              </p>
<td style="solid; border-width: 3px; "><center>北川</center></td>
<p>　</p>
<td style="solid; border-width: 3px; "><center>ハードウェア</center></td>
</tr>
</table>
<p></center></p>
<p><center></p>
<p style="margin-top: -30px;" ><b>図 2　合成的アプローチで得られた RDB</b></p>
<p></center></p>
<p>&emsp;この場合，<u>分解的アプローチで指摘された更新時異状は発生しません</u>．たとえば，新任教員の佐藤が赴任しプログラミングを担当することになったとすれば，R<sub>2</sub> にタップル（佐藤，プログラミング）を挿入すればそれで済みます．したがって，タップル挿入時異状は発生しません．学生の伊藤が西川先生の教えるソフトウェアが難しそうなので履修を取りやめたとすると，R<sub>1</sub> からタップル(伊藤，ソフトウェア，西川)を削除することになりますが，西川先生がソフトウェアを教えているという事実は R<sub>2</sub> にしっかり保存されています．したがって，タップル削除時異状は観察されません．たとえば，学生の伊藤がソフトウェアではなく北川先生のハードウェアに履修を変更すると，R<sub>1</sub> のタップル(伊藤，ソフトウェア，西川)を(伊藤，ハードウェア，北川)に修正するだけでよく，西川先生がソフトウェアを教えているという事実は R<sub>2</sub> に保存されており，タップル修正時異状は発生しません．</p>
<p>&emsp;フォーマルに上記の議論をまとめておくと，次のようです．<br />
&emsp;分解的アプローチで得られた RDB については，次が成立しています．</p>
<p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;(∀R∈<b><span style="font-style: italic;">R</span></b>)(R=R) ∧ <b><span style="font-style: italic;">R</span></b>≡<b><span style="font-style: italic;">R</span></b>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;・・・・・・・・・・・・・(3)</p>
<p>&emsp;一方，合成的アプローチで得られた RDB については，次が成立していいます．</p>
<p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;(∀R∈<b><span style="font-style: italic;">R</span></b>)( R=R<sub>1</sub>(<u>学生名</u>, <u>科目名</u>，教員名)*R<sub>2</sub>(<u>教員名</u>，科目名)) ∧<br />
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;<b><span style="font-style: italic;">R</span></b>≡<b><span style="font-style: italic;">R</span></b><sub>1</sub>(<u>学生名</u>, <u>科目名</u>，教員名)*<b><span style="font-style: italic;">R</span></b><sub>2</sub>(<u>教員名</u>，科目名) &emsp;・・・・・(4)</p>
<p>&emsp;分解的アプローチ，合成的アプローチ，共に情報無損失分解とリレーションスキーマタの等価関係が肯定的に示されましたが，分解的アプローチでは <b><span style="font-style: italic;">R</span></b> が 3NF ではあるものの BCNF ではありませんでした．一方，合成的アプローチで得られた <b><span style="font-style: italic;">R</span></b><sub>1</sub> と <b><span style="font-style: italic;">R</span></b><sub>2</sub> は共に BCNF です．この差が，分解的アプローチで RDB を設計した場合に，更新時異状発生の原因となったわけです．</p>
<p>&emsp;さて，上に示した現象は，RDB を設計するに当たり，分解的アプローチを採るのか合成的アプローチを採るのかという意思決定に際して，関数従属性保存を保証するために必要となるリレーションを格納するために「メモリ」が増加するという視点に加えて，3NF ではあるが BCNF ではないために発生する「更新時異状」という視点も勘案したうえで，どちらのアプローチを採るかを決定しないといけないということを主張しているということで，この 2 軸を勘案すると，これまた少し乱暴な表現となりますが，その選択は次のようにまとめられると思います．<br />
&emsp;<b>選択 1</b> :（データを格納するための）メモリは食わないが，設計された RDB が関数従属性保存であ<br />
&emsp;&emsp;&emsp;&emsp; るという確約はなく，また，RDB を構成するリレーションスキーマが 3NF ではあるものの<br />
&emsp;&emsp;&emsp;&emsp; BCNF の確約はないので，そのことにより更新時異状が発生するかもしれないというリスク<br />
&emsp;&emsp;&emsp;&emsp; のある分解的アプローチ<br />
&emsp;<b>選択 2</b> : 分解的アプローチに比べれば一般にメモリを食うものの，設計された RDB が関数従属性保<br />
&emsp;&emsp;&emsp;&emsp; 存で，また，RDB を構成するリレーションスキーマが BCNF であるので，3NF ではあるが<br />
&emsp;&emsp;&emsp;&emsp; BCNF ではないことによる更新時異状は発生しないことが約束されている合成的アプローチ</p>
<h4>5. おわりに</h4>
<p>&emsp;本稿では，RDB 設計のための「分解的アプローチ」と「合成的アプローチ」を俎上に上げて<ruby>蘊蓄<rt style="background-color: #DDDDDD;">うんちく</rt></ruby>を傾けました．RDB 設計にあたり与えられたリレーションスキーマと指定された所与の関数従属性の集合が同一でも，分解的アプローチと合成的アプローチでは一般に RDB の設計結果は異なります．分解的アプローチは設計された RDB が「情報無損失分解・3NF」であることは保障してくれますが，一般には関数従属性保存は保証してくれません．一方，合成的アプローチは「情報無損失分解・3NF・関数従属性保存」という 3 拍子揃った RDB 設計を保証してくれます．加えて，合成的アプローチでは作られたリレーションスキーマは厳密には BCNF まで正規度が上がっているので，いわゆるリレーションが 3NF ではあるが BCNF ではないために発生してしまう更新時異状も回避することができます．ただ，合成的アプローチは関数従属性保存を担保する代償として，分解的アプローチに比べて格納するべきデータ量は多くなり，メモリを食うことになります．<br />
&emsp;さて，この二者択一，貴方ならどちらを選択しますか？</p>
<p>【文献】</p>
<p style="margin-top: -10px;" >[1]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
E.F. Codd. A Relational Model of Data for Large Shared Data Banks. Communications of the ACM, Vol.13, No.6, pp.377-387, 1970.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[2]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
E.F. Codd. Further Normalization of the Data Base Relational Model. R. Rustin (Ed.), Data Base Systems (Courant Computer Science Symposia 6). Prentice-Hall, Englewood Cliffs, NJ, 1972.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[3]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
増永良文．増永教授のDB特論⑤「3NF分解と関数従属性保存」，SRA OSS Tech Blog, 2022.05.11.<br />
https://www.sraoss.co.jp/tech-blog/db-special-lecture/masunaga-db-special-lecture-5/
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[4]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
P.A. Bernstein. Synthesizing Third Normal Form Relations from Functional Dependencies. ACM Transactions on Database Systems, Vol.1, No.4, pp.277-298, 1976.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[5]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
増永良文．リレーショナルデータベース入門[第3版]．サイエンス社，2017．
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[6]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
M.W. Vincent and B. Srinivasan. A Note on Relational Schemes Which Are in 3NF But Not in BCNF. Information Processing Letters 48(6), pp. 281–283, 1993.
</td>
</tbody>
</table>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>増永教授のDB特論⑤「3NF 分解と関数従属性保存」</title>
		<link>https://www.sraoss.co.jp/tech-blog/db-special-lecture/masunaga-db-special-lecture-5/</link>
		
		<dc:creator><![CDATA[増永良文 (Yoshifumi Masunaga)]]></dc:creator>
		<pubDate>Wed, 11 May 2022 06:20:55 +0000</pubDate>
				<category><![CDATA[増永教授のDB特論]]></category>
		<category><![CDATA[3NF]]></category>
		<category><![CDATA[RDB]]></category>
		<category><![CDATA[リレーショナルデータベース]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=9814</guid>

					<description><![CDATA[1. はじめに &#8195;リレーショナルデータベース（RDB）を設計するにあたり，「リレーションは第 3 正規形（3NF）にしましょう」とはよく言われることです．リレーションの正規化理論によると，3NF への分解が情報 ...]]></description>
										<content:encoded><![CDATA[<h4>1. はじめに</h4>
<p style="margin-top: -10px;">
&emsp;リレーショナルデータベース（RDB）を設計するにあたり，「リレーションは第 3 正規形（3NF）にしましょう」とはよく言われることです．リレーションの正規化理論によると，3NF への分解が情報無損失であることは間違いのないことですが，その際，関数従属性は保存されるのか，されないのか？このことについて，どうも不確かな認識が流布しているのではないか？と思われる事例に遭遇したので，この記事を書く気になりました．</p>
<p><span id="more-9814"></span><br />
&emsp;その事例とは，何気なく過去の「データベーススペシャリスト試験問題」を眺めていた時に目に留まった次の設問と解答です．</p>
<p><center><u>平成 26 年度 春季 データベーススペシャリスト試験 午前Ⅱ 問題</u> [1]</center></p>
<p style="margin-top: -10px;" >　問 4</p>
<table style="border:none; margin-top: -62px; margin-left: 40px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
&emsp;関係モデルにおいて，情報無損失分解ができ，かつ，関数従属性保存が成り立つ変換が必ず存在するものはどれか。ここで，情報無損失分解とは自然結合によって元の関係が必ず得られる分解をいう。
</td>
</tbody>
</table>
<p>&emsp;&emsp;ア　第 2 正規形から第 3 正規形への変換<br />
&emsp;&emsp;イ　第 3 正規形からボイスコッド正規形への変換<br />
&emsp;&emsp;ウ　非正規形から第 1 正規形への変換<br />
&emsp;&emsp;エ　ボイスコッド正規形から第 4 正規形への変換</p>
<p>&emsp;この問題の正解は「ア」とされています[2]．</p>
<p>&emsp;さて，この設問と正解を眺めていて釈然としない点が 2 つありました．<br />
&emsp;一つは，情報無損失分解の定義は与えられていますが，「関数従属性保存」の定義が与えられていません．果たして，どういう意味でこの用語を使っているのでしょうか？<br />
&emsp;もう一つは，「情報無損失分解ができ，かつ，関数従属性保存が成り立つ変換が<strong>必ず</strong>存在するもの」を問うていますが，「必ず」とは一体どのような意味で使っているのでしょうか？「ア」を正解とするということなので，「リレーションの第 2 正規形から第 3 正規形への変換は必ず情報無損失分解かつ関数従属性保存である」が出題者の意図ではないかと推察されますが，本当にそうなのでしょうか？<br />
&emsp;そこで，本稿では，この問題を少しばかり深堀してみることとしました．</p>
<h4>2. 基礎的事項</h4>
<p style="margin-top: -10px;">
&emsp;議論を進めるために必要な概念を整理しておきます．<br />
<strong>【定義 1】</strong>（リレーションスキーマとリレーション）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> とはリレーション名 R と属性のリスト A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub> からなり，<b><span style="font-style: italic;">R</span></b>(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>) と表される．dom をドメイン関数とするとき，R⊆dom(A<sub>1</sub>)×dom(A<sub>2</sub>)×<sub>…</sub>×dom(A<sub>n</sub>) をリレーションスキーマ <b><span style="font-style: italic;">R</span></b> のインスタンス，あるいは dom(A<sub>1</sub>)，dom(A<sub>2</sub>)，<sub>…</sub>，dom(A<sub>n</sub>) 上のリレーション R という．<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> である性質 <span style="font-style: italic;">P</span> が成立するとは <b><span style="font-style: italic;">R</span></b> のすべてのインスタンス R で <span style="font-style: italic;">P</span> が成立するときおよびその時のみをいう．</P><br />
<strong>【定義 2】</strong>（関数従属性）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> で関数従属性（functional dependency, FD） f=X→Yが成立するとは，次が成立するときをいう．ここに，R∈<b><span style="font-style: italic;">R</span></b> は R が <b><span style="font-style: italic;">R</span></b> のインスタンスであることを表す．<br />
&emsp;&emsp;&emsp;&emsp;(∀R∈<b><span style="font-style: italic;">R</span></b>)(∀t, t<sup>’</sup>∈R)(t[X]=t<sup>&#8216;</sup>[X]⇒t[Y]=t<sup>&#8216;</sup>[Y])</p>
<p><strong>【定義 3】</strong>（所与の関数従属性集合）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の（given）関数従属性の集合 <span style="font-style: italic;">F</span>＝{f<sub>1</sub>, f<sub>2</sub>, <sub>…</sub>, f<sub>p</sub>}，ここに(∀i= 1, 2, …, p)(f<sub>i</sub>=X<sub>i</sub>→Y<sub>i</sub> ∧ X<sub>i</sub>, Y<sub>i</sub>⊆Ω<sub><b><span style="font-style: italic;">R</span></b></sub>)，を指定できる．ここで，Ω<sub><b><span style="font-style: italic;">R</span></b></sub> は <b><span style="font-style: italic;">R</span></b> の全属性集合 {A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>} を表し，一般に X, Y を集合とするとき，X⊆Y は X が Y の部分集合であることを，X⊂Y は X が Y の真部分集合（proper subset）であることを表す．</p>
<p><strong>【定義 4】</strong>（関数従属性集合の閉包）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとする．このとき， <b>F の閉包 <span style="font-style: italic;">F<sup>+</sup></span></b> は次のように定義される．ここに，<span style="font-style: italic;">F</span> ⊨ X→Y は X→Y がアームストロングの公理系のもとで <span style="font-style: italic;">F</span> から導出されることを表す．<br />
&emsp;&emsp;&emsp;&emsp;<span style="font-style: italic;">F</span><sup>+</sup>={X→Y | X, Y⊆Ω<sub><b><span style="font-style: italic;">R</span></b></sub> ∧ <span style="font-style: italic;">F</span> ⊨ X→Y}</p>
<p>&emsp;つまり，<span style="font-style: italic;">F</span><sup>+</sup> は <span style="font-style: italic;">F</span> が与えられたとき， <span style="font-style: italic;">F</span> を基にして <b><span style="font-style: italic;">R</span></b> 上で成立するすべての FD からなる集合を表します．<span style="font-style: italic;">F</span><sup>+</sup> を求めるアルゴリズムを示しますが，その前に，次が成立することに注目します．ここに，　X<sup>+</sup> は <span style="font-style: italic;">F</span> に関する X の閉包を表し，iff は if and only if，すなわち必要かつ十分条件を表します．<br />
&emsp;&emsp;&emsp;&emsp;(∀X, Y⊆Ω<sub><b><span style="font-style: italic;">R</span></b></sub>)(X→Y∈<span style="font-style: italic;">F</span><sup>+</sup> iff Y⊆X<sup>+</sup>)</p>
<p>&emsp;なお，X<sup>+</sup> を求めるアルゴリズムは次のとおりです．このアルゴリズムの時間計算量は多項式時間であり，扱いやすい（tractable）問題です．</p>
<p><strong>【X<sup>+</sup> を求めるアルゴリズム】</strong><br />
&emsp;1． X<sup>(0)</sup>=Xとおく．<br />
&emsp;2． X<sup>(i)</sup>= X<sup>(i－1)</sup>∪{A|A∈Z ∧ Y→Z∈F ∧ Y⊆X<sup>(i－1)</sup>} (i≧1)とする．<br />
&emsp;3． もし，X<sup>(i)</sup>= X<sup>(i－1)</sup> ならX<sup>+</sup>= X<sup>(i－1)</sup> とおく．そうでなければステップ 2 にいく．</p>
<p><strong>【例題1】</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C) に所与の FD 集合 <span style="font-style: italic;">F</span>={A→B, B→C}が指定されているとする．たとえば，X={A} としてX<sup>+</sup> を求めると，ステップ 1 で X<sup>(0)</sup>={A}, ステップ 2 と 3 を繰り返して，X<sup>(1)</sup>= X<sup>(0)</sup>∪{B}, X<sup>(2)</sup>= X<sup>(1)</sup>∪{C} (={A, B, C}), X<sup>(3)</sup>= X<sup>(2)</sup> となり, X<sup>+</sup>={A, B, C}を得る．</p>
<p>&emsp;さて，<span style="font-style: italic;">F</span><sup>+</sup> を求めるアルゴリズムは次のとおりです．</p>
<p><strong>【<span style="font-style: italic;">F</span><sup>+</sup> を求めるアルゴリズム】</strong><br />
&emsp;1． <span style="font-style: italic;">F</span><sup>+</sup>=Φ とおく．<br />
&emsp;2． 2<sup>ΩR</sup>－Φ の各元 X に対してその閉包 X<sup>+</sup>を求め，<span style="font-style: italic;">F</span><sup>+</sup> = <span style="font-style: italic;">F</span><sup>+</sup>∪{X→X<sup>+</sup>} とする．<br />
&emsp;3． ステップ 2 の操作が全て終了すれば，その時の <span style="font-style: italic;">F</span><sup>+</sup> が求める結果である．</p>
<p>&emsp;ステップ 2 で，2<sup>ΩR</sup>－Φ の各元 X に対してその閉包 X<sup>＋</sup> を求めていることから明らかなように，このアルゴリズムの時間計算量は <span style="font-style: italic;">O</span>(2<sup>|ΩR|</sup>)，ここに <span style="font-style: italic;">O</span> はオーダー関数，|Ω<sub><b><span style="font-style: italic;">R</span></b></sub> |は Ω<sub><b><span style="font-style: italic;">R</span></b></sub> の濃度を表す，と指数時間となり，扱いにくい（intractable）問題であることが分かります．つまり，上記のアルゴリズムは|Ω<sub><b><span style="font-style: italic;">R</span></b></sub> |が小さいときは問題なく動きますが，それが大きくなるにつれてとんでもない時間を要することになります．<br />
&emsp;なお，リレーションの情報無損失分解に係る関数従属性保存を論じるためには，<span style="font-style: italic;">F</span><sup>+</sup> の属性集合Z（⊆Ω<sub><b><span style="font-style: italic;">R</span></b></sub>）上の射影 <span style="font-style: italic;">F</span><sup>+</sup>[Z] を定義する必要がありますが（定義 5），それを端的に行うためにはステップ 3 をステップ 3’ に置き換えておくと都合がよいのでそのようにします（射影と関わらない議論はステップ 3 で得られた <span style="font-style: italic;">F</span><sup>+</sup> を念頭に置いて行っています）．<br />
&emsp;3&#8217;． ステップ 2 の操作が全て終了すれば，その時の <span style="font-style: italic;">F</span><sup>+</sup> が求める結果であるが，もし<br />
&emsp;&emsp;&emsp;<span style="font-style: italic;">F</span><sup>+</sup> の元 X→X<sup>+</sup> の被決定子が X<sup>+</sup>=A<sub>1</sub>A<sub>2</sub><sub>…</sub>A<sub>q</sub>（A<sub>i</sub>∈Ω<sub><b><span style="font-style: italic;">R</span></b></sub>, q≧2）のように単一の属性で<br />
&emsp;&emsp;&emsp;でなければ，X→X<sup>+</sup> をX→A<sub>1</sub>, X→A<sub>2</sub>, …, X→A<sub>q</sub>置き換えた <span style="font-style: italic;">F</span><sup>+</sup> を求める結果とする<br />
&emsp;&emsp;&emsp;（この置換えは，X→YZ iff X→Y ∧ X→Z が成立することによる）．<br />
&emsp;&emsp;&emsp;ここに，一般に A<sub>1</sub>A<sub>2</sub><sub>…</sub>A<sub>q</sub> は集合{A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub> , A<sub>q</sub>} の簡略表現とする（以下，同様）．<br />
&emsp;&emsp;&emsp;したがって，たとえば AB={A, B}={B, A}=BA である．</p>
<p><strong>【例題2】</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C)に所与の FD 集合 <span style="font-style: italic;">F</span>={A→B, B→C} が指定されているとする．このとき，<span style="font-style: italic;">F</span><sup>+</sup> を求めると，2<sup>ΩR</sup>={Φ, A, B, C, AB, AC, BC, ABC} であるので，ステップ 1 で <span style="font-style: italic;">F</span><sup>+</sup>=Φ，ステップ 2 と 3 を繰り返して，A<sup>+</sup>=ABC, B<sup>+</sup>=BC, C<sup>+</sup>=C, AB<sup>+</sup>=ABC, AC<sup>+</sup>=ABC, BC<sup>+</sup>=BC, ABC<sup>+</sup>=ABC なので，ステップ 3 で <span style="font-style: italic;">F</span><sup>+</sup> は次のようになる．<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>={A→ABC, B→BC, C→C, AB→ABC, AC→ABC, BC→BC, ABC→ABC}<br />
<span style="font-style: italic;">F</span><sup>+</sup>をステップ 3 ではなくステップ 3’ を用いて求めた場合，それは次のようになる．<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>={A→A, A→B, A→C, B→B, B→C, C→C, AB→A, AB→B, AB→C, AC→A,<br />
&emsp;&emsp;&emsp;AC→B, AC→C, BC→B, BC→C, ABC→A, ABC→B, ABC→C}<br />
なお，一般に <span style="font-style: italic;">F</span><sup>+</sup> には A→A や AB→A など自明な FD も含まれているが，<span style="font-style: italic;">F</span><sup>+</sup> はそれらも含めて <b><span style="font-style: italic;">R</span></b> 上で成り立つ関数従属性の全てからなる集合を表しているということである．</p>
<p><strong>【定義5】</strong>（関数従属性集合の閉包の射影）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとする．このとき，一般に Z⊆Ω<sub><b><span style="font-style: italic;">R</span></b></sub> として，<strong><span style="font-style: italic;">F</span><sup>+</sup> の Z 上の射影 <span style="font-style: italic;">F</span><sup>+</sup>[Z]</strong>は次のように定義される．ここに <span style="font-style: italic;">F</span><sup>+</sup> はステップ 3’ を用いて求められており，A∈Ω<b><sub><span style="font-style: italic;">R</span></sub></b> である．<br />
&emsp;&emsp;&emsp;<strong><span style="font-style: italic;">F</span><sup>+</sup>[Z]</strong>={X→A|X→A∈<span style="font-style: italic;">F</span><sup>+</sup> ∧ X∪A⊆Z}</p>
<p><strong>【例題3】</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C)に所与の FD 集合 <span style="font-style: italic;">F</span>={A→B, B→C} が指定されているとする．このとき，<span style="font-style: italic;">F</span><sup>+</sup> の {B, C} 上の射影，<span style="font-style: italic;">F</span><sup>+</sup>[B, C] は次のようになる．<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[B, C]= {B→B, B→C, C→C, BC→B, BC→C }</p>
<p>&emsp;なお，B, C∈Ω<b><sub><span style="font-style: italic;">R</span></sub></b> としたとき，<span style="font-style: italic;">F</span><sup>+</sup>[B, C]は本来は <span style="font-style: italic;">F</span><sup>+</sup>[{B, C}]あるいは <span style="font-style: italic;">F</span><sup>+</sup>[BC]と書くべきであるが，慣習的に <span style="font-style: italic;">F</span><sup>+</sup>[B, C]と書くことも多く，本稿でもそれに倣っている．</p>
<p><strong>【定義6】</strong>（リレーションスキーマの情報無損失分解）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> の情報無損失分解は <span style="font-style: italic;">F</span><sup>+</sup> の元 X→Y （X，Y⊆Ω<sub><span style="font-style: italic;">R</span></sub></b>）を使って <b><span style="font-style: italic;">R</span></b> を 2 つの射影 <b><span style="font-style: italic;">R</span></b>[X∪Y]と <b><span style="font-style: italic;">R</span></b>[Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y]，ここに － は差集合演算を表す，に分解することをいう．</p>
<p>&emsp;FD による分解はリレーションスキーマが 2 つの射影に情報無損失分解されるための十分条件なので，この分解は情報無損失，すなわち <b><span style="font-style: italic;">R</span></b>=<b><span style="font-style: italic;">R</span></b>[X∪Y]*<b><span style="font-style: italic;">R</span></b>[Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y]が成立することは改めて言うまでもないことです．ここに * は自然結合演算を表しています．</p>
<p>&emsp;ここで，念のためにリレーションスキーマが第 2 正規形（2NF），第 3 正規形（3NF）そしてボイス‐コッド正規形（BCNF）であることの定義を確認しておきます．「リレーションスキーマ <b><span style="font-style: italic;">R</span></b> が第 2 正規形（2NF）であるとは，<b><span style="font-style: italic;">R</span></b> は 1NF であって，<b><span style="font-style: italic;">R</span></b> の全ての非キー属性は <b><span style="font-style: italic;">R</span></b> の各候補キーに完全関数従属している」こと，「リレーションスキーマ <b><span style="font-style: italic;">R</span></b> が第 3 正規形（3NF）であるとは，<b><span style="font-style: italic;">R</span></b> は 2NF であって，<b><span style="font-style: italic;">R</span></b> の全ての非キー属性は <b><span style="font-style: italic;">R</span></b> のいかなる候補キーにも推移的に関数従属しない」こと，そして，リレーションスキーマ <b><span style="font-style: italic;">R</span></b> がボイス‐コッド正規形（BCNF）であるとは，「X→Yを <b><span style="font-style: italic;">R</span></b> の関数従属性とするとき，X→Y は自明な FD であるか，あるいは X は <b><span style="font-style: italic;">R</span></b> のスーパーキーである」ことです．<br />
&emsp;なお，リレーショナルデータモデルと正規化理論の原典に立ち戻って RDB 設計の分解的手法を今一度整理しておきたい向きには文献[3, 4]を，本稿では立ち入らないが分解的手法と対極をなす RDB 設計の合成的手法の原典にあたりたい向きには文献[5]を，そしてそれらをカバーした書籍として拙著[6]を薦めます．</p>
<h4>3. 関数従属性保存とは</h4>
<p style="margin-top: -10px;">
&emsp;まず，リレーションスキーマの情報無損失分解に係る関数従属性保存の定義を与えます．<br />
<strong>【定義7】</strong>(関数従属性保存)<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとする．X→Y∈<span style="font-style: italic;">F</span><sup>+</sup> として，X→Y による <b><span style="font-style: italic;">R</span></b> の <b><span style="font-style: italic;">R</span></b>[X∪Y] と <b><span style="font-style: italic;">R</span></b>[Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y]への情報無損失分解が関数従属性保存とは，次が成立するときをいう．<br />
&emsp;&emsp;&emsp;(<span style="font-style: italic;">F</span><sup>+</sup>[X∪Y]∪<span style="font-style: italic;">F</span><sup>+</sup>[Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y])<sup>+</sup>=<span style="font-style: italic;">F</span><sup>+</sup></p>
<p>&emsp;つまり，<span style="font-style: italic;">F</span> の閉包 <span style="font-style: italic;">F</span><sup>+</sup> の X∪Y 上の射影 <span style="font-style: italic;">F</span><sup>+</sup>[X∪Y] とその Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y 上の射影 <span style="font-style: italic;">F</span><sup>+</sup>[Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y]の和集合の閉包 (<span style="font-style: italic;">F</span><sup>+</sup>[X∪Y]∪<span style="font-style: italic;">F</span><sup>+</sup>[Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y])<sup>+</sup> が <span style="font-style: italic;">F</span><sup>+</sup> と等しいかどうかを問うていて，両者が等しいときに，関数従属性保存と言います．決して <span style="font-style: italic;">F</span>[X∪Y]∪<span style="font-style: italic;">F</span>[Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y]=<span style="font-style: italic;">F</span> を問うているわけではないことに注意してください．あくまで，閉包レベルの概念です．</p>
<p>&emsp;なお，一般にリレーションスキーマ <b><span style="font-style: italic;">R</span></b> を X→Y で<b><span style="font-style: italic;">R</span></b>[X∪Y]と <b><span style="font-style: italic;">R</span></b>[Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y]へ情報無損失分解したとき，もし <b><span style="font-style: italic;">R</span></b>[Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y]に Z→W∈<span style="font-style: italic;">F</span><sup>+</sup>（ここに，Z∪W⊂Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y）が存在していると，<b><span style="font-style: italic;">R</span></b>[Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y]は <b><span style="font-style: italic;">R</span></b>[Z∪W]と <b><span style="font-style: italic;">R</span></b>[Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y－W]へ情報無損失分解可能で，結果として <b><span style="font-style: italic;">R</span></b> は <b><span style="font-style: italic;">R</span></b>[X∪Y]と <b><span style="font-style: italic;">R</span></b>[Z∪W]と <b><span style="font-style: italic;">R</span></b>[Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y－W]に情報無損失分解できます．このとき，上記の関数従属性保存の定義は素直に次のように拡張されます（この拡張はより一般的な形で可能です）．<br />
&emsp;&emsp;&emsp;(<span style="font-style: italic;">F</span><sup>+</sup>[X∪Y]∪<span style="font-style: italic;">F</span><sup>+</sup>[Z∪W]∪<span style="font-style: italic;">F</span><sup>+</sup>[Ω<b><sub><span style="font-style: italic;">R</span></sub></b>－Y－W])<sup>+</sup>=<span style="font-style: italic;">F</span><sup>+</sup></p>
<p>&emsp;以上で準備は整いました．ここからは 2NF ではあるが 3NF ではないリレーションスキーマの 3NF への情報無損失分解が関数従属性保存か否かを検証していきます．3 つのパターンが示されますが，それらの結果は大変興味深いものです．</p>
<h4>4. 3NF 分解が関数従属性保存である例</h4>
<p style="margin-top: -10px;">
<strong>【例題4】</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C) に所与の FD 集合 <span style="font-style: italic;">F</span>={A→B, B→C} が指定されているとする．このとき，<b><span style="font-style: italic;">R</span></b> は 2NF ではあるが 3NF ではない．<b><span style="font-style: italic;">R</span></b> の 3NF への情報無損失分解が関数従属性保存であるかどうかを検証してみよ．なお，図 1 に本例題での所与の FD 集合の様子を示す．<br />
<strong>(解答)</strong><br />
&emsp;例題 2 で示したように，<span style="font-style: italic;">F</span><sup>+</sup>={A→A, A→B, A→C, B→B, B→C, C→C, AB→A, AB→B, AB→C, AC→A, AC→B, AC→C, BC→B, BC→C, ABC→A, ABC→B, ABC→C} である．<br />
&emsp;まず，確認すれば <b><span style="font-style: italic;">R</span></b> は 2NF ではあるが 3NF ではない．なぜならば，推移的関数従属性 A→B→C が存在するからである．そこで，A→B→C の解消を図るため，B→C を用いて，<b><span style="font-style: italic;">R</span></b> を <b><span style="font-style: italic;">R</span></b>[B, C]と <b><span style="font-style: italic;">R</span></b>[A, B] に情報無損失分解する．このとき，<span style="font-style: italic;">F</span><sup>+</sup>[B, C]= {B→B, B→C, C→C, BC→B, BC→C}，<span style="font-style: italic;">F</span><sup>+</sup>[A, B]= {A→A, A→B, B→B, AB→A, AB→B}となる．<br />
&emsp;さて，<span style="font-style: italic;">G</span>=<span style="font-style: italic;">F</span><sup>+</sup>[B, C]∪<span style="font-style: italic;">F</span><sup>+</sup>[A, B]と置いて，<span style="font-style: italic;">F</span><sup>+</sup>と <span style="font-style: italic;">G</span> の元を見比べてみると，<span style="font-style: italic;">F</span><sup>+</sup> の元 A→C，AB→C，　AC→A，AC→B，AC→C，ABC→A，ABC→B，ABC→C が <span style="font-style: italic;">G</span> に入っていない．そこで，これらの元で自明でないA→C，AB→C， AC→B について，それらが <span style="font-style: italic;">G</span><sup>+</sup> の元であるかどうかを検証する．<br />
&emsp;まず，A→C は，(A→B∈<span style="font-style: italic;">F</span><sup>+</sup>[A, B])∧(B→C∈<span style="font-style: italic;">F</span><sup>+</sup>[B, C])なので，アームストロングの公理系の推移律から A→C∈<span style="font-style: italic;">G</span><sup>+</sup> であることが分かる（つまり，<span style="font-style: italic;">G</span> ⊨ A→C である）．AB→C は，(AB→B∈<span style="font-style: italic;">F</span><sup>+</sup>[A, B])　∧(B→C∈<span style="font-style: italic;">F</span><sup>+</sup>[B, C])なので，アームストロングの公理系の推移律から AB→C∈<span style="font-style: italic;">G</span><sup>+</sup> であることが分かる（<span style="font-style: italic;">G</span> ⊨ AB→C）．AC→B については，A→B∈<span style="font-style: italic;">F</span><sup>+</sup>[A, B]なので，アームストロングの公理系の添加律から AC→BC で，BC→B∈<span style="font-style: italic;">F</span><sup>+</sup>[B, C] なので，アームストロングの公理系の推移律から AC→B∈<span style="font-style: italic;">G</span><sup>+</sup> であることが分かる（<span style="font-style: italic;">G</span> ⊨ AC→B）．したがって，<span style="font-style: italic;">G</span><sup>+</sup>=<span style="font-style: italic;">F</span><sup>+</sup> となり，<u>この情報無損失分解は関数従属性保存で<strong>ある</strong></u>．</p>
<p><center><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/05/drmasunaga-pic-01.png" alt="SQL code" style="margin-top: -22px; width: 300px" /></center><br />
<center>図1　リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C) に所与の FD 集合（例題4）</center></p>
<p>&emsp;前述の平成 26 年度 春季 データベーススペシャリスト試験 午前Ⅱ 問題 問 4 が（ア）を正解としたのは，例題 4 のような状況を想定しての設問だったのかもしれませんが，そのような但し書きは一切ありません，しかしながら，3NF 分解と関数従属性保存の関係性は常にこのように単純というわけではなく，以下に見るように，その出題意図に反した例を多々示すことができます．</p>
<h4>5. いかなる 3NF 分解も関数従属性保存でない例</h4>
<p style="margin-top: -10px;">
<strong>【例題5】</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C, D) に所与の FD 集合 <span style="font-style: italic;">F</span>={A→B, B→C, A→D, D→C} が指定されているとする．このとき，<b><span style="font-style: italic;">R</span></b> は 2NF ではあるが 3NF ではない．<b><span style="font-style: italic;">R</span></b> の 3NF への情報無損失分解が関数従属性保存であるかどうかを検証してみよ．なお，図 2 に本例題での所与の FD 集合の様子を示す．<br />
<strong>(解答)</strong><br />
&emsp;このとき，A<sup>+</sup>=ABCD, B<sup>+</sup>=BC, C<sup>+</sup>=C, D<sup>+</sup>=CD, AB<sup>+</sup>=AC<sup>+</sup>=AD<sup>+</sup>=ABCD, BC<sup>+</sup>=BC, BD<sup>+</sup>=BCD, CD<sup>+</sup>=CD, ABC<sup>+</sup>=ABD<sup>+</sup>=ACD<sup>+</sup>=ABCD, BCD<sup>+</sup>=BCD, ABCD<sup>+</sup>=ABCD なので，<span style="font-style: italic;">F</span><sup>+</sup>={A→A, A→B, A→C, A→D, B→B, B→C, C→C, D→C, D→D, AB→A, AB→B, AB→C, AB→D, AC→A, AC→B, AC→C, AC→D, AD→A, AD→B, AD→C, AD→D, BC→B, BC→C, BD→B, BD→C, BD→D, CD→C, CD→D, ABC→A, ABC→B, ABC→C, ABC→D, ABD→A, ABD→B, ABD→C, ABD→D, ACD→A, ACD→B, ACD→C, ACD→D, BCD→B, BCD→C, BCD→D, ABCD→A, ABCD→B, ABCD→C, ABCD→D}となる．<b><span style="font-style: italic;">R</span></b> の候補キーはAのみなので 2NF である．一方，<b><span style="font-style: italic;">R</span></b> にはA→B→C，A→D→Cという 2 つの推移的関数従属性が存在し 3NF ではないので <b><span style="font-style: italic;">R</span></b> を情報無損失分解する．</p>
<p><strong>(場合1) A→B→C の解消を図る．</strong><br />
&emsp;<b><span style="font-style: italic;">R</span></b> を A→B→C を構成する B→C を使って <b><span style="font-style: italic;">R</span></b>[B, C] と <b><span style="font-style: italic;">R</span></b>[A, B, D]に情報無損失分解すると，次が成立する．このときは <b><span style="font-style: italic;">R</span></b>[A, B, D] も 3NF となっている．<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[B, C]= {B→B, B→C, C→C, BC→B, BC→C}<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[A, B, D]= {A→A, A→B, A→D, B→B, D→D, AB→A, AB→B, AB→D, AD→A, AD→B, AD→D, BD→B, BD→D, ABD→A, ABD→B, ABD→D}<br />
&emsp;そこで，<span style="font-style: italic;">G</span>=<span style="font-style: italic;">F</span><sup>+</sup>[B, C]∪<span style="font-style: italic;">F</span><sup>+</sup>[A, B, D] と置き，<span style="font-style: italic;">G</span><sup>+</sup>=<span style="font-style: italic;">F</span><sup>+</sup> かどうかを検証する．<span style="font-style: italic;">F</span><sup>+</sup> と <span style="font-style: italic;">G</span> の元を見比べてみると， <span style="font-style: italic;">F</span><sup>+</sup> の元 A→C, D→C, AB→C, AC→A, AC→B, AC→C, AC→D, AD→C, BD→C, CD→C, CD→D, ABC→A, ABC→B, ABC→C, ABC→D, ABD→C, ACD→A, ACD→B, ACD→C, ACD→D, BCD→B, BCD→C, BCD→D, ABCD→A, ABCD→B, ABCD→C, ABCD→D が <span style="font-style: italic;">G</span> に入っていない．これらの中の自明でない FD である A→C, D→C, AB→C, AC→B, AC→D, AD→C, BD→C, ABC→D, ACD→B が <span style="font-style: italic;">G</span><sup>+</sup> の元か否かを検証すると，D→C が <span style="font-style: italic;">G</span> の下では導出されないことが分かる（￢(<span style="font-style: italic;">G</span> ⊨ D→C)，ここに￢は否定を表す）．したがって，<u>この情報無損失分解は関数従属性保存では<strong>ない</strong></u>．</p>
<p><strong>(場合2) A→D→C の解消を図る．</strong><br />
&emsp;<b><span style="font-style: italic;">R</span></b> を A→D→C を構成する D→C を使って <b><span style="font-style: italic;">R</span></b>[D, C] と <b><span style="font-style: italic;">R</span></b>[A, B, D] に情報無損失分解したときには，(場合1)と同様な展開で B→C が保存されず，<u>この情報無損失分解も関数従属性保存ではない<strong>ない</strong></u>．</p>
<p>&emsp;つまり，リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C, D) に所与の FD 集合 <span style="font-style: italic;">F</span>={A→B, B→C, A→D, D→C} が指定されているとき，<b><span style="font-style: italic;">R</span></b> を 3NF に正規化しようとする<u>何れの情報無損失分解も関数従属性保存ではない</u>ことが示されました．これが，前述の午前 Ⅱ 問題 問 4 とその正解を(ア)とする解答への端的な反証となります．</p>
<p><center><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/05/drmasunaga-pic-02.png" alt="SQL code" style="margin-top: -22px; width: 300px" /></center><br />
<center>図2　リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C, D) に所与の FD 集合（例題5）</center></p>
<h4>6. 3NF 分解が関数従属性保存となるか否かが，場合による 3 例</h4>
<p style="margin-top: -10px;">
<strong>【例題6】</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C, D)に所与の FD 集合 <span style="font-style: italic;">F</span>={A→B, B→C, C→D} が指定されているとする．このとき，<b><span style="font-style: italic;">R</span></b> は 2NF ではあるが 3NF ではない．<b><span style="font-style: italic;">R</span></b> の 3NF への情報無損失分解が関数従属性保存であるかどうかを検証してみよ．なお，図 3 に本例題での所与の FD 集合の様子を示す．<br />
<strong>(解答)</strong><br />
&emsp;このとき，<span style="font-style: italic;">F</span><sup>+</sup>={A→A, A→B, A→C, A→D, B→B, B→C, B→D, C→C, C→D, D→D, AB→A, AB→B, AB→C, AB→D, AC→A, AC→B, AC→C, AC→D, AD→A, AD→B, AD→C, AD→D, BC→B, BC→C, BC→D, BD→B, BD→C, BD→D, CD→C, CD→D, ABC→A, ABC→B, ABC→C, ABC→D, ABD→A, ABD→B, ABD→C, ABD→D, ACD→A, ACD→B, ACD→C, ACD→D, BCD→B, BCD→C, BCD→D, ABCD→A, ABCD→B, ABCD→C, ABCD→D}<br />
&emsp;<b><span style="font-style: italic;">R</span></b> の候補キーは A のみなので 2NF である．一方，<b><span style="font-style: italic;">R</span></b> には A→B→C，A→B→D，B→C→D，A→C→D という 4 つの推移的関数従属性が存在し 3NF ではないので <b><span style="font-style: italic;">R</span></b> を情報無損失分解する．</p>
<p><strong>(場合1) A→B→C の解消を図る．</strong><br />
&emsp;<b><span style="font-style: italic;">R</span></b> を A→B→C を構成する B→C を使って <b><span style="font-style: italic;">R</span></b>[B, C] と <b><span style="font-style: italic;">R</span></b>[A, B, D] に情報無損失分解すると，A→B→D により，<b><span style="font-style: italic;">R</span></b>[A, B, D] も 3NF ではないので，それを B→D を使って <b><span style="font-style: italic;">R</span></b>[B, D] と <b><span style="font-style: italic;">R</span></b>[A, B]に情報無損失分解すると次が成立する．<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[B, C]= {B→B, B→C, C→C, BC→B, BC→C}<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[B, D]= {B→B, B→D, D→D, BD→B, BD→D}<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[A, B]= {A→A, A→B, B→B, AB→A, AB→B}<br />
&emsp;そこで，<span style="font-style: italic;">G</span>=<span style="font-style: italic;">F</span><sup>+</sup>[B, C]∪<span style="font-style: italic;">F</span><sup>+</sup>[B, D]∪<span style="font-style: italic;">F</span><sup>+</sup>[A, B] と置き，<span style="font-style: italic;">G</span><sup>+</sup>=<span style="font-style: italic;">F</span><sup>+</sup> かどうかを検証する．そのために，<span style="font-style: italic;">F</span><sup>+</sup> の元であって <span style="font-style: italic;">G</span> の元でない FD について，それが <span style="font-style: italic;">G</span><sup>+</sup> の元であるか否かを検証する．そのような元は，<br />
A→C, A→D, C→D, AB→C, AB→D, AC→A, AC→B, AC→C, AC→D, AD→A,AD→B, AD→C, AD→D, BC→D, BD→C, CD→C, CD→D, ABC→A, ABC→B, ABC→C, ABC→D, ABD→A, ABD→B, ABD→C, ABD→D, ACD→A, ACD→B, ACD→C, ACD→D, BCD→B, BCD→C, BCD→D, ABCD→A, ABCD→B, ABCD→C, ABCD→Dである．これらのうち，自明でない FD である A→C, A→D, AB→C, AB→C, AB→D, AC→B, AC→D, AD→B, AD→C, BC→D, BD→C, ABC→D, ABD→C, ACD→B, BCD→A について，それらが <span style="font-style: italic;">G</span><sup>+</sup> の元か否かを検証すると，C→D が <span style="font-style: italic;">F</span><sup>+</sup> の元ではないことが分かる（￢(<span style="font-style: italic;">G</span> ⊨ C→D)）．したがって，<u>この情報無損失分解は関数従属性保存では<strong>ない</strong></u>．</p>
<p><strong>(場合2) A→B→D の解消を図る．</strong><br />
&emsp;<b><span style="font-style: italic;">R</span></b> を A→B→D を構成する B→D を使って <b><span style="font-style: italic;">R</span></b>[B, D] と <b><span style="font-style: italic;">R</span></b>[A, B, C] に情報無損失分解すると，A→B→C により，<b><span style="font-style: italic;">R</span></b>[A, B, C] も 3NF ではないので，それを B→C を使って <b><span style="font-style: italic;">R</span></b>[B, C] と <b><span style="font-style: italic;">R</span></b>[A, B] に情報無損失分解すると次が成立する．その結果，<b><span style="font-style: italic;">R</span></b> は <b><span style="font-style: italic;">R</span></b>[B, D] と <b><span style="font-style: italic;">R</span></b>[B, C] と <b><span style="font-style: italic;">R</span></b>[A, B] に情報無損失分解されるが，検証しないといけないことは (場合1)と同様となる．したがって，<u>この情報無損失分解は関数従属性保存では<strong>ない</strong></u>．</p>
<p><strong>(場合3) B→C→D の解消を図る．</strong><br />
&emsp;<b><span style="font-style: italic;">R</span></b> を B→C→D を構成する C→D を使って <b><span style="font-style: italic;">R</span></b>[C, D] と <b><span style="font-style: italic;">R</span></b>[A, B, C] に情報無損失分解すると，A→B→C により，<b><span style="font-style: italic;">R</span></b>[A, B, C] も 3NF ではないので，それを B→C を使って <b><span style="font-style: italic;">R</span></b>[B, C] と <b><span style="font-style: italic;">R</span></b>[A, B]に情報無損失分解すると次が成立する．<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[C, D]= {C→C, C→D, D→D, CD→C, CD→D}<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[B, C]= {B→B, B→C, C→C, BC→B, BC→C}<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[A, B]= {A→A, A→B, B→B, AB→A, AB→B}<br />
&emsp;そこで，<span style="font-style: italic;">G</span>=<span style="font-style: italic;">F</span><sup>+</sup>[C, D]∪<span style="font-style: italic;">F</span><sup>+</sup>[B, C]∪<span style="font-style: italic;">F</span><sup>+</sup>[A, B] と置き，<span style="font-style: italic;">G</span><sup>+</sup>=<span style="font-style: italic;">F</span><sup>+</sup> かどうかを検証する．そのために，<span style="font-style: italic;">F</span><sup>+</sup> の元であって <span style="font-style: italic;">G</span> の元でない FD について，それが <span style="font-style: italic;">G</span><sup>+</sup> の元であるか否かを検証する．そのような元は，<br />
A→C, A→D, B→D, AB→C, AB→D, AC→A, AC→B, AC→C, AC→D, AD→A, AD→B, AD→C, AD→D, BC→D, BD→B, BD→C, BD→D, ABC→A, ABC→B, ABC→C, ABC→D, ABD→A, ABD→B, ABD→C, ABD→D, ACD→A, ACD→B, ACD→C, ACD→D, BCD→B, BCD→C, BCD→D, ABCD→A, ABCD→B, ABCD→C, ABCD→D である．これらのうち，自明でない FD である A→C, A→D, B→D, AB→C, AB→D, AC→B, AC→D, AD→B, AD→C, BC→D, BD→C, ABC→D, ABD→C, ACD→B について，それらが <span style="font-style: italic;">G</span><sup>+</sup> の元か否かを検証すると，すべてが <span style="font-style: italic;">G</span><sup>+</sup> の元であることが分かる．したがって，<u>この情報無損失分解は関数従属性保存で<strong>ある</strong></u>．</p>
<p><strong>(場合4) A→C→D の解消を図る．</strong><br />
&emsp;<b><span style="font-style: italic;">R</span></b> を A→C→D を構成する C→D を使って <b><span style="font-style: italic;">R</span></b>[C, D] と <b><span style="font-style: italic;">R</span></b>[A, B, C]に情報無損失分解する．このとき，行わなくてはならない検証は(場合3)と同じとなり，したがって，<u>この情報無損失分解は関数従属性保存で<strong>ある</strong></u>．</p>
<p>&emsp;以上，例題 6 では，関数従属性保存か否かは情報無損失分解の仕方による，ということが示されました．<br />
<center><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/05/drmasunaga-pic-03.png" alt="SQL code" style="margin-top: -22px; width: 300px" /></center><br />
<center>図 3　リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C, D)に所与のFD集合（例題6）</center></p>
<p><strong>【例題7】</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C, D) に所与の FD 集合 <span style="font-style: italic;">F</span>={A→B, B→C, A→D, D→B} が指定されているとする．このとき，<b><span style="font-style: italic;">R</span></b> は 2NF ではあるが 3NF ではない．<b><span style="font-style: italic;">R</span></b> の 3NF への情報無損失分解が関数従属性保存であるかどうかを検証してみよ．なお，図 4 に本例題での所与の FD 集合の様子を示す．<br />
<strong>(解答)</strong><br />
&emsp;このとき，A<sup>+</sup>=ABCD, B<sup>+</sup>=BC, C<sup>+</sup>=C, D<sup>+</sup>=BCD, AB<sup>+</sup>=AC<sup>+</sup>=AD<sup>+</sup>=ABCD, BC<sup>+</sup>=BC, BD<sup>+</sup>=BCD, CD<sup>+</sup>=BCD, ABC<sup>+</sup>=ABD<sup>+</sup>=ACD<sup>+</sup>=ABCD, BCD<sup>+</sup>=BCD, ABCD<sup>+</sup>=ABCD なので，<span style="font-style: italic;">F</span><sup>+</sup> は次の通りとなる．<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>={A→A, A→B, A→C, A→D, B→B, B→C, C→C, D→B, D→C, D→D, AB→A, AB→B, AB→C, AB→D, AC→A, AC→B, AC→C, AC→D, AD→A, AD→B, AD→C, AD→D, BC→B, BC→C, BD→B, BD→C, BD→D, CD→B, CD→C, CD→D, ABC→A, ABC→B, ABC→C, ABC→D, ABD→A, ABD→B, ABD→C, ABD→D, ACD→A, ACD→B, ACD→C, ACD→D, BCD→B, BCD→C, BCD→D, ABCD→A, ABCD→B, ABCD→C, ABCD→D}<br />
&emsp;<b><span style="font-style: italic;">R</span></b> の候補キーは A のみで，2NF である．一方，<b><span style="font-style: italic;">R</span></b> には A→B→C, A→D→B, D→B→C, A→D→C という 4 つの推移的関数従属性が存在し 3NF ではない．そこで，<b><span style="font-style: italic;">R</span></b> を 3NF に情報無損失分解する．</p>
<p><strong>(場合1) A→B→C の解消を図る．</strong><br />
&emsp;<b><span style="font-style: italic;">R</span></b> を A→B→C を構成する B→C を使って <b><span style="font-style: italic;">R</span></b>[B, C] と <b><span style="font-style: italic;">R</span></b>[A, B, D] に情報無損失分解すると，A→D, D→B∈<span style="font-style: italic;">F</span><sup>+</sup> なので，<b><span style="font-style: italic;">R</span></b>[A, B, D] は 3NF ではなく，それを D→B で情報無損失分解して 3NF にするとき，次が成立する．<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[B, C]= {B→B, B→C, C→C, BC→B, BC→C}<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[A, D]= {A→A, A→D, D→D, AD→A, AD→D}<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[B, D]= {B→B, D→B, D→D, BD→B, BD→D}<br />
&emsp;そこで，<span style="font-style: italic;">G</span>=<span style="font-style: italic;">F</span><sup>+</sup>[B, C]∪<span style="font-style: italic;">F</span><sup>+</sup>[A, D]∪<span style="font-style: italic;">F</span><sup>+</sup>[B, D] と置き，<span style="font-style: italic;">G</span><sup>+</sup>=<span style="font-style: italic;">F</span><sup>+</sup> かどうかを検証する．そのために，<span style="font-style: italic;">F</span><sup>+</sup> の元であって <span style="font-style: italic;">G</span> の元でない FD について，それが <span style="font-style: italic;">G</span><sup>+</sup> の元であるか否かを検証する．そのような元は，<br />
A→B, A→C, D→C, AB→A, AB→B, AB→C, AB→D, AC→A, AC→B, AC→C, AC→D, AD→B, AD→C, BD→C, CD→B, CD→C, CD→D, ABC→A, ABC→B, ABC→C, ABC→D, ABD→A, ABD→B, ABD→C, ABD→D, ACD→A, ACD→B, ACD→C, ACD→D, BCD→B, BCD→C, BCD→D, ABCD→A, ABCD→B, ABCD→C, ABCD→D である．これらのうち，自明でない FD である A→B, A→C, D→C, AB→C, AB→D, AC→B, AC→D, AD→B, AD→C, BD→C, CD→B, ABC→D, ABD→C, ACD→B について，それらが <span style="font-style: italic;">G</span><sup>+</sup> の元か否かを検証すると，すべてが <span style="font-style: italic;">G</span><sup>+</sup> の元であることが分かる．したがって，<u>この情報無損失分解は関数従属性保存で<strong>ある</strong></u>．</p>
<p><strong>(場合2) A→D→B の解消を図る．</strong><br />
&emsp;<b><span style="font-style: italic;">R</span></b> を A→D→B を構成する D→B を使って <b><span style="font-style: italic;">R</span></b>[D, B] と <b><span style="font-style: italic;">R</span></b>[A, C, D] に情報無損失分解すると，A→D, D→C∈<span style="font-style: italic;">F</span><sup>+</sup> なので，<b><span style="font-style: italic;">R</span></b>[A, C, D] は 3NF ではなく，それを D→C で情報無損失分解して 3NF にするとき，次が成立する．<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[D, B]= {B→B, D→B, D→D, BD→B, BD→D}<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[C, D]= {C→C, D→C, D→D, CD→C, CD→D}<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[A, D]= {A→A, A→D, D→D, AD→A, AD→D}<br />
&emsp;そこで，<span style="font-style: italic;">G</span>=<span style="font-style: italic;">F</span><sup>+</sup>[D, B]∪<span style="font-style: italic;">F</span><sup>+</sup>[C, D]∪<span style="font-style: italic;">F</span><sup>+</sup>[A, D] と置き，<span style="font-style: italic;">G</span><sup>+</sup>=<span style="font-style: italic;">F</span><sup>+</sup> かどうかを検証する．そのために，<span style="font-style: italic;">F</span><sup>+</sup> の元であって <span style="font-style: italic;">G</span> の元でない FD について，それが <span style="font-style: italic;">G</span><sup>+</sup> の元であるか否かを検証する．そのような元は，<br />
A→B, A→C, B→C, AB→A, AB→B, AB→C, AB→D, AC→A, AC→B, AC→C, AC→D, AD→B, AD→C, BC→B, BC→C, BD→C, CD→B, ABC→A, ABC→B, ABC→C, ABC→D, ABD→A, ABD→B, ABD→C, ABD→D, ACD→A, ACD→B, ACD→C, ACD→D, BCD→B, BCD→C, BCD→D, ABCD→A, ABCD→B, ABCD→C, ABCD→D となる．これらのうち，自明でない FD である A→B, A→C, B→C, AB→C, AB→D, AC→B, AC→D, AD→B, AD→C, BD→C, CD→B, ABD→C, ACD→B について，<span style="font-style: italic;">G</span><sup>+</sup> の元であるか否かを検証すると，B→C が <span style="font-style: italic;">G</span><sup>+</sup> の元ではないことが分かる（￢(<span style="font-style: italic;">G</span> ⊨ B→C)）．したがって，<u>この情報無損失分解は関数従属性保存では<strong>ない</strong></u>．</p>
<p><strong>(場合3) D→B→C の解消を図る．</strong><br />
&emsp;<b><span style="font-style: italic;">R</span></b> を D→B→C を構成する B→C を使って情報無損失分解することとなるが，このとき，行わなくてはならない検証は(場合1)と同じとなり，したがって，<u>この情報無損失分解は関数従属性保存で<strong>ある</strong></u>．</p>
<p><strong>(場合4) A→D→C の解消を図る．</strong><br />
&emsp;<b><span style="font-style: italic;">R</span></b> を A→D→C を構成する D→C を使って <b><span style="font-style: italic;">R</span></b>[D, C] と <b><span style="font-style: italic;">R</span></b>[A, B, D] に情報無損失分解すると，A→D, D→B∈<span style="font-style: italic;">F</span><sup>+</sup> かつ ¬(D→A∈<span style="font-style: italic;">F</span><sup>+</sup>) なので，<b><span style="font-style: italic;">R</span></b>[A, B, D]は 3NF ではなく，それを D→B で情報無損失分解して 3NF にするとき，次が成立する．<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[D, C]= {C→C, D→C, D→D, CD→C, CD→D}<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[D, B]= {B→B, D→B, D→D, BD→B, BD→D}<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[A, D]= {A→A, A→D, D→D, AD→A, AD→D}<br />
&emsp;そこで，<span style="font-style: italic;">G</span>=<span style="font-style: italic;">F</span><sup>+</sup>[D, C]∪<span style="font-style: italic;">F</span><sup>+</sup>[D, B]∪<span style="font-style: italic;">F</span><sup>+</sup>[A, D] と置き，<span style="font-style: italic;">G</span><sup>+</sup>=<span style="font-style: italic;">F</span><sup>+</sup> かどうかを検証する．そのために，<span style="font-style: italic;">F</span><sup>+</sup> の元であって <span style="font-style: italic;">G</span> の元でない FD について，それが <span style="font-style: italic;">G</span><sup>+</sup> の元であるか否かを検証する．そのような元は，<br />
A→B, A→C, B→C, AB→A, AB→B, AB→C, AB→D, AC→A, AC→B, AC→C, AC→D, AD→B, AD→C, BC→B, BC→C, BD→C, CD→B, ABC→A, ABC→B, ABC→C, ABC→D, ABD→A, ABD→B, ABD→C, ABD→D, ACD→A, ACD→B, ACD→C, ACD→D, BCD→B, BCD→C, BCD→D, ABCD→A, ABCD→B, ABCD→C, ABCD→D となる．<br />
&emsp;これらのうち，自明でない FD である A→B, A→C, B→C, AB→A, AB→B, AB→C, AB→D, AC→A, AC→B, AC→C, AC→D, AD→B, AD→C, BC→B, BC→C, BD→C, CD→B, ABC→A, ABC→B, ABC→C, ABC→D, ABD→A, ABD→B, ABD→C, ABD→D, ACD→A, ACD→B, ACD→C, ACD→D, BCD→B, BCD→C, BCD→D, ABCD→A, ABCD→B, ABCD→C, ABCD→D について，<span style="font-style: italic;">G</span><sup>+</sup> の元であるか否かを検証すると，B→C が <span style="font-style: italic;">G</span><sup>+</sup> の元ではないことが分かる（￢(<span style="font-style: italic;">G</span> ⊨ B→C)）．したがって，<u>この情報無損失分解は関数従属性保存では<strong>ない</strong></u>．</p>
<p>&emsp;以上，例題 7 では，関数従属性保存か否かは情報無損失分解の仕方による，ということが示されました．<br />
<center><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/05/drmasunaga-pic-04.png" alt="SQL code" style="margin-top: -22px; width: 300px" /></center><br />
<center>図 4　リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C, D) に所与の FD 集合（例題7）</center></p>
<p><strong>【例題8】</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C, D) に所与の FD 集合 <span style="font-style: italic;">F</span>={A→B, B→C, B→D, D→C} が指定されているとする．このとき，<b><span style="font-style: italic;">R</span></b> は 2NF ではあるが 3NF ではない．<b><span style="font-style: italic;">R</span></b> の 3NF への情報無損失分解が関数従属性保存であるかどうかを検証してみよ．なお，図 5 に本例題での所与の FD 集合の様子を示す．<br />
<strong>(解答)</strong><br />
&emsp;このとき，A<sup>+</sup>=ABCD, B<sup>+</sup>=BCD, C<sup>+</sup>=C, D<sup>+</sup>=CD, AB<sup>+</sup>=AC<sup>+</sup>=AD<sup>+</sup>=ABCD, BC<sup>+</sup>=BCD, BD<sup>+</sup>=BCD, CD<sup>+</sup>=CD, ABC<sup>+</sup>=ABD<sup>+</sup>=ACD<sup>+</sup>=ABCD, BCD<sup>+</sup>=BCD, ABCD<sup>+</sup>=ABCD なので，<span style="font-style: italic;">F</span><sup>+</sup> は次の通りとなる．<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>={A→A, A→B, A→C, A→D, B→B, B→C, B→D, C→C, D→C, D→D, AB→A, AB→B, AB→C, AB→D, AC→A, AC→B, AC→C, AC→D, AD→A, AD→B, AD→C, AD→D, BC→B,BC→C, BC→D, BD→B, BD→C, BD→D, CD→C, CD→D, ABC→A, ABC→B, ABC→C, ABC→D, ABD→A, ABD→B, ABD→C, ABD→D, ACD→A, ACD→B, ACD→C, ACD→D, BCD→B, BCD→C, BCD→D, ABCD→A, ABCD→B, ABCD→C, ABCD→D}<br />
&emsp;<b><span style="font-style: italic;">R</span></b> の候補キーは A のみで，2NF である．一方，<b><span style="font-style: italic;">R</span></b> には A→B→C，A→B→D, B→D→C，A→D→C という 4 つの推移的関数従属性が存在し 3NF ではない．そこで，<b><span style="font-style: italic;">R</span></b> を情報無損失分解する．</p>
<p><strong>(場合1) A→B→C の解消を図る．</strong><br />
&emsp;この場合，B→C を使って <b><span style="font-style: italic;">R</span></b> を <b><span style="font-style: italic;">R</span></b>[B, C] と <b><span style="font-style: italic;">R</span></b>[A, B, D] に情報無損失分解する．<b><span style="font-style: italic;">R</span></b>[A, B, D] では A→B→D が成立していて 3NF ではないので，B→D でそれを <b><span style="font-style: italic;">R</span></b>[B, D] と <b><span style="font-style: italic;">R</span></b>[A, B] に情報無損失分解する．このとき，次が成立する．<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[B, C]= {B→B, B→C, C→C, BC→B, BC→C }<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[B, D]= {B→B, B→D, D→D, BD→B, BD→D}<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[A, B]= {A→A, A→B, B→B, AB→A, AB→B}<br />
&emsp;そこで，<span style="font-style: italic;">G</span>=<span style="font-style: italic;">F</span><sup>+</sup>[B, C]∪<span style="font-style: italic;">F</span><sup>+</sup>[B, D]∪<span style="font-style: italic;">F</span><sup>+</sup>[A, B] と置いて，<span style="font-style: italic;">G</span><sup>+</sup>=<span style="font-style: italic;">F</span><sup>+</sup> かどうかを検証する．そのために，<span style="font-style: italic;">F</span><sup>+</sup> の元であって <span style="font-style: italic;">G</span> の元でない FD について，それが <span style="font-style: italic;">G</span><sup>+</sup> の元であるか否かを検証する．<br />
&emsp;そのような元は，A→C, A→D, D→C, AB→C, AB→D, AC→A, AC→B, AC→C, AC→D, AD→A, AD→B, AD→C, AD→D, BC→D, BD→C, CD→C, CD→D, ABC→A, ABC→B, ABC→C, ABC→D, ABD→A, ABD→B, ABD→C, ABD→D, ACD→A, ACD→B, ACD→C, ACD→D, BCD→B, BCD→C, BCD→D, ABCD→A, ABCD→B, ABCD→C, ABCD→D となる．これらのうち，自明でない FD である A→C, A→D, D→C, AB→C, AB→D, AC→B, AC→D, AD→B, AD→C, BC→D, BD→C, ABC→D, ABD→C, ACD→B について，<span style="font-style: italic;">G</span><sup>+</sup> の元であるか否かを検証すると，唯一，D→C が <span style="font-style: italic;">G</span> の下では導出されない,つまり，D→C は <span style="font-style: italic;">G</span><sup>+</sup> の元ではないことが分かる（￢(<span style="font-style: italic;">G</span> ⊨ D→C)）．したがって，<u>この情報無損失分解は関数従属性保存では<strong>ない</strong></u>．</p>
<p><strong>(場合2) A→B→D の解消を図る．</strong><br />
&emsp;この場合，B→D を使って <b><span style="font-style: italic;">R</span></b> を <b><span style="font-style: italic;">R</span></b>[B, D] と <b><span style="font-style: italic;">R</span></b>[A, B, C] に情報無損失分解する．<b><span style="font-style: italic;">R</span></b>[A, B, C] は 3NF ではないので，B→C でそれを <b><span style="font-style: italic;">R</span></b>[B, C] と <b><span style="font-style: italic;">R</span></b>[A, B] に情報無損失分解する．このとき，行わなくてはならない検証は(場合1)と同じとなり，したがって，<u>この情報無損失分解は関数従属性保存では<strong>ない</strong></u>．</p>
<p><strong>(場合3) B→D→C の解消を図る．</strong><br />
&emsp;この場合，D→C を使って <b><span style="font-style: italic;">R</span></b> を <b><span style="font-style: italic;">R</span></b>[D, C] と <b><span style="font-style: italic;">R</span></b>[A, B, D] に情報無損失分解する．<b><span style="font-style: italic;">R</span></b>[A, B, D] は A→B→D の存在により 3NF ではないので，B→D でそれを <b><span style="font-style: italic;">R</span></b>[B, D] と <b><span style="font-style: italic;">R</span></b>[A, B] に情報無損失分解する．このとき，次が成立する．<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[C, D]= {C→C, D→C, D→D, CD→C, CD→D }<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[B, D]= {B→B, B→D, D→D, BD→B, BD→D}<br />
&emsp;<span style="font-style: italic;">F</span><sup>+</sup>[A, B]= {A→A, A→B, B→B, AB→A, AB→B}</p>
<p>&emsp;そこで，<span style="font-style: italic;">G</span>=<span style="font-style: italic;">F</span><sup>+</sup>[C, D]∪<span style="font-style: italic;">F</span><sup>+</sup>[B, D]∪<span style="font-style: italic;">F</span><sup>+</sup>[A, B] と置いて，<span style="font-style: italic;">G</span><sup>+</sup>=<span style="font-style: italic;">F</span><sup>+</sup> かどうかを検証する．そのために，<span style="font-style: italic;">F</span><sup>+</sup> の元であって <span style="font-style: italic;">G</span> の元でない FD について，それが <span style="font-style: italic;">G</span><sup>+</sup> の元であるか否かを検証する．そのような元は，<br />
A→C, A→D, B→C, AB→C, AB→D, AC→A, AC→B, AC→C, AC→D, AD→A, AD→B, AD→C, AD→D, BC→B, BC→C, BC→D, BD→C, ABC→A, ABC→B, ABC→C, ABC→D, ABD→A, ABD→B, ABD→C, ABD→D, ACD→A, ACD→B, ACD→C, ACD→D, BCD→B, BCD→C, BCD→D, ABCD→A, ABCD→B, ABCD→C, ABCD→D となる．これらのうち，自明でない FD である A→C, A→D, B→C, AB→C, AB→D, AC→B, AC→D, AD→B, AD→C, BC→D, BD→C, ABC→D, ABD→C, ACD→B について，<span style="font-style: italic;">G</span><sup>+</sup> の元であるか否かを検証すると，すべてが <span style="font-style: italic;">G</span> の下で導出されることが分かる．したがって，<u>この情報無損失分解は関数従属性保存で<strong>ある</strong></u>．</p>
<p><strong>(場合4) A→D→C の解消を図る．</strong><br />
&emsp;この場合，D→C を使って <b><span style="font-style: italic;">R</span></b> を <b><span style="font-style: italic;">R</span></b>[D, C] と <b><span style="font-style: italic;">R</span></b>[A, B, D] に情報無損失分解する．このとき，行わなくてはならない検証は(場合3)と同じとなり，したがって，<u>この情報無損失分解は関数従属性保存で<strong>ある</strong></u>．<br />
&emsp;以上，例題 8 でも，関数従属性保存か否かは情報無損失分解の仕方による，ということが示されました．</p>
<p><center><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2022/05/drmasunaga-pic-05.png" alt="SQL code" style="margin-top: -22px; width: 300px" /></center><br />
<center>図 5　リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A, B, C, D)に所与のFD集合（例題8）</center></p>
<p>&emsp;以上，例題 4～8 を通して確認できたように，「情報無損失分解ができ，かつ，関数従属性保存が成り立つ変換が必ず存在するものは，第 2 正規形から第3正規形への変換である」（午前 Ⅱ 問題 問 4 の出題意図）とは言い切れないことが分かりました．関数従属性保存が成り立つか否かは場合によるということです．</p>
<h4>7. おわりに</h4>
<p>&emsp;筆者は，平成 26 年度 春季 データベーススペシャリスト試験 午前 Ⅱ 問題 問 4 とその正解を「出題ミス」として簡単に片付けてしまう気にはなれず，この問題をもう少し重く受け止めています．その理由は，なぜこのような認識がなされてしまったのだろうかと考えるとき，どうもその背景には RDB 設計の現場に，RDB 設計のための「分解的手法」と「合成的手法」について，特に，その差異について十分な理解がなされていないのではないかと思うからです．<br />
&emsp;そもそも，分解的手法とはコッドのリレーショナルデータモデルとその正規化理論に基づく RDB の設計手法で，FD や多値従属性や結合従属性によるリレーションの情報無損失分解がすべてを取り仕切ります．<u>その時，FD が保存されるか否かは，情報無損失分解とは独立した概念であり</u>，本稿で示したように，FD が保存される場合もあれば，保存されない場合もあるわけです．<br />
&emsp;一方，バーンシュタイン（P.A. Bernstein）により提案された RDB 設計の「合成的手法」[5] は，データベース化の対象となった実世界で成り立つ FD をリストアップし，それを所与の FD 集合と指定することで，それから「関数従属性保存・3NF・情報無損失分解」と三拍子そろった RDB を設計することができます．<br />
&emsp;つまり，3NF のリレーションスキーマを設計するにあたり，<u>分解的手法では情報無損失分解と関数従属性保存はセットではありませんが，合成的手法では情報無損失分解と関数従属性保存はセットです</u>．ここで，セットという言葉は共に成り立つ，という意味で使っています．これはとても大きな違いなのですが，このことがひょっとして RDB 設計の現場で十分認識されないまま，いつしか分解的手法でも 3NF までならば「関数従属性保存・3NF・情報無損失分解」と三拍子そろった RDB を設計することができるやに誤認識されて今日に至っているのではないか，筆者はそれをとても危惧してこの記事を書いたということです．本稿をお読みいただいた方の中には RDB 設計の最前線に立たれている方も大勢いらっしゃるのではないかと思いますが，機会があれば現場の声を是非お聞かせ願いたく思います．</p>
<p>【文献】</p>
<p style="margin-top: -10px;" >[1]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
平成26年度春期データベーススペシャリスト試験午前Ⅱ問題<br />
https://www.jitec.ipa.go.jp/1_04hanni_sukiru/mondai_kaitou_2014h26_1/2014h26h_db_am2_qs.pdf
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[2]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
平成26年度春期データベーススペシャリスト試験解答例<br />
https://www.jitec.ipa.go.jp/1_04hanni_sukiru/mondai_kaitou_2014h26_1/2014h26h_db_am2_ans.pdf
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[3]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
E.F. Codd. A Relational Model of Data for Large Shared Data Banks. Communications of the ACM, Vol.13, No.6, pp.377-387, 1970.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[4]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
E.F. Codd. Further Normalization of the Data Base Relational Model. R. Rustin (Ed.), Data Base Systems (Courant Computer Science Symposia 6), pp.33-64, Prentice-Hall, Englewood Cliffs, NJ, 1972.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[5]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
P.A. Bernstein. Synthesizing Third Normal Form Relations from Functional Dependencies. ACM Transactions on Database Systems, Vol.1, No.4, pp.277-298, 1976.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[6]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
増永良文．リレーショナルデータベース入門[第3版]．サイエンス社，2017．
</td>
</tbody>
</table>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>増永教授のDB特論④「候補キーの見つけ方」</title>
		<link>https://www.sraoss.co.jp/tech-blog/db-special-lecture/masunaga-db-special-lecture-4/</link>
		
		<dc:creator><![CDATA[増永良文 (Yoshifumi Masunaga)]]></dc:creator>
		<pubDate>Wed, 06 Apr 2022 00:00:59 +0000</pubDate>
				<category><![CDATA[増永教授のDB特論]]></category>
		<category><![CDATA[RDB]]></category>
		<category><![CDATA[リレーショナルデータベース]]></category>
		<category><![CDATA[候補キー]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=9482</guid>

					<description><![CDATA[1. はじめに &#8195;SQL でテーブルを定義するときに PRIMARY KEY や UNIQUE を指定すると思いますが，皆さんはリレーション（スキーマ）のキー（key）を一体どのようにして見つけていますか？ &#038; ...]]></description>
										<content:encoded><![CDATA[<h4>1. はじめに</h4>
<p style="margin-top: -10px;">
&emsp;SQL でテーブルを定義するときに PRIMARY KEY や UNIQUE を指定すると思いますが，皆さんはリレーション（スキーマ）のキー（key）を一体どのようにして見つけていますか？<br />
&emsp;そもそも，「キーとはタップルの一意識別能力を有する属性の<ruby>極<rt style="background-color: #DDDDDD;">・</rt></ruby><ruby>小<rt style="background-color: #DDDDDD;">・</rt></ruby>組」であることは，リレーショナルデータモデルを学んだ人ならばデータベースのイロハといった事項でしょうが，具体的にリレーション（スキーマ）と所与の関数従属性の集合が指定されたときに，キーを求めなさいと言われると，結構難儀する場合もあるのではないか，と思います．<br />
&emsp;本稿では，次に示す 3 つの問題について改めて論じてみます．</p>
<ul style="margin-top: -08px;">
<li style="margin-top: -25px; margin-left: +50px;">候補キーを 1 つ見つける．</li>
<li style="margin-left: +50px;">候補キーをすべて見つける．</li>
<li style="margin-left: +50px;">候補キーの数の上限は？</li>
</ul>
<p><span id="more-9482"></span></p>
<h4>2. 基礎的事項</h4>
<p style="margin-top: -10px;">
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> とはリレーション名 R と属性のリスト A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub> からなり，<b><span style="font-style: italic;">R</span></b>(A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub>)と表されます．Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> (= { A<sub>1</sub>, A<sub>2</sub>, <sub>…</sub>, A<sub>n</sub> })で <b><span style="font-style: italic;">R</span></b> の全属性集合を表すことにします．<b><span style="font-style: italic;">R</span></b> をリレーションスキーマとするとき，<b><span style="font-style: italic;">R</span></b> に所与の（given）関数従属性の集合 <span style="font-style: italic;">F</span>＝{f<sub>1</sub>, f<sub>2</sub>, <sub>…</sub>, f<sub>p</sub>}，ここに (∀<sub>i</sub>= 1, 2, <sub>…</sub>, p)(f<sub>i</sub>=X<sub>i</sub>→Y<sub>i</sub> ∧ X<sub>i</sub>, Y<sub>i</sub>⊆Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>)，を指定できます．なお，一般に X, Y を集合とするとき，X⊆Y は X が Y の部分集合であることを，X⊂Y は X が Y の真部分集合（proper subset）であることを表します．</p>
<p><strong>【定義 1】</strong>（候補キー）<br />
&emsp;K⊆Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> がリレーションスキーマ <b><span style="font-style: italic;">R</span></b> の<strong>候補キー</strong>（candidate key）と言われるのは，次が成立するときをいう．ここに，∀R∈<b><span style="font-style: italic;">R</span></b> は「<b><span style="font-style: italic;">R</span></b> の任意のインスタンス R に対して」を表す．</p>
<p style="margin-top: -25px; margin-left: +50px;">(∀R∈<b><span style="font-style: italic;">R</span></b>)((∀t, t’∈R)(t[K]=t’[K] ⇒ t=t’) ∧</p>
<p style="margin-top: -25px; margin-left: +50px;">(∀H⊂K)(∃R∈<b><span style="font-style: italic;">R</span></b>) ((∃t, t’∈R)(t[H]=t’[H] ∧ t≠t’)))</p>
<p>&emsp;リレーションは有限個のドメインの直積の有限部分集合と定義されているので ，いかなるリレーションにも候補キーがないということはなく，最も極端なケースはリレーションスキーマ <b><span style="font-style: italic;">R</span></b> の全属性集合 Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> が候補キーとなることも皆さんにとっては常識でしょう．<br />
&emsp;組織体管理者（enterprise administrator, すなわち組織のデータベース設計に責任を有する個人またはグループ）は，候補キーが一つしかなければそれを，複数ある場合にはデータベース構築の目的に合っていると考えられるものを一つを選んで<strong>主キー</strong>（primary key）とします．主キーとされなかった候補キーと主キーとの違いは，主キーには<strong>キー制約</strong>（key constraint）が課せられることにあることもよくご存じのことでしょう．また，何らかの候補キーを含む属性集合を<strong>スーパーキー</strong>（super key）と言います．</p>
<p><strong>【定義 2】</strong>（キー制約）<br />
&emsp;K がリレーションスキーマ <b><span style="font-style: italic;">R</span></b> の主キーであるならば，次が成立しなければならない．ここに，NULLは空（すなわち，値がないこと）を表す．</p>
<p style="margin-top: -25px; margin-left: +50px;">(∀R∈<b><span style="font-style: italic;">R</span></b>) (∀t∈R)((∀A∈K)(t[A] IS NOT NULL)) </p>
<p>&emsp;簡単な例を示すと，リレーションスキーマ <b><span style="font-style: italic;">社員</span></b>(社員番号，社員名，所属，給与，マイナンバー)では，社員番号 や マイナンバー は候補キーでしょうが，もし 社員番号 を主キーと選べば リレーション 社員 のいかなるタップルの社員番号がNULLとなってはいけないというデータベースの一貫性制約が「キー制約」です．このとき，勿論，マイナンバー にも社員を一意識別する力はあるものの，主キーと指定されなかったので，NULLであってもよいということです．主キーとそう指定されなかった候補キーとの違いはこの一点です．<br />
&emsp;なお，主キーか否かを問わず，候補キーを構成している属性を<strong>キー属性</strong>と言い，キー属性でない属性を<strong>非キー属性</strong>と言います．候補キーと主キーを特段に区別する必要を感じないときには単に<strong>キー</strong>ということも多く，また特段に混乱をきたさないと考えられる場合には本来リレーションスキーマと書くべきところをリレーションと書いているところもあるのであらかじめ断っておきます．</p>
<p>&emsp;さて，定義1で候補キーの定義を与えましたが，その定義を<strong>関数従属性</strong>（functional dependency, FD）を使って表現し直すことができます．多少くどいかもしれませんが，その定義を記しておきます．</p>
<p><strong>【定義 3】</strong>（関数従属性，FD）<br />
&emsp;X，Y をリレーションスキーマ <b><span style="font-style: italic;">R</span></b> の属性集合 Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> の部分集合とするとき，X から Y への FD がある，このことを X→Y と書く，とは次が成立するときをいう．ここに，iff は if and only if（必要かつ十分）を，⇒ は論理的含意を表し，X→Y の X を決定子（determinant），Y を被決定子（resultant）という．</p>
<p style="margin-top: -25px; margin-left: +150px;">X→Y iff (∀R∈<b><span style="font-style: italic;">R</span></b>)(∀t, t’∈R)( t[X]=t’[X] ⇒ t[Y]=t’[Y])</p>
<p>&emsp;また，FD については，Armstrong の公理系が成立することも皆さん，よくご存じのことと思います．</p>
<p><strong>【公理 1】</strong>（Armstrong の公理系）<br />
&emsp;A1.  Y⊆X ならば，X→Y である（反射律）．<br />
&emsp;A2.  X→Y かつ Z⊆W ならば，X∪W→Y∪Z である（添加律）．<br />
&emsp;A3.  X→Y かつ Y→Z ならば，X→Z である（推移律）．</p>
<p>&emsp;さて，定義 1 で候補キーの定義を与えましたが，FD を使ってこの定義を表現し直してみると，次のようになります．</p>
<p><strong>【定義 4】</strong>（FD を用いた候補キーの定義）<br />
&emsp;K⊆Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> がリレーションスキーマ <b><span style="font-style: italic;">R</span></b> の候補キーと言われるのは，次が成立するときをいう．ここに，↛ は FD が成立しないことを表す．</p>
<p style="margin-top: -25px; margin-left: +50px;">(K→Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>) ∧ (∀H⊂K)(H↛Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>)</p>
<p>&emsp;さらに，この定義はリレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されたとき，属性集合 X の<strong>閉包</strong>（closure），これを X<sup>+</sup> と記す，を用いて以下のように書き直せます．</p>
<p>&emsp;まず，リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されたとき，<b><span style="font-style: italic;">R</span></b> の属性集合 X の閉包の求め方を示しておきます．このアルゴリズムの<strong>時間計算量</strong>（time complexity）は<b><span style="font-style: italic;">O</span></b>(n×p)，ここにn=|Ω<span style="font-style: italic;"><sub>R</sub></span>|，p=|<span style="font-style: italic;">F</span>|，と多項式オーダーであり<strong>扱いやすい問題</strong>（tractable problem）です．したがって X<sup>+</sup> は問題なく求められます．</p>
<p>&emsp;<strong>【X<sup>+</sup> を求めるアルゴリズム】</strong></p>
<p style="margin-top: -25px; margin-left: +50px;">ステップ 1　X<sup>(0)</sup>=X とおく．</p>
<p style="margin-top: -25px; margin-left: +50px;">ステップ 2　X<sup>(i)</sup>=X<sup>(i-1)</sup>∪{Z | Y→Z∈F ∧ Y⊆X<sup>(i-1)</sup> } (i≧1)</p>
<p style="margin-top: -25px; margin-left: +50px;">ステップ 3　もし X<sup>(i)</sup>=X<sup>(i-1)</sup> なら X<sup>＋</sup>=X<sup>(i-1)</sup> とおく．そうでなければステップ 2 に行く．</p>
<p>&emsp;ここで，関数従属性と閉包の関係性について記します．</p>
<p><strong>【命題 1】</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとする．X, Y⊆Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> とするとき，次が成立する．</p>
<p style="margin-top: -25px; margin-left: +50px;">X→Y iff Y⊆X<sup>+</sup></p>
<p>（証明）<br />
&emsp;X<sup>+</sup> を求めるアルゴリズムでは，一般に X<sup>(i)</sup>=X<sup>(i-1)</sup>∪{Z | Y→Z∈F ∧ Y⊆X<sup>(i-1)</sup>} であるので，X<sup>(0)</sup>={X}としたとき X→Y∈<span style="font-style: italic;">F</span> ならば Y はX<sup>(1)</sup>の元となり，結果的にY⊆X<sup>+</sup>である．逆に，Y⊆X<sup>+</sup>ならば，X<sup>+</sup>の元は X に関数従属した属性からなるので，X→X<sup>+</sup>である．Y⊆X<sup>+</sup>なので反射律から X<sup>+</sup>→Y が成立する．従って，推移律から X→Y である．</p>
<p>&emsp;そうすると，定義 4で与えた FD を用いた候補キーの定義は閉包の概念を用いて定義 5 のように書き直せます．これは，命題 1 より，K→Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> iff K<sup>+</sup>=Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> が成立することから明らかでしょう．</p>
<p><strong>【定義 5】</strong>（閉包の概念を用いた候補キーの定義）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとする．K⊆Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> が <b><span style="font-style: italic;">R</span></b> の候補キーと言われるのは，次が成立するときをいう． </p>
<p style="margin-top: -25px; margin-left: +50px;">(K<sup>+</sup>=Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>) ∧ (∀H⊂K)(H<sup>+</sup>≠Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>)</p>
<p>&emsp;ここまで準備完了です．では，続けて，リレーションスキーマの候補キーを求める問題を考えてみましょう．2 つの立場から考察していきます．</p>
<table style="margin-top: -18px; border:none;">
<tbody>
<tr>
<td style="width: 60px; border:none; vertical-align: top; ">　(1)</td>
<td style="border:none;">
リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとき，<b><span style="font-style: italic;">R</span></b> の候補キーを（何でもよいので）<b>１つ</b>見つける．
</td>
</tr>
<tr>
<td style="border:none; vertical-align: top; ">　(2)</td>
<td style="border:none;">
リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span> が指定されているとき，<b><span style="font-style: italic;">R</span></b> の候補キーを<strong>すべて</strong>見つける
</td>
</tr>
</tbody>
</table>
<h4>3. 候補キーを 1 つ見つける</h4>
<p><strong>【問題 1】（候補キーを 1 つ見つける）</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span>＝{f<sub>1</sub>, f<sub>2</sub>, <sub>…</sub>, f<sub>p</sub>}が指定されているとき，<b><span style="font-style: italic;">R</span></b> の候補キーを（何でもよいので）1 つ求めなさい．<br />
<b>（解答）</b><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> の全属性集合 Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> は <b><span style="font-style: italic;">R</span></b> のスーパーキーであることに着眼する．すると，次に示すアルゴリズムで候補キーが 1 つ見つかる．</p>
<p>&emsp;<strong>【候補キーを 1 つ見つけるアルゴリズム】</strong></p>
<table style="margin-top: -30px; border:none; margin-left: +40px;">
<tbody>
<tr>
<td style="width: 120px; border:none; vertical-align: top; ">ステップ 1</td>
<td style="border:none;">
K=Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> とおく．
</td>
</tr>
<tr>
<td style="border:none; vertical-align: top; ">ステップ 2</td>
<td style="border:none;">
属性A∈K を1つ選び，(K－A)<sup>+</sup> を計算する．もし，(K－A)<sup>+</sup>=Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> ならば，K=K－A とおいてステップ 2 に戻る．そうでなければ，K が求める候補キーである．ここに，－は差集合演算を表す．
</td>
</tr>
</tbody>
</table>
<p>&emsp;このアルゴリズムの正当性は明らかでしょう．注意するべき点は，どのような候補キーが返されるかはステップ 2 で取り除かれた属性 A の選択のされ方によることです．このような曖昧性はありますが，必ず候補キーは 1 つ返ってきます．このアルゴリズムの時間計算量は閉包を計算するアルゴリズムの時間計算量に依存し，それは多項式オーダーとなり扱いやすい問題です．</p>
<h4>4. 候補キーをすべて見つける</h4>
<p><strong>【問題 2】（候補キーをすべて見つける）</strong><br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> に所与の関数従属性の集合 <span style="font-style: italic;">F</span>＝{f<sub>1</sub>, f<sub>2</sub>, <sub>…</sub>, f<sub>p</sub>}が指定されているとき，<b><span style="font-style: italic;">R</span></b> の候補キーをすべて求めなさい．</p>
<p><strong>（解答）</strong><br />
&emsp;<b><span style="font-style: italic;">R</span></b> の候補キーをすべて求めるアルゴリズムを以下に示します．</p>
<p><strong>【候補キーをすべて見つけるアルゴリズム】</strong></p>
<table style="margin-top: -30px; border:none; margin-left: +40px;">
<tbody>
<tr>
<td style="width: 120px; border:none; vertical-align: top; ">ステップ 1</td>
<td style="border:none;">
Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> の<ruby>冪<rt style="background-color: #DDDDDD;">べき</rt></ruby>集合 2<sup>Ω<span style="font-style: italic;"><b><sub>R</sub></b></span></sup> の元をその構成要素の数 i (i=0, 1, <sub>…</sub>, |Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|)で類別して，S<sub>0</sub>，S<sub>1</sub>，…, S<sub>|Ω<span style="font-style: italic;"><b><sub>R</sub></b></span>|</sub>を作る．すなわち，2<sup>Ω<span style="font-style: italic;"><b><sub>R</sub></b></span></sup> = S<sub>0</sub>∪S<sub>1</sub>∪ <sub>…</sub> ∪S<sub>|Ω<span style="font-style: italic;"><b><sub>R</sub></b></span>|</sub>である．
</td>
</tr>
<tr>
<td style="border:none; vertical-align: top; ">ステップ 2</td>
<td style="border:none;">
i∈{1, <sub>…</sub>, |Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|}に対して i=1 から始めて順次，次の処理をする．<br />
S<sub>i</sub>={X<sub>i,1</sub>, X<sub>i,2</sub>, <sub>…</sub>, X<sub>i,ni</sub>}の各元 X<sub>i,j</sub> に対して X<sub>i,j</sub><sup>+</sup> を計算する．ここに，n<sub>i</sub>=<sub>|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|</sub>C<sub>i</sub> (=|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|! / (i!×(|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|－i)!)) は組合せ（combination）を表す．このとき，もし X<sub>i,j</sub><sup>+</sup>=Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>なら，X<sub>i,j</sub> は候補キーである．このとき，各|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|≧k≧i+1であるkに対して，S<sub>k</sub>=S<sub>k</sub>－{Y∈S<sub>k</sub>|Y⊃X<sub>i,j</sub> }とS<sub>k</sub> を再編成する（つまり，X<sub>i,j </sub>を含むスーパーキーをこの後の候補キー探索処理から除外する）．
</td>
</tr>
<tr>
<td style="border:none; vertical-align: top; ">ステップ 3</td>
<td style="border:none;">
ステップ 2 の操作が終了した時点で得られていた候補キーが求める結果である．
</td>
</tr>
</tbody>
</table>
<p style="margin-top: -40px; ">
&emsp;このアルゴリズムは Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> のすべての部分集合（空集合を除く）について，その濃度の小さい方から大きい方の順，すなわちS<sub>1</sub>，S<sub>2</sub>，…, S<sub>|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|</sub> の順に，S<sub>i</sub> の各元が候補キーとなっているか否かを総当たりで検証していくこと（S<sub>i</sub>の任意の 2元 X<sub>i,j</sub> と X<sub>i,k</sub> が包含関係になることはないのでどちらかが他方のスーパーキーになることはないことに注目すること），そして S<sub>k</sub>を再編成することでスーパーキーを除外していることから，その正当性は明らかでしょう．しかし，それが故に，その時間計算量は指数オーダーとなり，<strong>扱いにくい問題</strong>（intractable problem）となります．</p>
<p>&emsp;さて，復習がてらに上述のアルゴリズムを使って，候補キーをすべて求める問題と解を 2 つ例示しましょう．
</p>
<p><strong>【例題 1】</strong>（データベーススペシャリスト平成29年春期 午前Ⅱ 問4）<br />
関係 R(A，B，C，D，E)において，<br />
&emsp;関数従属 {A，B}→C，{B，C}→D，D→{A，E}<br />
が成立する．これらから決定できるRの候補キーを全て挙げたものはどれか．<br />
&emsp;{A，B，C}<br />
&emsp;{A，B}，{B，C}<br />
&emsp;{A，B}，{B，C}，{B，D}<br />
&emsp;{B，C}，{C，D}</p>
<p><strong>（解答）</strong><br />
&emsp;{A，B}，{B，C}，{B，D} が正解である．<br />
&emsp;これを本稿に示した「候補キーをすべて見つけるアルゴリズム」に則り示すと次の通りである．なお，見やすさのために，{A，B} を AB，{A，B}→C を AB→C という具合に表現し直している．<br />
&emsp;まず，ステップ 1 の処理をする．<br />
&emsp;Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>={ A，B，C，D，E }なので，|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|=5，Ω<b><span style="font-style: italic;"><sub>R</sub></span></b> の<ruby>冪<rt style="background-color: #DDDDDD;">べき</rt></ruby>集合 2<sup>Ω<span style="font-style: italic;"><b><sub>R</sub></b></span></sup> の元を構成要素数で類別して，S<sub>i</sub>，i=0～5を作ると， S<sub>0</sub>=Φ（空集合），S<sub>1</sub>={A，B，C，D，E}，S<sub>2</sub>={AB, AC, AD, AE, BC, BD, BE, CD, CE, DE, ABC}，S<sub>3</sub>={ABD, ABE, ACD, ACE, ADE, BCD, BCE, BDE, CDE}，S<sub>4</sub>={ABCD, ABCE, ABDE, ACDE, BCDE}，S<sub>5</sub>={ABCDE}となる．すなわち，2<sup>Ω<span style="font-style: italic;"><b><sub>R</sub></b></span></sup> = S<sub>0</sub>∪S<sub>1</sub>∪S<sub>2</sub>∪S<sub>3</sub>∪S<sub>4</sub>∪S<sub>5</sub>である．<br />
&emsp;続いて，ステップ 2 の処理をする．<br />
&emsp;まず，S<sub>1</sub> に対してステップ 2 の処理をすると，結果は次のとおりである．<br />
&emsp;A<sup>+</sup>=A，B<sup>+</sup>=B，C<sup>+</sup>=C，D<sup>+</sup>=ADE，E<sup>+</sup>=E．つまり，候補キーはない．<br />
&emsp;続いて，S<sub>2</sub> に対しての処理結果は次のとおりである．<br />
&emsp;<b>AB<sup>+</sup>=ABCDE</b>, AC<sup>+</sup>=AC, AD+=ADE, AE<sup>+</sup>=AE, <b>BC<sup>+</sup>=ABCDE</b>, <b>BD<sup>+</sup>=ABCDE</b>, BE<sup>+</sup>=BE, CD<sup>+</sup>=ACDE, CE<sup>+</sup>=CE, DE<sup>+</sup>=ADE．つまり，AB，BC，BD が候補キーであることが分かった．そこで，S<sub>3</sub>～S<sub>5</sub> の再編作業を行う．まず，S<sub>3</sub> については，AB，BC，BD を含む要素を S<sub>3</sub>から除外して改めて S<sub>3</sub> を作成すると次のとおりである．S<sub>3</sub>={ACD, ACE, ADE, CDE}．S<sub>4</sub> と S<sub>5</sub> に対しても同様な操作を行い，S<sub>4</sub>={ACDE}, S<sub>5</sub>=Φ となる．<br />
&emsp;続いて，再編成された S<sub>3</sub> に対してステップ 2 の処理をすると次のとおりである．<br />
&emsp;ACD<sup>+</sup>=ACDE, ACE<sup>+</sup>=ACE, ADE<sup>+</sup>=ADE, CDE<sup>+</sup>=ACDE．つまり，候補キーはない．<br />
&emsp;続いて，S<sub>4</sub> の処理を行うと，ACDE<sup>+</sup>=ACDE であり，候補キーはない．<br />
&emsp;S<sub>5</sub>=Φ なので候補キーはない．<br />
&emsp;よって，AB，BC，BD が <b><span style="font-style: italic;">R</span></b> の候補キーの全てであることが分かる．</p>
<p><strong>【例題 2】</strong>（2 の<ruby>冪<rt style="background-color: #DDDDDD;">べき</rt></ruby>乗個の候補キーが見つかる例）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A<sub>1</sub>, A<sub>2</sub>, B<sub>1</sub>, B<sub>2</sub>)に所与の関数従属性 A<sub>i</sub>→B<sub>i</sub>，B<sub>i</sub>→A<sub>i</sub> (i=1, 2)が指定されているとする．<b><span style="font-style: italic;">R</span></b> の候補キーをすべて求めなさい．</p>
<p><strong>（解答）</strong><br />
&emsp;Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>={A<sub>1</sub>, A<sub>2</sub>, B<sub>1</sub>, B<sub>2</sub>}とすると，S<sub>0</sub>=Φ，S<sub>1</sub>={A<sub>1</sub>, A<sub>2</sub>, B<sub>1</sub>, B<sub>2</sub>}，S<sub>2</sub>={ A<sub>1</sub>A<sub>2</sub>, A<sub>1</sub>B<sub>1</sub>, A<sub>1</sub>B<sub>2</sub>, A<sub>2</sub>B<sub>1</sub>, A<sub>2</sub>B<sub>2</sub>, B<sub>1</sub>B<sub>2</sub>}，S<sub>3</sub>={A<sub>1</sub>A<sub>2</sub>B<sub>1</sub>, A<sub>1</sub>A<sub>2</sub>B<sub>2</sub>, A<sub>1</sub>B<sub>1</sub>B<sub>2</sub>, A<sub>2</sub>B<sub>1</sub>B<sub>2</sub>}，S<sub>4</sub>={ A<sub>1</sub>A<sub>2</sub>B<sub>1</sub>B<sub>2</sub>}となる．<br />
&emsp;そこで，S<sub>1</sub> の各元に対してその閉包を計算する．A<sub>i</sub><sup>+</sup>=A<sub>i</sub>B<sub>i</sub> (i=1,2)，B<sub>i</sub><sup>+</sup>=A<sub>i</sub>B<sub>i</sub> (i=1,2)であり，候補キーではない．そこで，S<sub>2</sub> の各元に対してその閉包を計算する．A<sub>1</sub>A<sub>2</sub><sup>+</sup>=A<sub>1</sub>A<sub>2</sub>B<sub>1</sub>B<sub>2</sub>, A<sub>1</sub>B<sub>1</sub><sup>+</sup>=A<sub>1</sub>B<sub>1</sub>, A<sub>1</sub>B<sub>2</sub><sup>+</sup>=A<sub>1</sub>A<sub>2</sub>B<sub>1</sub>B<sub>2</sub>, A<sub>2</sub>B<sub>1</sub><sup>+</sup>=A<sub>1</sub>A<sub>2</sub>B<sub>1</sub>B<sub>2</sub>, A<sub>2</sub>B<sub>2</sub><sup>+</sup>=A<sub>2</sub>B<sub>2</sub>, B<sub>1</sub>B<sub>2</sub><sup>+</sup>=A<sub>1</sub>A<sub>2</sub>B<sub>1</sub>B<sub>2</sub>となる．従って，A<sub>1</sub>A<sub>2</sub>, A<sub>1</sub>B<sub>2</sub>, A<sub>2</sub>B<sub>1</sub>, B<sub>1</sub>B<sub>2</sub> が候補キーであることが分かる．S<sub>3</sub> の再編作業を行うと S<sub>3</sub> は Φ となるので，ここで処理が終了する．</p>
<p>&emsp;例題 2 を一般化してすべての候補キーを求める問題の時間計算量について補足説明を行います．リレーションスキーマ <b><span style="font-style: italic;">R</span></b>(A<sub>1</sub>, A<sub>2</sub>, ···, A<sub>n</sub>, B<sub>1</sub>, B<sub>2</sub>, ・・・, B<sub>n</sub>)に所与の関数従属性集合 <span style="font-style: italic;">F</span> = {A<sub>i</sub>→B<sub>i</sub>, B<sub>i</sub>→A<sub>i</sub>|i∈{1, 2, <sub>…</sub>, n}}が指定された場合，<b><span style="font-style: italic;">R</span></b> は，A<sub>1</sub>A<sub>2</sub>・・・A<sub>n</sub>, B<sub>1</sub>A<sub>2</sub>・・・A<sub>n</sub>, A<sub>1</sub>B<sub>2</sub>A<sub>3</sub>・・・A<sub>n</sub>, ・・・, B<sub>1</sub>B<sub>2</sub>・・・B<sub>n</sub>と 2<sup>n</sup>個の候補キーを有することになるので，n が大きくなると実用的でなくなります．つまり，例題 2 では n=2 なので候補キーの数は 2<sup>2</sup>=4 で済みましたが，このようなタイプの関数従属性集合 <span style="font-style: italic;">F</span> を指定されたリレーションスキーマ <b><span style="font-style: italic;">R</span></b> の候補キーの数は 2<sup>n</sup>なので，n が大きくなるにつれて，それ数え上げるには指数時間かかり，一般にすべての候補キーを求める問題は扱いにくい問題であることが直感できると思います．</p>
<h4>5. 候補キーの数の上限は？</h4>
<p>&emsp;1 つのリレーションスキーマには幾つ候補キーが存在しうるのか，その上限について次の結果[2, 3]が示されているので，紹介しておきたいと思います．</p>
<p><strong>【命題 2】</strong>（候補キーの数の上限）<br />
&emsp;リレーションスキーマ <b><span style="font-style: italic;">R</span></b> の候補キーの数は高々 <sub>n</sub>C<sub>⌊n/2⌋</sub>である．ここに，C は組合せ，⌊r⌋ は r を越えない最大の自然数を表し，|Ω<b><span style="font-style: italic;"><sub>R</sub></span></b>|=n とする．<br />
<strong>（証明）</strong><br />
&emsp;濃度 n の集合 S において，候補キーの集合はお互いが集合の包含関係にないという意味でスパナー族（Sperner family）をなし，従って，比較不可能な S の部分集合の数は高々 <sub>n</sub>C<sub>⌊n/2⌋</sub> となる．</p>
<p>&emsp;例えば，n=2 なら <sub>n</sub>C<sub>⌊n/2⌋</sub>=2 であるので，候補キーの数は高々 2 です．<b><span style="font-style: italic;">R</span></b>(A, B)とすれば，もし上限の 2 個の候補キーがあった場合には，それらは {A} と {B} です．n=3 なら <sub>n</sub>C<sub>⌊n/2⌋</sub>=3 であるので，<b><span style="font-style: italic;">R</span></b>(A, B, C)とすれば，もし上限の 3 個の候補キーがあった場合には，それらは {A, B}，{A, C}，{B, C} です．n=4 なら <sub>n</sub>C<sub>⌊n/2⌋</sub>=6 であるので，<b><span style="font-style: italic;">R</span></b>(A, B, C, D)とすれば，もし上限の 6 個の候補キーがあったとすれば，それらは {A, B}，{A, C}，{A, D}，{B, C}，{B, D}，{C, D}です．<b><span style="font-style: italic;">R</span></b>(A, B, C, D, E)とすれば，n=5 で <sub>5</sub>C<sub>⌊5/2⌋</sub>=10 であるので，もし上限の 10 個の候補キーがあったとすれば，それらは {A, B}，{A, C}，{A, D}，{A, E}, {B, C}，{B, D}，{B, E}, {C, D}, {C, E}, {D, E} です．例題 2 の候補キーの数は 4 でしたが，2<sup>2</sup>＜<sub>4</sub>C<sub>2</sub>=6 とこの結果に符合しています．</p>
<h4>6. おわりに</h4>
<p>&emsp;リレーションの候補キーを求める問題を論じました．リレーションスキーマに所与の関数従属性集合が指定されたとき，候補キーを 1 つ見つけるためのアルゴリズムと，候補キーをすべて見つけるアルゴリズムを提示しました．上に見たように，同じく候補キーを求める問題ではあるのですが，「候補キーを 1 つ見つける問題」の時間計算量は多項式オーダーなので扱いやすい問題ですが，「候補キーをすべて見つける問題」の時間計算量は指数オーダーとなり扱いにくい問題であることを示しました．つまり，すべての候補キーを求めようとすると，リレーションスキーマの全属性数が小さいときには問題となりませんが，それが大きくなるととてつもない時間を要することとなり，現実的ではなくなるということです．とりあえず，候補キーが「1 つ」見つかればよいというなら話は簡単そうですが，「すべて」と言われると気長に根気よく見つけていくしか<ruby>術<rt style="background-color: #DDDDDD;">すべ</rt></ruby>はなさそうですね．</p>
<p>【文献】</p>
<p style="margin-top: -10px;" >[1]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
増永良文．リレーショナルデータベース入門[第3版]．サイエンス社，2017.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[2]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
J. Demetrovics. On the equivalence of candidate keys with Sperner systems. Acta Cybernetica 4, pp.247-252, 1979.
</td>
</tbody>
</table>
<p style="margin-top: -22px;" >[3]</p>
<table style="border:none; margin-top: -62px; margin-left: 20px; margin-bottom: -00px;" align="left" >
<tbody style="border:none;">
<td style="width: 800px; border:none;">
J. Demetrovics and G.O.H. Katona. A survey of some combinatorial results concerning functional dependencies in database relations. Annals of Mathematics and Artificial Intelligence 7, pp.63-82, 1993.
</td>
</tbody>
</table>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>増永教授のDB特論①「6NF？」</title>
		<link>https://www.sraoss.co.jp/tech-blog/db-special-lecture/masunaga-db-special-lecture-1/</link>
		
		<dc:creator><![CDATA[増永良文 (Yoshifumi Masunaga)]]></dc:creator>
		<pubDate>Tue, 04 Jan 2022 23:00:14 +0000</pubDate>
				<category><![CDATA[増永教授のDB特論]]></category>
		<category><![CDATA[6NF]]></category>
		<category><![CDATA[RDB]]></category>
		<category><![CDATA[リレーショナルデータベース]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=7714</guid>

					<description><![CDATA[&#160; データベース設計に関心のある方なら，6NF って用語，どこかで目にしたり耳にしたりしたことありませんか？リレーションの第 6 正規形（sixth normal form）のことです．一体何なんでしょうか？  ...]]></description>
										<content:encoded><![CDATA[<p>&nbsp;<br />
<span id="more-7714"></span></p>
<p>データベース設計に関心のある方なら，<strong>6NF </strong>って用語，どこかで目にしたり耳にしたりしたことありませんか？リレーションの<strong>第 6 正規形</strong>（sixth normal form）のことです．一体何なんでしょうか？<br />
<em>　</em>これまでリレーショナルデータベースの正規化理論では，リレーションを幾つかの射影に分解して，得られた結果を自然結合演算で再合成して元に戻ることができる（情報無損失分解）か否かで正規化の体系を創り上げてきました．関数従属性（FD）や多値従属性（MVD）は 2 分解，つまり 1 枚のリレーションを 2 つの射影に分解する考え方でリレーションの情報無損失分解を規定します．FDにより第 2 正規形，第 3 正規形，Boyce-Codd 正規形（BCNF）が規定されました．FD を概念拡張した MVD により第 4 正規形（4NF）が規定されました．FD や MVD はリレーションを 2 分解しますが，MVD をさらに概念拡張して結合従属性（JD）が導入されると，JD は一般にリレーションが n（n≧2）個の射影に情報無損失分解されるための必要かつ十分条件となり，第 5 正規形（5NF）が明らかとなりました．JD は n を 2 に限定しないので，与えられたリレーションを幾つかの射影に情報無損失分解して更新時異状を解消しようというリレーションの正規化理論の枠組みは，JD が規定する 5NF で打ち止めとなり，6NF という正規形は「ない」と理解されています．これは皆さんも納得済みのことでしょう．<br />
<em>　</em>ところが，第 6 正規形（6NF）という言葉が聞こえてくるわけです．一体何なんでしょうか？これは C. J. Date が言い出した正規形で，彼は 5NF が従来の枠組みでは最も高い正規度であると認識しているといいながらも，6NF を主張しているのです．まず，彼の与えた 6NF の定義を見てみましょう[1]．<br />
【定義1】（Sixth normal form for regular data by C.J. Date）<br />
Relvar R is in <strong>sixth normal form</strong> (6NF) if and only if the only JDs that hold in R are trivial ones.¹<br />
<em>　</em>では，これは何を意味しているのでしょうか？そのためには，少し寄り道をする必要があります．次に，彼の与えた JD の定義を確認します．</p>
<hr style="margin-top: -15px;" align="left" width="40%" />
<p style="margin-top: -15px; margin-bottom: 20px;"><span style="font-size: small;"><sup>1</sup> &#8220;regular data&#8221; は temporal data と区別しての言い方で，&#8221;relvar&#8221;はリレーションと読み替えてよい． Trivial については脚注4 の意味に同じ．</span></p>
<p>【定義2】（結合従属性（JD）by Date）<br />
Let X<sub>1</sub>, &#8230;, X<sub>n</sub> be subsets of the heading H of relvar R²; then the join dependency (JD) <img decoding="async" src="https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781449330187/files/httpatomoreillycomsourceoreillyimages1137282.png" alt="" width="15" height="15" /> { X<sub>1</sub> , &#8230; , X<sub>n</sub> } holds in R if and only if R can be nonloss decomposed into its projections on X<sub>1</sub>, &#8230; , X<sub>n</sub>.<br />
<em>　</em>この定義は，表現こそ異なりますが，次に示す従来知られている結合従属性（JD）の定義と同じです³．</p>
<hr style="margin-top: -15px;" align="left" width="40%" />
<p style="margin-top: -15px; margin-bottom: 20px;"><span style="font-size: small;"><sup>2</sup> the heading H of relvar R とは，従来の言葉で表せば H がリレーション R の全属性集合という意味です．従来，結合従属性は*{}と書いてきましたが， Date は*の対象がリレーションではなく属性集合なので，それはおかしいと異議を唱え，*を使わず<img decoding="async" src="https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781449330187/files/httpatomoreillycomsourceoreillyimages1137282.png" alt="" width="15" height="15" />（星印）を使うとしています．表現の違いだけで中身は同じです．ここでは特別に留意しない限り，*を使います．<br />
<sup>3</sup> 従来の定義や関連する事項は拙著[2]を参照して下さい．</span></p>
<p>【定義3】（JD）<br />
<b><span style="font-style: italic;">R</span></b>(A, B, &#8230;, C)をリレーションスキーマ，ここに H={A, B, &#8230;, C}，とするとき，<b><span style="font-style: italic;">R</span></b> の任意のインスタンス R がその n 個の射影 R[X<sub>1</sub>]，R[X<sub>2</sub>]，&#8230; ，R[X<sub>n</sub>]に情報無損失分解される，つまり R=R[X<sub>1</sub>]*R[X<sub>2</sub>]* &#8230; *R[X<sub>n</sub>]が成立するとき，<b><span style="font-style: italic;">R</span></b> に JD *(X<sub>1</sub>, X<sub>2</sub>&#8230; , X<sub>n</sub>)が存在するという．<br />
<em>　</em>そして，このとき，JD を使って 5NF は次のように定義されます．<br />
【定義4】（5NF）<br />
リレーション R が 5NF であるとは，*(X<sub>1</sub>, X<sub>2</sub>, &#8230; , X<sub>n</sub>)を R の JD とするとき，次のいずれかが成立するときをいう．<br />
<em>　</em>(1) *(X<sub>1</sub>, X<sub>2</sub>, &#8230;, X<sub>n</sub>)は自明な結合従属性である<sup>4</sup>．<br />
<em>　</em>(2) 各 X<sub>i</sub> は R のスーパキーである．<br />
<em>　</em>一方，Date が与えた 5NF の定義は次の通りです．</p>
<hr style="margin-top: -15px;" align="left" width="40%" />
<p style="margin-top: -15px; margin-bottom: 20px;"><span style="font-size: small;"><sup>4</sup> JD *(X<sub>1</sub>, X<sub>2</sub>, &#8230; , X<sub>n</sub> が trivial （自明）とは X<sub>1</sub>, X<sub>2</sub>, &#8230;, X<sub>n</sub> のうちの一つが R の全属性集合に等しいときをいいます．</span></p>
<p>【定義5】（5NF by Date）<br />
Relvar R is in fifth normal form (5NF) if and only if every JD of R is implied by the keys of R.<br />
<em>　</em>さて，定義4 と定義5 を見比べてみると，微妙な差に気づきますね．即ち，Date の 5NF の定義は従来の 5NF の定義の（2）項の条件を満たしているときと定義しているというわけです．<br />
<em>　</em>では，従来の 5NF の定義の（1）項に相当する場合の 5NF リレーションは，Date では一体どこでどのように定義されているのでしょうか？定義1 を見直してください．それはまさしく従来の 5NF の定義の（1）項のことです．つまり，Date の定義した 6NF は従来の 5NF の定義の（1）項の条件が成立するときの 5NF を言っているということになります．<br />
<em>　</em>では，なぜそれを特に 6NF ということにしたのでしょうか？Date の真意は測りかねますが，できるだけ彼の立場に立って考えてみましょう．そこで，Date の著書[1]に記載されている例を引用して，そこで定義されているリレーションの正規度を考察してみます．3 つのリレーション S，P，SP があるとします．ここに，S は suppliers，P は parts，そして SP は shipments を表すリレーションで，SNO は supplier number，PNO は part number，STATUS は status value，CITY は location，QTY は quantity などを表します．アンダーラインが引かれている属性が主キーです．また，S には関数従属性 CITY→STATUS があるとします．<br />
<em>　</em>S(<u>SNO,</u> SNAME, STATUS, CITY)<br />
<em>　</em>P(<u>PNO,</u> PNAME, COLOR, WEIGHT, CITY)<br />
<em>　</em>SP(<u>SNO, PNO,</u> QTY)<br />
そうすると，S は第 3 正規形にもなっていなく，P は 5NF であるが 6NF ではなく，SP は 6NF となります．なぜでしょうか？<br />
<em>　</em>まず，S が第 3 正規形にもなっていないことは遷移的関数従属性 SNO→CITY→STATUS の存在で明らかでしょう．P には *({ PNO, PNAME }, { PNO, COLOR, WEIGHT, CITY }), *({PNO, COLOR}, {PNO, PNAME, WEIGHT, CITY }), *({PNO, PNAME, COLOR}, {PNO, EIGHT, CITY }), &#8230; , *({PNO, PNAME}, {PNO, COLOR}, {PNO, WEIGHT}, {PNO, CITY}) など多数の JD があることが分かりますが，これらすべての JD は P の自明でない情報無損失分解を誘引し定義4（5NF）の（2）項の条件を満たすので 5NF であり，かつこれらの JD は自明ではないので 6NF ではないことが分かります．一方，SP では { SNO, PNO}→QTY なので，この FD を用いて SP を情報無損失分解しても SP そのものにしかならず，これを JD で表せば *({SNO, PNO, QTY})となり，定義4（5NF）の（1）項の条件を満たす，つまり定義1 を満たすので，従って 6NF ということになります．<br />
<em>　</em>そこで，6NF の意味ですが，5NF である P を JD *({PNO, PNAME}, {PNO, COLOR}, {PNO, WEIGHT}, {PNO, CITY}) を使って情報無損失分解すると，P[PNO, PNAME], P[PNO, COLOR], P[PNO, WEIGHT], P[PNO, CITY] とそれぞれが 6NF のリレーションに情報無損失分解できることになります．言い換えると，P の場合，P 自体では parts の PNAME, COLOR, WEIGHT, CITY という 4 つの属性を合わせて一つの意味を持つリレーションとして設計されたのですが，それを 5NF ではあるが 6NF ではないという理由で 4 つに情報無損失分解すると，例えば P[PNO, PNAME] という成分は parts の NAME のみを属性として持つリレーションということになります．<br />
<em>　</em>つまり，Date の主張したいことは，データベースを設計するにあたり，リレーション P を例にとれば，P のままでは「この part の名前は P<sub>1</sub>で，色は L<sub>1</sub>で，重さは W<sub>1</sub>で，その part の保管場所は C<sub>1</sub> である」という 4 つの事象を一括して格納するリレーションを定義したことになりますが，それは望ましくなく，5NF ではあっても 6NF でなければ，「この part の名前は P<sub>1</sub> である」，「この part の色は L<sub>1</sub> である」，「この part の重さは W<sub>1</sub> である」，「この part の保管場所は C<sub>1</sub> である」という具合に，4 つの事象を個別に格納する 4 つのリレーションを定義するべきだと Date は主張したかったということになります．<br />
<em>　</em>みなさん，いかがでしょう？ここまで細分化したリレーショナルデータベース設計をやりますか？やるとしたら，どのような時？もしあったら是非教えてください．<br />
<em>　</em>結びですが，6NF ってなんだか tricky だな，と筆者は感じています．なぜならば，Date は従来の 5NF の定義を「定義4（5NF）」ではなく「定義5（5NF by Date）」で与えることによって，その間隙を埋めるべく 6NF を持ち出しているからです．確かに，5NF を定義5 のように定義する文献も見受けられますが，FD が自明であることや MVD が自明であることは，リレーションがそれぞれ BCNF や 4NF であるための条件となっています．したがって，5NF の定義は定義4（5NF）でよいのではないかと思うわけです．そうすれば，6NF を言い出す隙はありません．そのようなわけで，6NF に直面したら（ギョッとするのではなく）あくまで 5NF の一つという認識で臨むのが正解かなと考える次第です．</p>
<p>【文献】<br />
[1] C.J. Date. Database Design and Relational Theory. O’Reilly Media, Inc., 2012.<br />
[2] 増永良文．リレーショナルデータベース入門[第3版]，サイエンス社，2017．</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
