Spec-Zone.ru › MySQL 5.7

16.4.1.15 Функции репликации и системные функции

Некоторые функции не реплицируются корректно в определенных условиях:

  • Функции USER(), CURRENT_USER() (или CURRENT_USER), UUID(), VERSION() и LOAD_FILE() реплицируются без изменений и, следовательно, не работают надёжно на реплике, если не включена репликация на основе строк. (См. Раздел 16.2.1, «Форматы репликации».)

    USER() и CURRENT_USER() автоматически реплицируются с помощью репликации на основе строк при использовании режима MIXED и генерируют предупреждение в режиме STATEMENT. (См. также Раздел 16.4.1.8, «Репликация CURRENT_USER()».) Это также верно для VERSION() и RAND().

  • Для NOW() бинарный лог включает метку времени. Это означает, что значение возвращаемое вызовом этой функции на источнике реплицируется на реплику. Чтобы избежать неожиданных результатов при репликации между серверами MySQL в разных часовых поясах, настройте часовой пояс на обоих источнике и реплике. Дополнительную информацию см. в Разделе 16.4.1.31, «Репликация и часовые пояса».

    Чтобы пояснить возможные проблемы при репликации между серверами, находящимися в разных часовых поясах, предположим, что источник расположен в Нью-Йорке, реплика — в Стокгольме, и оба сервера используют местное время. Дополнительно предположим, что на источнике вы создаёте таблицу 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. По этой причине, если вы выберите данные из копии таблицы mytable на реплике после того, как CREATE TABLE и INSERT были реплицированы, вы, возможно, ожидаете, что mycol будет содержать значение 2009-09-01 18:00:00. Однако это не так; при выборе данных из копии таблицы mytable на реплике вы получите точно такой же результат, как на источнике:

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

    В отличие от NOW(), функция SYSDATE() не является безопасной для репликации, так как она не зависит от операторов SET TIMESTAMP в бинарном логе и является недетерминированной, если используется журнализация на основе операторов. Это не проблема, если используется журнализация на основе строк.

    Альтернативой является использование параметра --sysdate-is-now, чтобы функция SYSDATE() стала алиасом для NOW(). Это должно быть сделано на источнике и на реплике, чтобы это работало правильно. В таких случаях функция все равно выдает предупреждение, но его можно безопасно игнорировать, если параметр --sysdate-is-now используется как на источнике, так и на реплике.

    SYSDATE() автоматически реплицируется с помощью репликации на основе строк при использовании режима MIXED и генерирует предупреждение в режиме STATEMENT.

    См. также Раздел 16.4.1.31, «Репликация и часовые пояса».

  • Следующее ограничение относится только к репликации на основе операторов, а не к репликации на основе строк. Функции 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.

Та же идея применима и к операторам вставки нескольких строк, но её использование более сложное. Для вставки двух строк можно сделать так:

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

Однако, если число строк велико или неизвестно, обходное решение затруднительно или непрактично. Например, нельзя преобразовать следующий оператор в оператор, в котором каждой строке сопоставляется отдельная переменная пользователя:

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

Внутри хранимой функции RAND() реплицируется корректно, если она вызывается только один раз во время выполнения функции. (Вы можете рассматривать временную метку выполнения функции и семена генерации случайных чисел как неявные входные данные, которые идентичны на источнике и реплике.)

Функции 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. (Ошибка #12092, ошибка #30244)

До версии MySQL 5.7.3 значение функции LAST_INSERT_ID() не реплицировалось корректно, если на реплике были включены фильтры, такие как --replicate-ignore-db и --replicate-do-table. (Ошибка #17234370, ОШИБКА # 69861)

© 2025 Oracle
Licensed under the GPLv2 License.
https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/replication-features-functions.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API