バナリログには,デタベスの内容を変更するSQLステトメントに関する情報が含まれます。この情報は,変更にいて記述した「ベント」の形式で格納されます。バ▪▪ナリログには2▪▪の重要な目的があります。
レプリケーションの場合,バイナリログは,スレーブサーバーに送信されるステートメントのレコードとして,マスターレプリケーションサーバー上で使用されます。マスターサーバーは,そのバイナリログに格納されているイベントをそのスレーブに送信し,スレーブはこれらのイベントを実行して,マスター上で実行されたものと同じデータ変更を実行します。セクション17.2“レプリケションの実装”を参照してください。
ある特定のデタリカバリ操作には,バナリログの使用が必要です。バックアップファイルがリストアされたあと,バックアップの作成後に記録されたバイナリログ内のイベントが,再度実行されます。これらの▪▪ベントは,デ▪▪タベ▪スをバックアップのポ▪▪ントから最新の状態に持って行きます。セクション7.3.2“リカバリへのバックアップの使用”を参照してください。
ただし,ロギングがステートメントレベルで行われる場合,ストアドプログラム(ストアドプロシージャーおよびストアドファンクション,トリガー,イベント)に関して該当する,特定のバイナリロギングの問題があります。
場合によっては,ステ,トメントが,マスタ,とスレ,ブで別々の行セットに影響する可能性があります。
スレーブ上で実行された複製ステートメントは,完全な権限を持つスレーブSQLスレッドで処理されます。プロシージャーが,マスターサーバーとスレーブサーバーで別々の実行パスに従うことが可能なので,ユーザーは,スレーブ上でのみ実行し,完全な権限を持つスレーブスレッドで処理される危険なステートメントを含んだルーチンを作成できます。
デ,タを変更するストアドプログラムが非決定的である場合,再現可能ではありません。これにより,マスターとスレーブでデータが異なる結果になったり,リストアしたデータが元のデータと一致しなくなったりする場合があります。
このセクションでは,MySQL 5.6のストアドプログラムのバイナリロギングの処理について説明します。ここでは,実装がストアドプログラムの使用に対して設定している現在の条件と,問題を避けるために実行可能な対処について記しています。また,これらの条件の理由に関する追加情報も示します。
一般に,ここで述べる問題は,SQLステートメントレベルでバイナリロギングが行われるときに生じます。行ベースのバイナリロギングを使用する場合,ログには,SQLステートメントを実行した結果として個々の行に行われた変更が含まれます。ルーチンまたはトリガーが実行されると,行の変更が記録されますが,変更を行なったステートメントは記録されません。ストアドプロシ,ジャ,の場合,これは调用
ステ,トメントが記録されないことを意味します。ストアドファンクションの場合,関数内で行われた行の変更が記録され,関数呼び出しは記録されません。トリガ,の場合,トリガ,によって行われた行の変更が記録されます。スレ,ブ側では,行の変更だけが表示され,ストアドプログラムの呼び出しは表示されません。行ベスのロギングに関する一般情報にいては,セクション17.1.2“レプリケション形式”を参照してください。
特に明記しないかぎり,ここでの説明では,——log-bin
オプションを指定してサーバーを起動することによって,バイナリロギングを有効にしていると想定しています。(セクション5.2.4 "バナリログ"を参照してください)バイナリログが有効でない場合,レプリケーションは可能でなく,バイナリログをデータリカバリに利用することもできません。
MySQL 5.6でストアドファンクションを使用するための現在の条件は,次のように要約できます。これらの条件は,ストアドプロシージャーまたはイベントスケジューラのイベントには適用されず,バイナリロギングが有効でないかぎり適用されません。
ストアドファンクションを生成または変更するには,ユ,ザ,は,通常必要になる
创建程序
権限または改变日常
権限以外に,超级
権限が必要です。(関数定義の定义者
値によっては,バ超级
が必要になる場合があります。セクション13.1.15 "创建过程および创建函数構文"を参照してください。)ストアドファンクションを作成するとき,その関数が決定的であるということ,またはデータを変更しないということを宣言する必要があります。そのようにしないと,デ,タリカバリまたレプリケ,ションにとって安全でなくなる可能性があります。
デフォルトでは,
创建函数
ステ,トメントを受け入れるには,确定的
、没有SQL
,または读取SQL数据
の少なくとも1を明示的に指定する必要があります。そうでない場合はエラ,が発生します。错误1418 (HY000):这个函数在它的声明中没有DETERMINISTIC, NO SQL,或READS SQL DATA,并且启用了二进制日志记录(你*可能*想使用不安全的log_bin_trust_function_creators变量)
次の関数は決定的なため(また,デ,タを変更しません),安全です。
创建函数f1(i INT)返回确定的读取SQL数据开始返回i结束;
次の関数は
UUID ()
を使用しますが,これは決定的でないため,関数も決定的でなく,安全ではありません创建函数f2()返回字符集utf8开始返回UUID();结束;
次の関数はデ,タを変更するので,安全ではない可能性があります。
创建函数f3(p_id INT)返回INT BEGIN UPDATE t SET modtime = NOW() WHERE id = p_id;返回ROW_COUNT ();结束;
関数の性質の評価は,作成者の「誠実さ」に基づいています。MySQLは,
确定的
と宣言された関数に非決定的な結果を生成するステートメントが含まれていないかどうかをチェックしません。确定的
を指定しないで,決定的であるストアドファンクションを作成することは可能ですが,ステートメントベースのバイナリロギングを使用してこの関数を実行できません。このような関数を実行するには,行ベ,スまたは混合バ,ナリロギングを使用する必要があります。または,関数定義で确定的
と明示的に指定すると,ステートメントベースのバイナリロギングを含むあらゆる種類のロギングを使用できます。関数作成に関する前述の条件(
超级
権限を持つ必要があることと,関数が決定的であるか,データを変更しないと宣言する必要があること)を緩和するには,log_bin_trust_function_creators
グロバルシステム変数を1に設定します。デフォルトでこの変数には0の値が設定されていますが,次のように変更できます。mysql> SET GLOBAL log_bin_trust_function_creators = 1;
サ,バ,の起動時に
——log-bin-trust-function-creators = 1
オプションを使用することによって,この変数を設定することもできます。バ电子邮箱ナリロギングが有効でない場合,
log_bin_trust_function_creators
は適用されません。前述のように,関数定義の定义者
値が必要としないかぎり,関数の作成に超级
は必要ありません。レプリケーションで安全ではない可能性のある(そのため,これらを使用するストアドファンクションも安全でなくなります)組み込み関数の詳細は,セクション17.4.1“レプリケ,ションの機能と問題”を参照してください。
トリガーは,ストアドファンクションと似ているので,関数に関する前述の説明がトリガーにも当てはまりますが,创建触发器
にはオプションの确定的
特性がないため,トリガ,は常に決定的であると想定されるという点が異なります。ただし,この想定は一部の場合で無効になることがあります。たとえば,UUID ()
関数は非決定的です(また,複製しません)。トリガ,でのこのような関数の使用には注意する必要があります。
トリガ,はテ,ブルを更新できるので,必要な権限がない場合には,创建触发器
で,ストアドファンクションの場合と同様のエラ,メッセ,ジが表示されます。スレ,ブ側では,スレ,ブは定义者
トリガ,属性を使用して,トリガ,の作成者であると思われるユ,ザ,を特定します。
このセクションの残りの部分では,ロギングの実装とその意味に関する追加詳細にいて説明します。ストアドルーチンの使用に関する現在のロギング関連の条件の理論的根拠についての背景に関心がある場合には,こちらをお読みください。この説明はステ,トメントベ,スのロギングにのみ該当し,行ベ,スのロギングには該当しませんが,创建
および下降
ステートメントは,ロギングモードとは無関係にステートメントとして記録されるという最初の項目は除きます。
サ,バ,は,
创建事件
、创建过程
、创建函数
、改变事件
、改变的过程
、改变函数
、删除事件
、下降过程
,および删除函数
ステトメントをバナリログに書き込みます。ストアドファンクションの呼び出しは,この関数がデータを変更し,それ以外では記録されないようなステートメント内で行われた場合に,
选择
ステ,トメントとして記録されます。これにより,記録されないステートメントでストアドファンクションを使用した結果生じたデータの変更をレプリケーションできなくなるという事態が防止されます。たとえば,选择
ステトメントはバナリログに書き込まれませんが,选择
は,変更を行うストアドファンクションを呼び出す場合があります。これを扱うため,选择
ステトメントは,指定した関数が変更を行うときにバナリログに書き込まれます。次のステ,トメントがマスタ,で実行されるとします。func_name
()创建函数f1(a INT)返回INT BEGIN IF (a < 3) THEN INSERT INTO t2 VALUES (a)如果;返回0;结束;创建表t1 (INT);插入t1 VALUES (1),(2),(3);SELECT f1(a) FROM t1;
选择
ステ,トメントが実行されると,関数f1 ()
は3回呼び出されます。このう2回の呼び出しで行を挿入し,MySQLは各行に対し选择
ステ,トメントを記録します。。选择f1 (1);选择f1 (2);
サーバーは,エラーを発生させるストアドプロシージャーをストアドファンクションが呼び出すときに,そのストアドファンクションの呼び出しに対する
选择
ステ,トメントも記録します。この場合,サ,バ,は,予想されるエラ,コ,ドとともに,选择
ステ,トメントをログに書き込みます。スレ,ブ上で,同じエラ,が起きた場合,これは予想される結果でありレプリケ,ションは継続します。それ以外の場合は,レプリケ,ションは停止します。関数によって実行されるステートメントではなく,ストアドファンクションの呼び出しのロギングは,レプリケーションでは,次の2つの要因から生じるセキュリティー上の意味があります。
関数が,マスタサバとスレブサバで別々の実行パスに従うことが可能です。
スレブ上で実行されたステトメントは,完全な権限を持スレブSQLスレッドで処理されます。
つまり,ユーザーは関数を作成するために
创建程序
権限を持つ必要がありますが,完全な権限を持つスレッドで処理されるスレーブ上でのみ実行する危険なステートメントを含んだ関数を作成できます。たとえば,マスターサーバーとスレーブサーバーのサーバー ID 値がそれぞれ 1 と 2 の場合、マスターサーバー上のユーザーは、安全ではない関数unsafe_func ()
を次のように作成し呼び出すことができます。mysql> delimiter // mysql> CREATE FUNCTION unsafe_func () RETURNS INT -> BEGIN -> IF @@server_id=2 THENdangerous_statement;如果;->返回1;- >结束;-> // mysql>分隔符;INSERT INTO t VALUES(unsafe_func());
创建函数
ステ,トメントおよび插入
ステトメントはバナリログに書き込まれるので,スレブサバはそれらを実行します。スレ,ブSQLスレッドには完全な権限があるので,危険なステ,トメントを実行します。したがって,関数の呼び出しがマスターとスレーブに与える効果は異なり,レプリケーションは安全ではなくなります。バイナリロギングを有効にしているサーバーに対するこの危険から保護するために,ストアドファンクションの作成者は,必要な通常の
创建程序
権限に加え,超级
権限も持必要があります。同様に,改变函数
を使用するには,ユ,ザ,は改变日常
権限に加え,超级
権限を持必要があります。超级
権限がないと,エラ,が発生します。错误1419 (HY000):您没有SUPER权限并且启用了二进制日志记录(您*可能*想使用不太安全的log_bin_trust_function_creators变量)
関数作成者が
超级
権限を持よう要求しない場合(たとえば,システム上の创建程序
権限を持すべてのユザが経験豊かなアプリケション開発者である場合),log_bin_trust_function_creators
グロバルシステム変数を1に設定します。サ,バ,の起動時に——log-bin-trust-function-creators = 1
オプションを使用することによって,この変数を設定することもできます。バ电子邮箱ナリロギングが有効でない場合,log_bin_trust_function_creators
は適用されません。前述のように,関数定義の定义者
値が必要としないかぎり,関数の作成に超级
は必要ありません。更新を実行する関数が非決定的である場合,再現可能ではありません。これは次の2の望ましくない影響を及ぼす可能性があります。
スレ,ブがマスタ,と一致しなくなります。
リストアされたデ,タが元のデ,タと異なります。
これらの問題に対処するために,MySQLでは,関数を決定的であるか,データを変更しないと宣言しないかぎり,マスターサーバーでは関数の作成と変更は拒否されるという要件を強制しています。ここでは次の2の関数特性セットが適用されます。
确定的
特性と不确定性
特性は,関数が一定の入力に対して常に同じ結果を生成するかどうかを示します。どらの特性も指定されていない場合は,デフォルトは不确定性
です。関数が決定的であることを宣言するには,明示的に确定的
を指定する必要があります。包含SQL
、没有SQL
、读取SQL数据
,および修改SQL数据
特性は,関数がデ,タを読み取るか書き込むかに関する情報を示します。没有SQL
または读取SQL数据
は,関数がデ,タを変更しないことを示しますが,特性が指定されていない場合にデフォルトは包含SQL
になるので,これらのどらかを明示的に指定する必要があります。
デフォルトでは,
创建函数
ステ,トメントを受け入れるには,确定的
、没有SQL
,または读取SQL数据
の少なくとも1を明示的に指定する必要があります。そうでない場合はエラ,が発生します。错误1418 (HY000):这个函数在它的声明中没有DETERMINISTIC, NO SQL,或READS SQL DATA,并且启用了二进制日志记录(你*可能*想使用不安全的log_bin_trust_function_creators变量)
log_bin_trust_function_creators
を1に設定した場合,関数が決定的であるか,デ,タを変更しないという要件は破棄されます。ストアドプロシ,ジャ,の呼び出しは
调用
レベルでなく,ステ,トメントレベルで記録されます。,调用
ステ,トメントを記録せず,実際に実行するプロシ,ジャ,内のステ,トメントを記録します。その結果,マスタ,で行われた同じ変更が,スレ,ブサ,バ,で確認されます。これにより,別々のマシン上で異なる実行パスを持プロシジャから生じる問題が防止されます。一般に,ストアドプロシージャー内で実行されるステートメントは,スタンドアロンでステートメントを実行した場合に適用されるものと同じルールを使用して,バイナリログに書き込まれます。プロシージャー内でのステートメントの実行は,非プロシージャーのコンテキストとまったく同じにはならないので,プロシージャーステートメントのロギング時には,十分に注意してください。
記録されるステ,トメントには,ロ,カルプロシ,ジャ,変数への参照が含まれる場合があります。これらの変数は,ストアドプロシージャーのコンテキスト外に存在しないので,このような変数を参照するステートメントは,文字どおりには記録できません。代わりに,ロ,カル変数のそれぞれの参照は,ロギングのために次の構造構文に置き換えられます。
NAME_CONST (var_name,var_value)
var_name
はロ,カル変数名であり,var_value
は,ステ,トメントの記録時に変数に含まれていた値を示す定数です。NAME_CONST ()
にはvar_value
の値とvar_name
の「名前」が含まれます。したがって,この関数を直接呼び出した場合,次のような結果が得られます。mysql> SELECT name ('myname', 14);+--------+ | 的名字 | +--------+ | 14 | +--------+
NAME_CONST ()
は,マスター上でストアドプロシージャー内で実行された元のステートメントと同じ効果で,記録されたスタンドアロンのステートメントを,スレーブ上でも実行できるようにします。NAME_CONST ()
を使用した結果,ソ,スカラム式がロ,カル変数を参照するときに,创建表…选择
ステ,トメントの問題が生じる場合があります。これらの参照をNAME_CONST ()
式に変換した結果,マスターサーバーとスレーブサーバーでカラム名が異なったり,正当なカラム識別子としては長すぎる名前になったりすることがあります。回避策では,ロ,カル変数を参照するカラムのエ,リアスを指定します。myvar#
の値が1の場合は次のステ,トメントを検討してください。CREATE TABLE t1 SELECT myvar
これは次のように書き換えられます。
SELECT NAME_CONST(myvar, 1);
マスターテーブルとスレーブテーブルに同じカラム名があることを確認するには,次のようなステートメントを作成します。
SELECT myvar作为myvar
書き換えられたステ,トメントは次のようになります。
SELECT NAME_CONST(myvar, 1) AS myvar;
記録されるステ,トメントには,ユ,ザ,定義変数への参照が含まれる場合があります。これを処理するために,MySQLは,
集
ステートメントをバイナリログに書き込んで,マスター上にあるものと同じ値の変数がスレーブ上にもあることを確認します。たとえば,ステ,トメントが変数@my_var
を参照する場合、そのステ、トメントはバ、ナリログ内で次のステ、トメントに優先されます。ここで,价值
マスタ,上の@my_var
の値です。SET @my_var =价值;
プロシ,ジャ,の呼び出しは,コミットまたはロ,ルバックしたトランザクション内で行えます。プロシージャー実行のトランザクションの側面が正しく複製されるように,トランザクションのコンテキストが説明されます。,,,,,
开始
、提交
,および回滚
ステ,トメントも必要に応じて記録します。たとえば,プロシージャーがトランザクションテーブルだけを更新し、ロールバックされるトランザクション内で実行される場合、これらの更新は記録されません。プロシージャーがコミットされたトランザクション内で行われた場合、开始
および提交
ステ,トメントが更新とともに記録されます。ロールバックしたトランザクション内で実行するプロシージャーの場合,そのステートメントは,ステートメントがスタンドアロンで実行された場合に適用されるものと同じルールを使用して記録されます。トランザクションテ,ブルに対する更新は記録されません。
非トランザクションテ,ブルに対する更新は,ロ,ルバックで取り消されないので,記録されます。
トランザクションテーブルと非トランザクションテーブルの混在に対する更新は,スレーブがマスターと同じ変更およびロールバックを行うように,
开始
と回滚
で囲まれて記録されます。
ストアドプロシージャーの呼び出しは,ストアドファンクション内から呼び出される場合,ステートメントレベルのバイナリログに書き込まれません。この場合,記録される唯一の対象は,関数を呼び出すステートメント(記録されたステートメント内で行われた場合)または
做
ステ,トメント(記録されないステ,トメント内で行われた場合)です。このため,それ以外の場合にプロシージャー自体が安全であっても,プロシージャーを呼び出すストアドファンクションを使用するときには注意を払う必要があります。