Я предполагаю, что это обновление является единственным способом изменения данных в этих таблицах, поэтому вам не нужно беспокоиться о несоответствиях из-за других процессов записи во время загрузки.
Все, что удаление и вставка будет дорогостоящим с точки зрения отмены использования; Вы также исключили бы возможность использования более быстрых методов загрузки данных. Например, ваши вставки будут выполняться намного быстрее, если вы вставляете в таблицы без индексов, а затем применяете индексы после завершения загрузки. Есть и другие стратегии, но обе они исключают метод «сделай все за одну транзакцию».
Ваш второй выбор будет моим выбором - построить новые таблицы, затем переименовать старые в фиктивное имя, переименовать временные в новое имя, а затем отбросить старые таблицы. Поскольку переименования бывают быстрыми, у вас будет менее одной секунды, когда таблицы будут недоступны, и вы сможете свободно удалять старые таблицы на досуге.
Если это второе окно неприемлемо, один из методов, который я использовал в подобных ситуациях, - это использование дополнительного объекта блокировки - в частности, таблицы с одной строкой, из которой пользователи должны были бы выбирать, прежде чем они получат доступ к реальному таблиц, и что ваш процесс загрузки может заблокироваться в монопольном режиме, прежде чем он выполнит операцию переименования.
Ваш PHP-скрипт будет использовать два соединения с БД - одно, где вы делаете блокировку, другое, где вы делаете загрузку, переименование и удаление. Таким образом, неявные фиксации в рабочем соединении не завершат блокировку в другой таблице.
Итак, в сценарии вы бы сделали что-то вроде:
Соединение 1:
Создавайте временные таблицы, загружайте их, создавайте новые индексы
Соединение 2:
LOCK TABLE Load_Locker IN SHARE ROW EXCLUSIVE MODE;
Соединение 1:
Выполнить переименование своп старых и новых таблиц
Соединение 2:
Откат;
Соединение 1:
Удалите старые таблицы.
Между тем, ваши клиенты сразу же после запуска транзакции будут выполнять следующую команду (или серию операций выбора):
LOCK TABLE Load_Locker IN SHARE MODE;
Таким образом, у вас может быть столько клиентов, которые блокируют таблицу таким образом - ваш процесс выше будет блокировать их, пока все они не снимают блокировку, после чего последующие клиенты будут блокировать, пока вы не выполните свои операции. Поскольку единственное, что вы делаете в контексте блокировки SHARE ROW EXCLUSIVE, - это переименование таблиц, ваши клиенты будут блокироваться только на мгновение. Кроме того, установка этого уровня детализации позволяет вам контролировать, как долго клиенты будут иметь согласованное чтение для старой таблицы; без этого, если бы у вас был клиент, который выполнял серию чтений, которые занимали некоторое время, вы могли бы в конечном итоге изменить таблицы в середине потока и получить странные результаты, если ранние запросы извлекали старые данные, а последующие запросы извлекали новые данные. Использование SET TRANSACTION SET ISOLATION LEVEL READ ONLY было бы еще одним способом решения этой проблемы, если бы вы не использовали мой подход.
Единственный реальный недостаток этого подхода заключается в том, что, если транзакции чтения вашего клиента занимают некоторое время, вы рискуете заблокировать других клиентов дольше, чем мгновение, поскольку любые блокировки в режиме SHARE, возникающие после того, как процесс загрузки выдает его Блокировка SHARE ROW EXCLUSIVE блокируется до тех пор, пока процесс загрузки не завершит свою задачу. Например:
10:00 user 1 issues SHARE lock
10:01 user 2 issues SHARE lock
10:03 load process issues SHARE ROW EXCLUSIVE lock (and is blocked)
10:04 user 3 issues SHARE lock (and is blocked by load's lock)
10:10 user 1 releases SHARE
10:11 user 2 releases SHARE (and unblocks loader)
10:11 loader renames tables & releases SHARE ROW EXCLUSIVE (and releases user 3)
10:11 user 3 commences queries, after being blocked for 7 minutes
Тем не менее, это действительно довольно глупо. Решение разделить Кинлан, скорее всего, путь. Добавьте дополнительный столбец к исходным таблицам, который содержит номер версии, разделите данные на основе этой версии, а затем создайте представления, похожие на ваши текущие таблицы, в которых отображаются только данные, отображающие текущую версию (определяется значением строки в Таблица "CurrentVersion"). Затем просто загрузите таблицу, обновите таблицу CurrentVersion и удалите раздел для старых данных.