web-dev-qa-db-ja.com

mysqlの確定関数

一見シンプルなコンセプトに戸惑いました。 Mysqlは決定論的関数を

同じ入力パラメーターに対して常に同じ結果を生成します

だから私の理解では、のような機能

CREATE FUNCTION foo (val INT) READS SQL DATA
BEGIN
   DECLARE retval INT;
   SET retval = (SELECT COUNT(*) FROM table_1 WHERE field_1 = val);
   RETURN retval;
END;

確定的ではありません(関数の2つの呼び出しの間に削除/更新/挿入が発生しないという保証はありません)。同時に、クエリの結果に基づいて戻り値がほぼ同じで、DETERMINISTICとして宣言されている多くの関数を確認しました。基本的なものが欠けているようです。

誰かがこの問題を明確にできますか?

ありがとう。

更新答えてくれてありがとう(+1);これまでのところ、DETERMINISTICキーワードの誤用が広まっているようです。多くの人がそうしていると私が信じるのはまだ難しいので、他の答えを少し待ちます。

32
a1ex07

MySQL 5.0リファレンスから:

ルーチンの性質の評価は、作成者の「誠実さ」に基づいています。MySQLは、DETERMINISTICと宣言されたルーチンに非決定的な結果を生成するステートメントがないことを確認しません。ただし、ルーチンを誤って宣言すると、結果やパフォーマンスに影響を与える可能性があります。非決定的ルーチンをDETERMINISTICとして宣言すると、オプティマイザが誤った実行プランを選択するため、予期しない結果が生じる可能性があります。確定的ルーチンをNONDETERMINISTICとして宣言すると、使用可能な最適化が使用されなくなり、パフォーマンスが低下する可能性があります。 MySQL 5.0.44より前では、DETERMINISTIC特性は受け入れられていますが、オプティマイザでは使用されていません。

したがって、それができたら、ストアドルーチンにDETERMINISTICのタグを付けなくてもタグ付けできますが、予期しない結果やパフォーマンスの問題が発生する可能性があります。

15
Xint0

DETERMINISTIC結果は、異なる時間に返される異なる結果セットを参照しません(その間に追加されたデータによって異なります)。さらに、同じデータを使用する異なるマシンの結果セットへの参照です。たとえば、uuid()を含む関数を実行するか、サーバー変数を参照する2台のマシンがある場合、これらは確定的ではないと見なされます。関数呼び出しはバイナリログ(マスター)に保存され、スレーブによっても実行されるため、これはレプリケーションなどで役立ちます。詳細と例については、 http://dev.mysql.com/doc/refman/5.0/en/stored-programs-logging.html を参照してください

したがって、DETERMINISTICの使用は正しい(99%の場合)であり、誤用とは見なされません。

12
Jon Gilbert

あなたのルーティンは決定論的だと思います。ドキュメントはあまり明確ではないため、多くの人がこの問題について非常に混乱しています。この問題は、実際には何よりもレプリケーションに関するものです。

2つのデータベース間でレプリケーションを設定している状況を考えてみましょう。マスターデータベースは、入力パラメーターを含め、実行されたすべてのストアドルーチンのログを保持し、このログをスレーブに送信します。スレーブは、同じ入力パラメーターで同じ順序で同じストアドルーチンを実行します。スレーブデータベースにマスターデータベースと同一のデータが含まれるようになりますか?ストアドルーチンがGUIDを作成してデータベースに保存する場合は、いいえ、マスターデータベースとスレーブデータベースが異なり、レプリケーションが壊れます。

DETERMINISTICフラグの主な目的は、このストアドルーチンへの呼び出しをレプリケーションログに含めると、マスターデータベースとレプリケートされたスレーブの間に違いが生じるため、安全ではないかどうかをMySQLに伝えることです。

DETERMINISTICフラグがストアドルーチンに適切かどうかを判断するときは、次のように考えてください。2つの同一のデータベースで開始し、両方のデータベースで同じ入力パラメーターを使用してルーチンを実行した場合、データベースは同じですか?もしそうなら、私のルーチンは決定論的です。

ルーチンが確定的でない場合に確定的であると宣言した場合、MySQLはプロシージャログをレプリケーションログに追加するだけであり、スレーブでプロシージャを実行しても同じ結果が生成されないため、メインデータベースのレプリカは元のデータベースと同一ではない可能性があります。 。

ルーチンが非決定的である場合、MySQLは影響を受ける行をレプリケーションログに含める必要があります。ルーチンが非決定論的であると宣言した場合、これは何も壊しませんが、レプリケーションログには、プロシージャコールだけで十分な場合に影響を受けるすべての行が含まれ、パフォーマンスに影響を与える可能性があります。

8
bikeman868

何も不足していません。この関数は非決定的です。確定的であると宣言してもデータベースは溶けませんが、パフォーマンスに影響する可能性があります。 MySQLサイトから :「非決定的ルーチンをDETERMINISTICとして宣言すると、オプティマイザが誤った実行プランを選択するため、予期しない結果が生じる可能性があります。」しかし、MySQLは宣言された決定論的ルーチンが実際に決定論的であるかどうかを強制または確認しません--- MySQLは、あなたが何をしているのかを知っていると信頼しています。

2
John Watson

レプリケーションをオンにしている場合、または1日使用する可能性がある場合は、確定性が重要です。たとえば、行の変更(更新または挿入)を引き起こす非決定的関数呼び出しは、バイナリ(行ベース)を使用して複製する必要があります。ここで、決定的関数はステートメントベースで複製できます。これは、上記のSQLの例を見ると興味深いものです。ステートメントベースを使用してレプリケートすると同じ結果が得られ(同じ結果が得られます)、マスターで取得した結果を使用してレプリケートする必要があります(行ベース)。ステートメントが適切なロックで実行され、スレーブで同じ順序で実行されることが保証される場合、それらは実際に確定的です。スレーブが使用するロック/ステートメントの順序(同時実行なし、ステートメントの開始順にシリアル処理)が答えを変える可能性がある場合、関数は非決定的である必要があります。

0
dooku