Oracle Database 概要 11gリリース1(11.1) E05765-03 |
|
この章では、整合性制約を使用してデータベースに関連するビジネス・ルールを規定し、表への無効な情報入力を防止する方法について説明します。
この章の内容は、次のとおりです。
列データが、データベース管理者やアプリケーション開発者によって事前定義された規則に準拠するのは重要なことです。
たとえば、データベース表の列に含まれるデータは、その列に設定された特定の規則の制約を受けることがあります。このような制約は、ある表と別の表のデータ列の関連付けに影響を与える可能性があります。
この項の内容は、次のとおりです。
この項では、様々な種類のデータ整合性を規定するために表の列に適用できる規則について説明します。
NULL規則: NULL規則は、単一の列に対して定義される規則で、その列でのNULLが入っている(値がない)行の挿入や更新を許可または禁止します。
一意の列値: 列(または列の集合)に対して定義される一意の列値規則は、その列(または列の集合)に含まれる値が一意である場合にかぎって、行の挿入または更新を許可します。
主キー値: キー(列または列の集合)に対して定義される主キー値規則は、表の中の各行がキーの値によって一意に識別できることを指定します。
参照整合性規則: 参照整合性規則は、1つの表のキー(列または列の集合)に対して定義される規則であり、そのキーの値が関連する表のキーの値(参照値)と一致することを保証します。
また、参照整合性には、参照先のデータに対してどのようなタイプのデータ操作を許可するか、およびその操作の結果として依存データがどのような影響を受けるかについて指示する規則が含まれています。参照整合性に関連する規則は、次のとおりです。
NULL
に設定されます。
RESTRICT
とは異なります。(Oracle Databaseはデフォルト・アクションとしてNO ACTIONを使用します。)
複雑な整合性チェック: 列(または列の集合)に対して設定されるユーザー定義の規則であり、その列の値に基づいて、行の挿入、更新、削除を許可または禁止します。
Oracle Databaseでは、前述のデータ整合性規則を定義し、規定できます。これらの規則のほとんどは、整合性制約またはデータベース・トリガー(挿入、更新または削除の各操作で自動的に起動されるストアド・データベース・プロシージャ)を使用して簡単に定義できます。
子表と親表が分散データベースの別のノードにある場合、宣言整合性制約を使用して参照整合性の規定はできません。ただし、データベース・トリガーを使用して、分散データベースで参照整合性を規定することはできます。
ENABLE
を指定すると、入ってくるすべてのデータが制約に準拠していることが保証されます。
DISABLE
を指定すると、入ってくるデータは、制約に準拠しているかどうかに関係なく許可されます。
VALIDATE
を指定すると、既存のデータが制約に準拠していることが保証されます。
NOVALIDATE
は、一部の既存データが制約に準拠していない可能性があることを意味します。
さらに、次のようになります。
ENABLE VALIDATE
はENABLE
と同じです。制約がチェックされ、すべての行が保持されることが保証されます。
ENABLE NOVALIDATE
は、制約はチェックされますが、すべての行についてTRUEでなくても許されることを意味します。これにより、既存の行が制約に違反することは許され、しかも、新しい行や変更した行に対してはすべて有効であることが保証されます。 ALTER TABLE
文のENABLE NOVALIDATE
オプションを使用すると、表内のすべてのデータの妥当性を最初にチェックせずに、使用禁止にした制約について制約チェックを再開できます。
DISABLE NOVALIDATE
はDISABLE
と同じです。制約はチェックされず、TRUEでなくてもかまいません。
DISABLE VALIDATE
を指定すると制約が使用禁止になり、制約の索引が削除され、対象となる列の変更は許されなくなります。 一意制約の場合、DISABLE VALIDATE
状態では、ALTER TABLE
文のEXCHANGE PARTITION
句を使用して、非パーティション表からパーティション表にデータを効率よくロードできます。
これらの状態間の遷移は、次の規則で制御されます。
NOVALIDATE
が指定されていない場合、ENABLE
は暗黙的にVALIDATE
を意味します。
VALIDATE
が指定されていない場合、DISABLE
は暗黙的にNOVALIDATE
を意味します。
VALIDATE
とNOVALIDATE
には、ENABLE
状態とDISABLE
状態に関するデフォルトの含意はありません。
DISABLE
状態からENABLE
状態に移る場合に、既存の索引がなければ一意索引が自動的に作成されます。同様に、一意キーまたは主キーがENABLE
からDISABLE
に移る場合に、一意索引で使用可能にされていれば、一意索引は削除されます。
NOVALIDATE
状態からVALIDATE
状態に移る場合は、すべてのデータをチェックする必要があります(この操作は、きわめて低速の場合があります)。ただし、VALIDATE
からNOVALIDATE
に移っても、データがチェックされたことが無視されるだけです。
ENABLE NOVALIDATE
状態からENABLE VALIDATE
状態への移動では、読取り、書込みまたは他のDDL文はブロックされません。パラレルに実行できます。Oracle Databaseでは、データベースの実表に無効なデータが入力されないようにするため、整合性制約を使用します。整合性制約を定義することによって、データベースの情報に関連付けるビジネス・ルールを規定できます。DML文を実行した結果が整合性制約に違反すると、Oracle Databaseはその文をロールバックし、エラーを戻します。
たとえば、employees
表のsalary
列に、どの行でもこの列に10,000より大きい数値を入れないという規則を規定する整合性制約を定義するとします。INSERT
文またはUPDATE
文がこの整合性制約に違反すると、Oracle Databaseはその文をロールバックし、通知エラー・メッセージを戻します。
この項の内容は、次のとおりです。
この項では、他の代替方法と比較して、データベースの表に関連付けられた整合性制約が優れている点を説明します。その利点は次のとおりです。
この項の内容は、次のとおりです。
宣言整合性制約は、アプリケーション・コードやデータベース・トリガーよりも優れています。SQL文を使用して整合性制約を定義するため、追加のプログラミングなしに表を定義または変更できます。SQL文は記述が容易で、プログラミングのエラーを避けられます。Oracle DatabaseがSQL文の機能を制御します。
また、ストアド・プロシージャを使用してデータ・アクセスを制御することによってデータ整合性を解決するという方法もありますが、整合性制約の場合はランダムなデータ・アクセスという柔軟性を犠牲にすることがないため、宣言アプローチを使用するほうがストアド・プロシージャより優れています。
整合性制約宣言の意味は明確に定義されており、個々の宣言規則ごとにパフォーマンスの最適化が実現されます。Oracle Databaseオプティマイザは、宣言を使用して、データをより詳細に認識し、問合せのパフォーマンスを全体として向上させます。(また、アプリケーション・コードとデータベース・トリガーから整合性規則を取り去ることによって、必要なときのみチェックが行われることが保証されます。)
整合性制約は、(アプリケーションではなく)表に対して定義され、データ・ディクショナリに格納されます。したがって、どのアプリケーションから入力されるデータも、表に対応付けられている同じ整合性制約を遵守する必要があります。アプリケーション・コードではなく、アプリケーション・コードの集中管理された整合性制約内にビジネス・ルールを保持することによって、どのデータベース・アプリケーションが情報を操作したとしても、データベース表には有効なデータが入っていることが保証されます。
整合性制約によって規定されるビジネス・ルールを変更する場合、管理者が整合性制約を変更するだけで、すべてのアプリケーションは変更後の制約を自動的に遵守するようになります。それに対して、それぞれのデータベース・アプリケーションのコードでビジネス・ルールを規定する場合、開発者はすべてのアプリケーションのソース・コードを修正して、その修正したアプリケーションを再コンパイルし、デバッグしてテストする必要があります。
Oracle Databaseは、各整合性制約ごとに、特定の情報をデータ・ディクショナリに格納します。Oracle DatabaseがSQL文を実行しチェックする前でも、データベース・アプリケーションが、その情報を使用して整合性制約の違反をユーザーに即時にフィードバックするように設計できます。たとえばOracle Formsアプリケーションは、文を発行する前でも、データ・ディクショナリに格納されている整合性制約の定義を使用して、フォームのフィールドに入力される値の違反をチェックできます。
大量のデータをロードする場合、制約チェックによるオーバーヘッドをなくすために、整合性制約を一時的に使用禁止にできます。データのロードが完了した後、整合性制約を使用可能にするのは簡単であり、整合性制約に違反した新しい行を別の例外表に自動的にレポートさせることもできます。
データ整合性の規則を規定することによる利点は、パフォーマンスを多少犠牲にして初めて獲得できます。一般に、整合性制約を組み込む場合のコストは、多くても、制約を評価するSQL文を実行するのと同じです。
整合性制約を使用して、通常列と仮想列の両方で値の入力時に制限を設定できます。次の制約を使用できます。
デフォルトでは、表のすべての列でNULLを使用できます。NULLは、値がないことを意味します。NOT
NULL
制約がある場合、表の列値にNULLを使用できません。
表のタイプおよび列のデータ型によっては、追加する列にNOT NULL
制約が使用され、かつデフォルト値が設定されている場合、データベースでの操作が最適化され、表がDML用にロックされる時間が短縮されることがあります。追加する列のデフォルト値が記述されたメタデータが、データベースの表に保存されます。そのため、列を追加してもデータベースで各行にデフォルト値を移入する必要がありません。これにより、表がロックされる時間が最小限になります。
NOT NULL
制約を持つ列は、行が1つも含まれていない表またはデフォルト値が指定された表にのみ追加できます。
一意
キー制約では、列または列の集合(キー)のすべての値が一意である必要があります。つまり、指定した列または列の集合について、表の2つの行の値が重複することは許されません。
この項の内容は、次のとおりです。
一意
キー制約の定義に含まれている列を、一意キーと呼びます。一意キーが2つ以上の列で構成されている場合、その列グループのことをコンポジット一意キーと呼びます。
「一意キー」という用語は、「一意キー制約」または「一意索引」のシノニムとして誤用されることがよくあります。しかし、「キー」とは、整合性制約の定義に使用される列または列のグループにすぎません。
たとえば、一意
キー制約では、市外局番と電話番号を何回でも入力できますが、特定の市外局番と電話番号の組合せが表内で重複することは許可されません。これにより、同じ電話番号が誤って入力されるのを防止できます。
一意キーとNOT NULL
整合性制約の両方を持つ列が一般的に使用されます。これらの組合せにより、ユーザーは一意キーに必ず値を入力することになり、さらに新しい行データが既存の行データと衝突することもなくなります。
データベースでは、各表に最大1つの主キー
制約を定義できます。この制約が指定されている1つ以上の列グループの値は、その行の一意識別子を構成します。つまり、それぞれの行は、その主キー値によって指定されます。
Oracle Databaseでは、主キー
整合性制約の実装により、次の2つのことが保証されます。
この項の内容は、次のとおりです。
表の主キー
整合性制約の定義に含まれる列を、主キーと呼びます。主キーは必須ではありませんが、次の利点を考慮して、すべての表に主キーを指定してください。
Oracle Databaseでは、すべての主キー
制約で索引が使用されます。列に主キー制約を作成すると、次の要素が暗黙的に作成されます。
コンポジット主キー制約は、コンポジット索引に課されているのと同じ32列までに制限されています。この索引の名前は、制約の名前と同じ名前です。また、制約の作成に使用するCREATE TABLE
文またはALTER TABLE
文にENABLE
句を組み込んで、索引の記憶域オプションを指定することもできます。主キー制約の作成時に使用できる索引がある場合、主キー制約は新しい索引を暗黙的に作成するかわりにその索引を使用します。
リレーショナル・データベースの中の異なる表は共通の列で関連付けることができ、列の関係を管理する規則が守られていることが必要です。参照整合性規則により、これらの関係が保たれることが保証されます。
表21-1に、参照整合性制約に関連する用語を示します。
参照整合性制約では、表の各行の外部キー値は親表の値と一致している必要があります。
図21-1に、emp
表のdeptno
列に対して定義された外部キーを示します。これにより、この列のすべての値がdept
表の主キー(つまりdeptno
列)の値と一致することが保証されます。このため、emp
表のdeptno
列に間違った部門番号が存在することはありません。
外部キーは、複数列として定義できます。ただし、コンポジット外部キーの列数とデータ型は、参照先のコンポジット主キーまたは一意キーと同じであることが必要です。コンポジット主キーおよび一意キーは32列までに制限されているため、コンポジット外部キーも32列までに制限されます。
この項の内容は、次のとおりです。
図21-2に示す別のタイプの参照整合性制約のことを、自己参照型整合性制約と呼びます。このタイプの外部キーは、同じ表の親キーを参照します。
図21-2では、参照整合性制約によって、emp
表のmgr
列のすべての値は、同じ行ではなくても、同じ表内のempno
列に現在存在する値と一致していることが保証されます。これは、すべての管理職は従業員である必要もあるためです。この整合性制約により、間違った従業員番号がmgr
列に存在する可能性がなくなります。
リレーショナル・モデルでは、外部キーの値は、参照先の主キーまたは一意キーの値と一致するか、NULLであることが可能です。コンポジット外部キーのいずれかの列がNULLの場合、そのキーのNULL以外の部分は、親キーの対応部分と一致している必要はありません。
参照整合性制約では、参照先の親キー値が修正された場合に子表の依存行に対して実行される特定のアクションを指定できます。Oracle Databaseの外部キー
整合性制約によってサポートされる参照アクションは、UPDATE
およびDELETE NO ACTION
、およびDELETE CASCADE
です。
この項の内容は、次のとおりです。
NO ACTION(デフォルト)オプションは、結果のデータが参照整合性制約に違反する場合に参照キー値を更新または削除できないことを指定します。たとえば、主キー値が外部キーの中の値によって参照されている場合は、依存データであるため、参照先の主キー値を削除できません。
参照キー値を含む行が削除された場合に、子表のうち依存している外部キー値を含むすべての行も削除されます。たとえば、親表の行が削除され、この行の主キー値が子表の1つ以上の外部キー値によって参照されている場合は、子表の中のこの主キー値を参照する行も子表から削除されます。
参照キー値を含む行が削除された場合に、子表のうち依存している外部キー値を含むすべての行の値がNULLに設定されます。たとえば、employee_id
がTMP
表内のmanager_id
を参照する場合は、管理者を削除すると、その管理者の部下である従業員全員の行のmanager_id
値がNULLに設定されます。
表21-2に、親表の主キー値または一意キー値および子表の外部キー値に対する異なる参照アクションごとに可能なDML文の概要を示します。
Oracle Databaseでは、親キーとそれに依存する外部キーとの関連において、同時実行性制御が最適化されます。ロックの動作は、外部キーの列が索引付けされているかどうかに依存します。外部キーが索引付けされていない場合、子表が頻繁にロックされ、デッドロックが発生し、同時実行性が低下する可能性があります。このため外部キーは、ほとんどの場合、索引付けが必要です。唯一の例外は、対応する一意キーまたは主キーの更新や削除が発生しないことが確実な場合です。
この項の内容は、次のとおりです。
次のような場合、データベースは子表に対する表ロックを取得します。
たとえば、hr.departments
表が、索引付けされていない外部キーdepartment_id
を含むhr.employees
の親である場合など。
たとえば、図21-3に示すように、データベース・セッションで、departments
表から行3が削除された場合。
図21-3では、子表の外部キー列に索引が作成されていないため、親表の行3の削除において子表に対する共有表ロックが取得されます。このロックでは、他のトランザクションは問合せはできますが、表の更新はできません。たとえば、employees
の電話番号は、departments
行の削除中に更新できません。表ロックは、departments
表へのDMLが完了すると、即時に解除されます。複数の行に影響がある場合、ロックは行ごとに取得および解除されます。
子表の外部キー列が索引付けされている場合、親表に対するDMLでは親表の表ロックが取得されます。このロックにより、トランザクションは排他表ロックを取得できませんが、親表に対するDMLの発生時に、親表または子表に対するDMLは阻止されません。この状況は、子表への更新が発生している間に、親表への更新または削除が発生する場合に適しています。
図21-4に、子表の外部キー列が索引付けされている場合の例を示します。親表はdepartments
、子表はemployees
です。セッションで、departments
の行3が更新されます。departments
に対するDMLによって、employees
への更新が阻止されることはありませんが、departments
の行の更新および削除は、employees
の索引に対する行レベルのロックが解除されるまで待機する必要があります。
子表でON DELETE CASCADE
を指定すると、親表からの削除によって、子表からも削除することができます。たとえば、departments
からレコードを削除した場合、削除された部門の従業員に関するレコードをemployees
から削除できます。この場合、待機とロックに関するルールは、親表から行を削除した後に子表から行を削除する場合と同じです。
列または列の集合に対するチェック
制約では、表のすべての行について、指定した条件がTRUEまたはUNKNOWNであることが必要です。DML文の結果でチェック
制約の条件がFALSEに評価される場合、その文はロールバックされます。
この項の内容は、次のとおりです。
チェック制約を使用すると、チェック条件を指定することによって、特定の目的の整合性規則を規定できます。チェック制約の条件には次のような制限があります。
SYSDATE
、UID
、USER
またはUSERENV
、あるいは疑似列LEVEL
またはROWNUM
を含むことはできません。
文字列リテラルまたはグローバリゼーション・サポート・パラメータを引数に指定したSQL関数(TO_CHAR
、TO_DATE
およびTO_NUMBER
など)が組み込まれているチェック
制約を評価する際、デフォルトではOracle Databaseはデータベースのグローバリゼーション・サポート設定を使用します。これらのデフォルトは、チェック
制約定義の中でそれらのファンクションにグローバリゼーション・サポート・パラメータを明示的に指定して、オーバーライドできます。
1つの列に、定義された列を参照する複数のチェック
制約を設定できます。1つの列に対して定義できるチェック
制約の数に制限はありません。
単一の列に対して複数のチェック
制約を作成する場合は、その目的が競合しないように慎重に設計してください。また、条件が特定の順序で評価されるとは考えないでください。Oracle Databaseでは、チェックの条件が矛盾しないかどうかは検証されません。
制約が存在する場合に許可されるアクションのタイプを把握する上で、Oracle Databaseが実際に制約をチェックするタイミングを理解しておくと役立ちます。この例では、次のような状況を想定します。
emp
表は、図21-2で定義されたものです。
mgr
列のエントリがempno
列の値に依存しています。わかりやすくするため、これ以降の説明では、emp
表のempno
列とmgr
列のみを対象にします。
emp
表に最初の行を挿入する場合を考えます。現在は行が存在しません。mgr
列がempno
列の既存の値を参照できない場合に行を入力する方法について考えます。この操作を実行するには、次の3つの方法が考えられます。
mgr
列にNOT
NULL
制約が定義されていない場合には、第1行のmgr
列にNULLを入力できます。外部キーにはNULLが許されるため、この行は表に正しく挿入されます。
empno
列とmgr
列の両方に同じ値を入力できます。このことから、Oracle Databaseが文の実行完了後に制約チェックを実行することがわかります。親キーと外部キーに同じ値を指定した行の入力を許可するために、Oracle Databaseは、文を実行(つまり、新しい行を挿入)してから、その新しい行のmgr
列に対応するempno
のある行がその表に含まれているかどうかをチェックします。
SELECT
文のネストを伴うINSERT
文など、複数行を挿入するINSERT
文により、相互に参照しあう行を挿入できます。たとえば、最初の行はempno
列が200でmgr
列が300、2番目の行はempno
列が300でmgr
列が200という挿入を実行できます。 このことから、制約チェックは文の実行が完了するまで遅延されていることがわかります。すべての行が挿入されてから、制約違反がないかどうかすべての行が調べられます。また、トランザクションが完了するまで制約のチェックを遅延させることもできます。
同じ自己参照型の整合性制約に関して、次の使用例を考えます。会社が買収された場合です。この買収に伴い、すべての従業員番号の現在の設定値に5000を加算して、新しい会社の従業員番号と調和させる必要があります。管理職番号は実際には従業員番号であるため、これらの値にも5000を加算する必要があります(図21-5を参照)。
UPDATE employees SET employee_id = employee_id + 5000, manager_id = manager_id + 5000;
制約は、各mgr
値がempno
値と一致するかどうかを検証するように定義されていますが、Oracle Databaseでは文の完了後に制約チェックが効率的に実行されるため、この文は有効です。図21-6に、制約チェックの前にSQL文全体のアクションが実行される流れを示します。
この項の例は、INSERT
文とUPDATE
文を実行した場合の制約チェックのメカニズムを示しています。これと同じメカニズムが、UPDATE
、INSERT
およびDELETE
文を含むすべてのタイプのDML文に使用されます。
また、これらの例は、自己参照型整合性制約を使用してチェックのメカニズムを示すものでした。これと同じメカニズムが、次にあげるすべてのタイプの制約に使用されます。
デフォルト値は、文の解析前にINSERT
文の一部として組み込まれます。このため、デフォルトの列値はすべての整合性制約チェックの対象になります。
制約の妥当性のチェックは、トランザクション終了時まで遅延できます。
制約によってアクション(DELETE CASCADEなど)が発生する場合は、遅延制約か即時制約かに関係なく、そのアクションは、アクションを発生させた文の一部として実行されます。
この項の内容は、次のとおりです。
制約は、遅延可能または遅延不可、および初期遅延または初期即時のどちらかに定義できます。これらの属性は、制約ごとに異なるものを指定できます。それらの定義は、CONSTRAINT
句の中で次のキーワードを使用して指定します。
制約について、追加、削除、使用可能と使用禁止の切替え、または妥当性チェックを実行できます。また、制約の属性も変更できます。
SET CONSTRAINTS
文は、特定のトランザクションのために、制約をDEFERRED
またはIMMEDIATE
のどちらかに指定します(構文的にも意味的にもANSI SQL-92規格に準拠)。この文を使用すると、制約名のリストまたはすべての制約(ALL
)を指定して、そのモードを設定できます。
SET CONSTRAINTS
モードは、トランザクションの継続時間中、または別のSET CONSTRAINTS
文によってモードが再設定されるまで有効です。
SET CONSTRAINTS
... IMMEDIATE
は、指定された制約を各制約文の実行直後にチェックするように指示します。チェック制約が一貫しており、他にSET CONSTRAINTS
文が発行されない場合、Oracle Databaseはまずトランザクション内で事前に遅延されている制約をチェックし、次にそのトランザクション内のそれ以降の文の制約を即時にチェックします。制約チェックが失敗すると、エラーが通知されます。この場合、COMMIT
を発行するとトランザクション全体が取り消されます。
ALTER SESSION
文にも、SET CONSTRAINTS
IMMEDIATE
またはDEFERRED
の句があります。これらの句では、暗黙的にすべて
の遅延制約が設定されます(つまり、制約名のリストは指定できません)。これらのオプションを指定することは、カレント・セッションで各トランザクションの最初にSET CONSTRAINTS
文を発行することと同じ意味を持ちます。
COMMIT
が成功するかどうかを調べる1つの方法は、トランザクションの最後に即時制約を設定することです。トランザクションの最後の文で制約をIMMEDIATE
に設定すれば、予期しないロールバックを回避できます。いずれかの制約がチェックを通らなかった場合は、エラーを訂正してから、トランザクションをコミットできます。
SET CONSTRAINTS
文は、トリガー内では許可されていません。
SET CONSTRAINTS
は分散型の文としても有効です。SET CONSTRAINTS ALL
文が出現すると、処理中のトランザクションがある既存のデータベース・リンクにそのことが知らされ、新しいリンクはトランザクションを開始すると同時にその文が出現したことを認識します。
あるユーザーのトランザクションで制約の矛盾(一意索引内に重複値が含まれているなど)が生成された場合、そのユーザーにはそのような制約の矛盾がわかります。マテリアライズド・ビューに対して遅延一意制約および遅延外部キー制約を設定すれば、リフレッシュ操作を高速かつ完全に完了できます。
遅延可能な一意制約は、常に一意でない索引を使用します。遅延可能制約を削除しても、その索引は残ります。制約を使用禁止にしても格納情報は残るため、この方法は便利です。遅延可能でない一意制約と主キーは、制約が規定される前に一意でない索引がキー列に置かれる場合には、一意でない索引も使用します。
|
Copyright © 1993, 2008 Oracle Corporation. All Rights Reserved. |
|