web-dev-qa-db-ja.com

多くのトリガーを使用するのは正常ですか?

他のテーブルの行数をカウントするために、データベース全体に多くのいわゆるサマリー列があります。たとえば、ユーザーによるコメント数のカウント(ユーザーテーブルの列)。現在、私はこの列を追加のクエリで更新します。

UPDATE user_table SET comments = comments + 1 WHERE user_id='x'

次に、2番目のクエリを実行する代わりに、データベースにTriggersを導入します。各列に2つのTriggers:1つのDELETEと1つのINSERT。次に、30〜40にしますTriggers !!!

ベンチマークは、Triggersを使用すると、2番目のクエリを実行するよりも約50%高速であることを示しています。どうやら、mysqlの最新機能を使用するのが妥当です。しかし、私がこの質問をするのは、コーディングが曖昧になるため、多くのプログラマーがTriggersに強く反対しているためです。さらに、Triggersをたくさん追加すると、Information_Schema乱雑。

私は正しい軌道に乗っていますか?

3
Googlebot

トリガーに関する主な問題は次のとおりです。

a)デバッグが難しい

b)トリガーカスケードはデータベースに致命的な影響を与える可能性があります。たとえば、あるテーブルに更新後トリガーがあり、別のテーブルを更新する場合、更新後トリガーもあると、多くの問題が発生します。

いくつかの質問:

a)アプリケーション内で「計算された」要約が使用される頻度はどれくらいですか?

b)「計算された」要約を更新する必要がある頻度はどれくらいですか?

c)必要な主要な「計算」で定期的に更新される「レポート」テーブルを作成することを検討しますか?

あなたが持っているようなサマリーフィールドにはいくつかのオプションがあります。

  • 必要に応じて計算します。これは、使用法によって値を非正規化する必要があることが示されるまでの好ましい開始点です。
  • トリガーを使用して、正規化されていない値を適切なテーブルに保持します。これは、値を維持するオーバーヘッドと、必要に応じて値を取得するコストとのトレードオフです。
  • バッチプロセスを使用して、正規化されていない値を定期的に更新します(システム負荷が低い場合)。これにより、ピーク時のリソース使用量と精度がトレードオフになります。

値を維持するための2回目の更新のオプションは含まれていません。これは、場合によっては見逃されがちで、データが永続的に不正確になる可能性があるためです。これに対する解決策は、不正確な部分を検出して修正するためのバッチ監査/更新です。これは、トリガーを使用するときの初期値設定に必要であり、トリガーがいつでも無効になる場合に備えて、保持しておく必要があります。

すでに述べたように、非正規化された値にトリガーを設定することは望ましくありません。これらは私がトリガーを使用する場合です:

  • 監査フィールドまたはテーブルを維持します。 (日付とユーザーを作成/更新します。監査テーブルの変更前イメージのスナップショット。)
  • クロスフィールドテーブルの検証を実行します。
  • 状態フィールドの状態変換を検証します。
  • 非正規化フィールドを維持します。 (検証後に追加され、パフォーマンスが向上します。最も一般的には、値が取得されるよりもはるかに少ない頻度で変更されます。
2
BillThor

多くの人がトリガーの使用に反対している理由は、2番目のクエリの必要性によってもたらされる制御の欠如と実際に関係しています。

情報を記録するために必要な2番目のクエリは、ストレージエンジン固有の側面を制御する機能がないMySQL環境の影響を受けます。

たとえば、 記録されたテーブルのストレージエンジンに根本的な原因が単純に煮詰められたMySQLイベントのトラブルシューティングを支援しようとしたことがあります 。その問題に関する経験的分析から、トリガー内からInnoDBテーブルに監査証跡情報を記録することを誓約しました。

Triggersの良い点、悪い点、醜い点について以前に投稿しました。

多くのトリガーが必要な場合は、 BLACKHOLEストレージエンジン とMySQLの組み合わせを使用することを強くお勧めしますレプリケーション。

ユーザーのコメントを記録するデータベースがあるとします。ユーザーのユーザーIDとコメント列を含むaudit_userというテーブルがあります。

_CREATE DATABASE auditinfo;
USE auditinfo
CREATE TABLE audit_user
(
    userid INT NOT NULL,
    comments INT NOT NULL DEFAULT 1,
    PRIMARY KEY (userid)
) ENGINE=BLACKHOLE;
_

次に、このクエリを実行するトリガーを設定します

_INSERT INTO auditinfo.audit_user (userid) VALUES (myuserid)
ON DUPLICATE KEY UPDATE comments = comments + 1;
_

すばらしいですが、テーブルに何も格納されていないのに、audit_userテーブルがBLACKHOLEストレージエンジンを使用するのはなぜですか?ここでMySQLレプリケーションが機能します。

すべての自動証跡データをキャッチすることを唯一の目的とするスレーブをセットアップします。 _replicate-do-db=auditinfo_オプションを使用してスレーブをマスターから複製します。次のように、スレーブにauditinfoデータベースとaudit_userテーブルを作成します。

_CREATE DATABASE auditinfo;
USE auditinfo
CREATE TABLE audit_user
(
    userid INT NOT NULL,
    comments INT NOT NULL DEFAULT 1,
    PRIMARY KEY (userid)
) ENGINE=MyISAM;
_

マスターのバイナリログには、コマンドINSERT INTO auditinfo.audit_user (userid) VALUES (myuserid) ON DUPLICATE KEY UPDATE comments = comments + 1;が記録されています。そのINSERTはスレーブのリレーログに送信されます。レプリケーションにより、INSERtクエリが実行されます。

したがって、問題は残ります。これを設定する利点は何ですか?

厳密に監査情報を記録することになると、マスターはそれを遅くするための重い書き込みI/Oを持ちません。監査を実行するために必要なSQLを記録するだけです。そのSQLは、実際の記録のために別のマシン(スレーブ)に送信されます。当然、この方法で監査を設定すると、マスターはより多くのトリガーを処理できます。 BLACHOLE/MySQLレプリケーションのこの組み合わせを使用しない場合、INSERTを実行するすべてのクエリは速度が低下し、数百のそのようなクエリが表示されるため、DBのパフォーマンスが著しく低下します。

2
RolandoMySQLDBA