MySQL 8.0 リファレンスマニュアル


17.5.1.14 レプリケーションとシステム関数

一部の関数は条件によっては適切に複製されません。

  • USER()CURRENT_USER() (または CURRENT_USER)、UUID()VERSION() および LOAD_FILE() 関数は変更なしでレプリケートされるため、行ベースのレプリケーションが有効になっていないかぎり、レプリカで確実に動作しません。 (セクション17.2.1「レプリケーション形式」を参照してください。)

    USER() および CURRENT_USER() は、MIXED モード使用時に行ベースレプリケーションを使用して自動的に複製され、STATEMENT モードでは警告を生成します。 (セクション17.5.1.8「CURRENT_USER() のレプリケーション」も参照してください。) これは、VERSION() および RAND() にも当てはまります。

  • NOW() の場合、バイナリログはタイムスタンプを含みます。 これは、値ソースでこの関数を呼び出したときに返されますがレプリカにレプリケートされることを意味します。 異なるタイムゾーンの MySQL サーバー間でレプリケートするときに予期しない結果が発生しないようにするには、ソースとレプリカの両方でタイムゾーンを設定します。 詳細は、セクション17.5.1.33「レプリケーションとタイムゾーン」を参照してください。

    異なるタイムゾーンのサーバー間でレプリケートする際の潜在的な問題を説明するために、ソースがニューヨークにあり、レプリカがストックホルムにあり、両方のサーバーがローカル時間を使用しているとします。 さらに、次に示すように、ソースでテーブル mytable を作成し、このテーブルに対して INSERT ステートメントを実行し、テーブルから選択するとします:

    mysql> CREATE TABLE mytable (mycol TEXT);
    Query OK, 0 rows affected (0.06 sec)
    
    mysql> INSERT INTO mytable VALUES ( NOW() );
    Query OK, 1 row affected (0.00 sec)
    
    mysql> SELECT * FROM mytable;
    +---------------------+
    | mycol               |
    +---------------------+
    | 2009-09-01 12:00:00 |
    +---------------------+
    1 row in set (0.00 sec)

    ストックホルムの現地時間はニューヨークより 6 時間遅れているため、その瞬間にレプリカで SELECT NOW() を発行すると、値 2009-09-01 18:00:00 が返されます。 このため、表示された CREATE TABLE および INSERT ステートメントがレプリケートされた後に、mytable のレプリカコピーから選択した場合、mycol2009-09-01 18:00:00 という値が含まれている可能性があります。 ただし、これは当てはまりません。mytable のレプリカコピーから選択すると、ソースとまったく同じ結果が得られます:

    mysql> SELECT * FROM mytable;
    +---------------------+
    | mycol               |
    +---------------------+
    | 2009-09-01 12:00:00 |
    +---------------------+
    1 row in set (0.00 sec)

    SYSDATE() 関数は、NOW() とは異なり、レプリケーションに安全ではありません。バイナリログ内で SET TIMESTAMP ステートメントに影響されず、ステートメントベースロギングが使用される場合は非決定的であるためです。 行ベースロギングを使用する場合は、これは問題ではありません。

    ほかの方法は --sysdate-is-now オプションを使用することで、SYSDATE()NOW() のエイリアスになります。 これは、ソースおよびレプリカで正しく機能するために必要です。 このような場合でも、この関数によって警告が発行されますが、--sysdate-is-now がソースとレプリカの両方で使用されているかぎり、無視しても問題ありません。

    SYSDATE() は、MIXED モードの使用時に行ベースのレプリケーションを使用して自動的にレプリケートされ、STATEMENT モードで警告を生成します。

    セクション17.5.1.33「レプリケーションとタイムゾーン」も参照してください。

  • 次の制限は、ステートメントベースレプリケーションにのみ適用され、行ベースレプリケーションには適用されません。 ユーザーレベルのロックを処理する GET_LOCK(), RELEASE_LOCK(), IS_FREE_LOCK() および IS_USED_LOCK() 関数は、ソース上の同時実行性コンテキストを認識していないレプリカでレプリケートされます。 したがって、レプリカ上のコンテンツが異なるため、これらの関数を使用してソーステーブルに挿入しないでください。 たとえば、INSERT INTO mytable VALUES(GET_LOCK(...)) などのステートメントを発行しないでください。

    これらの関数は、MIXED モード使用時に行ベースレプリケーションを使用して自動的に複製され、STATEMENT モードで警告を生成します。

ステートメントベースレプリケーションが有効のときに前述の制限に対する回避策として、問題のある関数結果をユーザー変数に保存して、後続のステートメントでその変数を参照する方法を使用できます。 たとえば、次の単一行 INSERT は、UUID() 関数を参照するため問題があります。

INSERT INTO t VALUES(UUID());

この問題を回避するには、代わりにこれを実行してください。

SET @my_uuid = UUID();
INSERT INTO t VALUES(@my_uuid);

このステートメントの連続は複製されます。@my_uuid の値が INSERT ステートメントの前にユーザー変数イベントとしてバイナリログに格納されて INSERT で使用できるためです。

同じ概念が複数行挿入に適用されますが、使用するのが面倒です。 2 行挿入の場合、このようにできます。

SET @my_uuid1 = UUID(); @my_uuid2 = UUID();
INSERT INTO t VALUES(@my_uuid1),(@my_uuid2);

ただし、行数が多いか不明の場合、この回避策は困難であるか実用的でありません。 たとえば、次のステートメントを個々のユーザー変数が各行に関連付けられているものに変換することはできません。

INSERT INTO t2 SELECT UUID(), * FROM t1;

ストアドファンクション内で、RAND() は、関数の実行中に 1 回だけ呼び出されるかぎり、正しく複製されます。 (関数実行タイムスタンプおよび乱数シードは、ソースとレプリカで同一の暗黙的な入力とみなすことができます。)

FOUND_ROWS()ROW_COUNT() 関数がステートメントベースレプリケーションを使用して複製されるときは、信頼性がありません。 回避策は、関数呼び出しの結果をユーザー変数に格納してから、INSERT ステートメントでこれを使用することです。 たとえば、mytable という名前のテーブルに結果を格納する場合は、普通は次のように実行するかもしれません。

SELECT SQL_CALC_FOUND_ROWS FROM mytable LIMIT 1;
INSERT INTO mytable VALUES( FOUND_ROWS() );

しかし、mytable を複製する場合は、次のように SELECT ... INTO を使用してから変数をテーブルに格納することをお勧めします。

SELECT SQL_CALC_FOUND_ROWS INTO @found_rows FROM mytable LIMIT 1;
INSERT INTO mytable VALUES(@found_rows);

このように、ユーザー変数はコンテキストの一部としてレプリケートされ、レプリカに正しく適用されます。

これらの関数は、MIXED モード使用時に行ベースレプリケーションを使用して自動的に複製され、STATEMENT モードで警告を生成します。 (Bug #12092、Bug #30244)


関連キーワード:  ソース, 関数, ベース, ステートメント, 変数, mytable, INSERT, バイナリ, テーブル, モード