19.5.1.14 Функции репликации и системные функции
Некоторые функции не реплицируются корректно в определенных условиях:
-
Функции
USER(),CURRENT_USER()(илиCURRENT_USER),UUID(),VERSION()иLOAD_FILE()реплицируются без изменений и, следовательно, не работают надёжно на реплике, если не включена репликация на уровне строк. (См. Раздел 19.2.1, «Форматы репликации».)Функции
USER()иCURRENT_USER()автоматически реплицируются с использованием репликации на уровне строк при использовании режимаMIXEDи генерируют предупреждение в режимеSTATEMENT. (См. также Раздел 19.5.1.8, «Репликация CURRENT_USER()».) Это также относится кVERSION()иRAND(). -
Для
NOW(), бинарный журнал включает метку времени. Это означает, что значение возвращаемое вызовом этой функции на источнике реплицируется на реплику. Чтобы избежать неожиданных результатов при репликации между серверами MySQL в разных часовых поясах, установите часовой пояс на источнике и реплике. Для получения дополнительной информации см. Раздел 19.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. По этой причине, если вы выберете данные из копии таблицы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. -
Следующее ограничение относится только к репликации на уровне операторов, а не к репликации на уровне строк. Функции
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)
© 2025 Oracle
Licensed under the GPLv2 License.