2015-11-11 2 views
1

Я создаю веб-сервис под управлением MySQL, который кэширует и индексирует данные из внешнего источника через равные промежутки времени (скажем, два раза в день). Процедура обновления - единственное, что изменяет кэшированные данные; для остальной части службы эти данные доступны только для чтения. Кроме того, данные извлекаются через несколько HTTP-запросов внешнему источнику. Количество запросов пропорционально количеству извлеченных данных. Предположим, что при объединении данные не вписываются в память. Я стремлюсь к следующему:Большие обновления фона с MySQL

  1. Для того чтобы обновление было атомарным с точки зрения остальной части службы. Служба не должна обслуживать частично обновленные данные.
  2. Для массового ввода новых данных достаточно быстро. Обновления и вставки не должны использовать отдельные транзакции, но работать в одной транзакции. В конце должна быть одна фиксация.
  3. Чтобы эти обновления прерывали остальную часть службы как можно меньше. Массовое обновление не должно блокировать другие сеансы от доступа к старым данным во время обновления.

Я пользуюсь InnoDB.

Предположим, у меня есть база данных с именем webservice, которая содержит таблицу с именем data. Очевидным первая попытка обновить данные будут следующие:

START TRANSACTION; 
INSERT INTO `data`(`row1`, `row2`, `row3`) VALUES ('val1', 'val2', 'val3'); 
INSERT INTO `data`(`row1`, `row2`, `row3`) VALUES ('val4', 'val5', 'val6'); 
UPDATE `data` SET `row2` = 'val7' WHERE `id` = 3; 
/* And so on for a very large number of INSERTs and UPDATEs. */ 
COMMIT; 

Насколько я знаю, это удовлетворяет 1 и 2, но нарушает 3.

Я имею в виду другое решение, которое, как представляется, удовлетворяет 1, 2 и 3. Это использует таблицы «temp» в другой базе данных, где будут вставлены новые данные, а затем заменяется на таблицы.

START TRANSACTION; 
DROP TABLE IF EXISTS `webservice_temp`.`data`; 
CREATE TABLE `webservice_temp`.`data` LIKE `webservice`.`data`; 
INSERT INTO `webservice_temp`.`data` 
    SELECT * from `webservice`.`data`; 
INSERT INTO `data`(`row1`, `row2`, `row3`) VALUES ('val1', 'val2', 'val3'); 
/* etc. */ 
COMMIT; 
RENAME TABLE `webservice_temp`.`data` TO `webservice`.`data`; 

Является ли это хорошим решением моей проблемы?

ответ

1

Если вы используете InnoDB, вы можете использовать свой первый подход (и он удовлетворит все три требования), используя START TRANSACTION WITH CONSISTENT SNAPSHOT. Это позволяет выполнять текущие запросы на чтение с моментального снимка исходных данных во время начальной транзакции.

Модификатор WITH CONSISTENT SNAPSHOT запускает последовательное чтение для двигателей хранения, которые способны к нему. Это относится только к InnoDB.

Согласованное считывание означает, что InnoDB использует multi-versioning для представления в запрос моментального снимка базы данных в определенный момент времени. В запросе отображаются изменения, сделанные транзакциями, которые были совершены до этого момента, и никаких изменений, сделанных с помощью последующих или незавершенных транзакций.

Операция чтения, которая использует информацию моментального снимка для представления результатов запроса на основе момента времени, независимо от изменений, выполненных другими транзакциями, выполняемыми одновременно. Если запрошенные данные были изменены другой транзакцией, исходные данные восстанавливаются на основе содержимого журнала отмены. http://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_consistent_read

+0

Это так! Я использую InnoDB. Это похоже на решение, которое я ищу. – mooiamaduck

Смежные вопросы