PostgreSQLなどのリレーショナルデータベースのトリガーは本当に必要ですか?


10

保存されたデータを検証してデータベースの整合性を保つためにトリガーを使用できることを知っています。ただし、データをデータベースに格納する前に、アプリケーション側でデータの検証を実行してはどうでしょうか。

たとえば、クライアントを保存し、DDLレベルでは簡単に実行できない検証を実行したいとします。 https://severalnines.com/blog/postgresql-triggers-and-stored-function-basics

別の例は監査です。

更新

トリガーとデータベーストランザクションがどのように連携するか。たとえば、挿入されているデータの検証を実行したい場合などです。トランザクション内で行われます。以前に何が起こるか:トランザクションがコミットされるか、トリガーが実行されますか?


However, why not perform validation of data on the application side before storing them into the database?まあ、これら2つは相互に排他的ではありません。両側で異なるものを検証する可能性があります。アプリケーション側の検証はビジネス中心ですが、データベースの検証はよりデータ中心です。いくつかの異なるアプリケーションによって供給されるデータベースを考えてください。
ライヴ

システムに無意味なデータのダンプを行っているだけの外部ソースからデータを挿入する必要がありますか?その場合、後で修正するために無効な形式でデータを挿入する必要がある場合があります。この場合、トリガーは無限の問題を引き起こします。これを覚えておいてください。トリガーを実行したくない場合があります。
Greg Burghardt

あなたの更新はそれ自体で、おそらくSOでの質問でなければなりませんが、あなたの質問はすでにDatabase Administrators.SEで回答を持っています。つまり、トランザクションがコミットされる前に「更新後」トリガーが実行され、トリガー内で例外がスローされると、ロールバックが発生します。
Doc Brown、

@GregBurghardtほとんどのデータベースには、これらの種類のアクティビティのトリガーを無効にするために使用できるステートメントがあります。
Blrfl

1
@Blrfl:はい。ただし、現在のセッションのチェックのみを条件付きで無効にする場合は、接続されているすべてのユーザーに対してこれらのトリガーが一時的に無効になる可能性があることに注意する必要があります。
Greg Burghardt

回答:


12

構築するアプリケーションシステムの種類によって異なります。

  • このアプリケーション専用の専用データベースを備えた1つのメインアプリケーションのみを含み、理想的にはアプリケーションとデータベースの進化を担当する1つのチームを含むアプリケーション中心のシステムを作成している場合、すべての検証ロジックを維持し、監査することもできます。アプリケーション内のロジック。

    これの主な利点は、アプリケーションとデータベースの間でビジネスロジックを分散する必要がないため、システムの保守と進化が容易になることが多いことです。おまけとして、特定のタイプのDBMSまたはDBMSベンダーにアプリケーションをあまり結び付けないでください。アプリケーションがトリガーを提供しない軽量のDBシステムを使用できるようにしたい場合、このアプローチは明らかに必要です。

  • ただし、多くの異なるアプリケーションが共通のデータベースを共有するシステムを作成し、将来どのアプリケーションがデータベースに書き込むか、または将来どのデータベースがデータベースにデータを入力するためのアプリケーションを開発するかを事前に想定できない場合は、あなたのデータベースができる限り多くのデータの一貫性を保証する責任があるでしょう。そして、それはトリガーが本当に役立つところです。大規模なシステムでは、参照制約ではこれで十分でないことがよくありますが、ストアドプロシージャを呼び出すトリガーは、必要なほとんどすべての種類の検証を実装できます。

トリガーを使用するもう1つの理由はパフォーマンスです。複雑なデータモデルでは、クライアントアプリケーションで使用可能な現在のワーキングセットの一部ではない多くの追加データを使用する必要がある複雑な整合性ルールに遭遇することは珍しくありません。クライアント側で検証を可能にするために、最初にこれらのデータをすべてネットワーク経由で転送すると、パフォーマンスに大きな影響を与える可能性があります。

この古いSEポストも参照してください:データベースのクリーニングのためのアプリケーションロジックとDBトリガー

そのため、構築しているシステムの種類を自分で決定し、トリガーがケースに適したツールであるかどうかを根拠に基づいて決定できます。


3

問題はデータの質に対する責任についてだと思います。

答えは、システムの見方によって異なります。

データベースをアプリケーションとは別の独立した独立した自律型サービスと見なす場合、データベースには、データベースに含まれるデータの一貫性と品質を保証する責任があります。基本的に、そのデータベースは別のアプリケーションで使用できるため、同じ一貫性と品質の動作を持つ2番目のアプリケーションに依存することはできません。このような状況では、APIと自律動作を公開するようにデータベースを設計する必要があります。このビューには少なくとも2つのアプリケーションがあり、1つはデータベースであり、もう1つはそれを使用するアプリケーションです。

逆に、データベースは、アプリケーションの直接かつ完全な制御下にある複雑な形式のファイルと考えることができます。この意味で、データベースは純粋なシリアル化およびドキュメントナビゲーションツールとして機能します。クエリをサポートする高度な動作とドキュメントのメンテナンス(JSONやXMLツールのような)を提供する場合がありますが、(ほとんどのファイルストリームのように)必要はありません。この場合、ファイル内で正しい形式とコンテンツを維持するのはプログラムの責任です。このビューには1つのアプリケーションがあります。

どちらのビューでも、次の質問は、データベースをファンシーファイルとして、または個別のサービスとして使用する方法です。これは次の方法で実現できます。

  • データベースプラットフォームがテーブル/ビュー/ストアドプロシージャ/トリガー/などの形式で提供するツールを使用する...
  • すべてのクライアントがデータベースにアクセスするために使用する必要があるサービス内にデータベース自体をラップする
  • データにアクセスするためにすべてのクライアントが使用する必要があるライブラリにデータベースをラップします。

それぞれに独自の長所/短所があり、システムが動作する環境のアーキテクチャ上の制約に依存します。

どちらのビューを使用するかに関係なく、境界でデータを検証することは常にコストがかかります。

  • ユーザーが入力するUIのフィールドを検証する
  • クライアントを離れる前にネットワーク/ APIリクエストを検証する
  • 何かを行う前に、サーバーでネットワーク/ APIリクエストを検証する
  • ビジネスルールに渡されるデータを検証する
  • 永続化する前にデータを検証する
  • 永続性から取得した後にデータを検証する
  • などなど

各境界でどの程度の検証が保証されるかは、検証を行わないことがどれほど危険かによって異なります。

  • 2つの数値を掛け合わせる?
    • 間違った番号を取得することは問題ですか?
  • 指定されたメモリ位置でプロシージャを呼び出しますか?
    • そのメモリ位置には何がありますか?
    • オブジェクトが存在しない場合、または状態が悪い場合はどうなりますか?
  • 漢字を含む文字列に正規表現を使用していますか?
    • 正規表現モジュールはユニコードを処理できますか?
    • 正規表現はユニコードを処理できますか?

検証ロジックを一元化することは良いことですが、imhoトリガーはそれを実装する良い方法ではありません。以前は、複数のアプリケーションがすべてデータベースを共有し、すべての検証ロジックと副作用がトリガーとストアドプロシージャを介してデータベースに実装されているシステムで作業していました。データベースの前にマイクロサービスを配置し、そこにすべてのロジックを実装する方がよいという印象になりました。SQLデータベース内の重要なロジックはアンチパターンです。
Joeri Sebrechts

1
@JoeriSebrechtsかしこまり ました。データベースの重要なロジックがアンチパターンである理由と、それを個別に保守されているプログラムに置くよりもアンチパターンのようにする理由は何ですか。
Blrfl

@Blrfl 2つの理由、DB内のロジックにアクセスするためのAPIは、WebサービスAPIよりも劣っており(バージョンが難しく、使用が難しく、簡単にキャッシュされないなど)、データベースにより、それらの内部でホストされるコードベース。私の経験では、データベースの内部よりも、データベースの前のWebサービスのロジックをホストする方が簡単です。
Joeri Sebrechts

@JoeriSebrechts私は、ほとんどのデータベースプラットフォームが、信頼でき、有用で、開発可能なAPIを実装するための悲惨なツールを提供していることに同意します。多くの点で、多くの苦痛を感じることは確かに誘いです。私のポイントは、それがパースペクティブについてであり、DBがファンシーなファイルであること、または本当に別のサービスであることを理解することであり、次の質問につながります。私はそれを明確にするために私の答えを詳しく説明します。
Kain0_0

2

いいえ、トリガーを使用して検証を行うことはできません。

データベースは、それ自体の整合性のみを担当します。検証に直面しているユーザーはすべて、アプリケーションで実行する必要があります。

データベースは、整合性のために3つのレベルの検証を実行します。1つ目はフィールドレベルの検証です。値がない場合(null)、フィールドは必須であり、エラーになります。チェック制約にすることもできます。ドメインには列挙された数の値があります。

次に、テーブル間に関係があります。1つのテーブルに1つ以上の外部キーを格納し、このテーブルを他のテーブルに関連付け、値を「他のテーブル」の有効なキーにする必要があります。さまざまな国の住所をサポートする住所データベースを考えてみてください。住所の国キーは、既知の国を指している必要があります。データ(郵便番号など)が有効かどうかは、この整合性チェックの問題ではありません。

第三に、最も複雑なのはトリガーです。一般的なルールとして、これらは対処する必要があります(意図的ではありません)は、条件付きの整合性ルールに関係します。住所の例に戻ると、国に郵便番号がない場合、このリストにある国に郵便番号があると問題になります。したがって、チェックは次のようになります。この国に郵便番号がない場合、郵便番号フィールドはnullである必要があります。

検証はアプリケーションの問題です。ドイツの郵便番号が数字のみで構成されているという事実は、データベースではなく、アプリケーションが行うべきチェックです。行は細いので、トリガー(データベースの整合性を保護する)またはアプリケーション(ユーザーが検証に直面する)に何かが必要な場合は、場合によっては考えたり議論したりする必要があります。


OPがデータベースに存在する必要がある複雑な検証ルールを追加する必要がある場合は、安全な代替手段として常にストアドプロシージャを使用できることを追加したかっただけです。
ボルジャブ

@Borjab:多分、データベースを正しく保つような検証。しかし、ユーザー向けの検証ですか?いいえ
MennoHölscher

1
最初のステートメントは「検証を行うためにトリガーを使用しないでください」と述べていますが、以下では「はい、特定の種類の検証にトリガーを使用できますが、どこに線を引くかは本質的に明確ではありません」と記述します。これはかなり矛盾しています。私はあなたの最初の文を削除することをお勧めします。ああ、「前/後」はトランザクションとは関係がないため、最後の文はOP更新の質問に答えません。それも削除することをお勧めします。(OPの質問の下の私のコメントを参照してください)。
Doc Brown、

@DocBrown違いは、データベースを破損から保護することと、ユーザーが直面する検証との間です。したがって、「これ以上の検証」では、ユーザーが直面する検証について言及します。この区別をより明確にするにはどうすればよいですか?まず、「さらに」を削除しました。
MennoHölscher

2
データベースで検証を行うのはまったく問題ありません。アプリケーションで実行するのと同じように。どちらにも利点があります。アプリケーションで検証を行うと、ほぼすべての複雑なアプリに必要なORMなしでSQLを実行するたびに、細心の注意を払う必要があります。
Qwertie

1

監査は、トリガーを効果的に使用する典型的な例です。トリガーによって実装された監査テーブルのおかげで、テスターに​​よるエラー(クライアントをあるサービスレベルから別のレベルに移動する)によっていくつかのエラーが見つかりました。監査にはトリガーを使用することを強くお勧めします。

検証フロントエンドレベルで実行できますが、私が処理したデータベース(3000で生まれた人など)に奇妙なエラーが表示されました。念のため、データベースでの検証について説明します。もちろん、これらのタイプのエラーはチェック制約で回避でき、多くの場合、より効果的です(MS SQLでは、これらの方法が推奨されます。常にドキュメントを確認してください)。


1

リレーショナルデータベースのトリガーが本当に必要かどうかが問題なので、トリガーを使用する他のいくつかの使用例を次に示します。

  1. 他の回答に記載されている監査用。
  2. 広い意味での監査:データベースエントリが変更された場合、トリガーは非同期ポスト処理のイベントを記録できます(たとえば、別のアプリケーションへの毎晩のエクスポート)。
  3. ビューのトリガー:トリガーを定義できますinstead of。これにより、ビューからエントリを挿入、更新、削除できます。トリガーは、これらのアクションを複数のテーブルに分散できます。これは、基になるテーブルの詳細を公開せずに、制限されたビューを使用可能にする方法です。
  4. データベースの方向転換を明示的に保存するには、テーブルAとBと中間テーブルRの間にN:Mの関係があると想定します。 Bの対応するエントリが削除されます。ただし、ビジネスロジックでは、AのエントリがBのエントリと少なくとも1つの関係を持つ必要がある場合があります。この場合、Rの削除のトリガーは、このロジックの適用に役立ちます。Aのエントリの場合、Rの最後のエントリを削除すると、トリガーはAを削除できます。アプリケーション中心のビューでは、少なくとも2つの方向転換が必要です。これは検証の例です。他の例も考えられます:ユースケース(1)、(2)、
  5. 信頼:データベース管理者は、アプリケーションを使用しないコマンドラインでエントリを変更することがあります。管理者は注意深く作業し、自分が何をしているかを知っています。ただし、時々それらは間違っているかもしれません。一貫性が重要である場合、トリガーはその安全ベルトです。

欠点として、ビジネスロジックがレイヤー間に分散されており、これはメンテナンスにとって大きな欠点です。別の著者が書いたように、それはアプリケーションとデータベースの間の薄い境界であり、選択は必ずしも明確ではありません。私の個人的な見解では、トリガーは開発者に負担をかけます。開発にかかる時間を節約できます。明らかに、遅いネットワーク接続でのパフォーマンスを向上させるため、ユーザーの有効期限が向上します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.