Ну ... Ага. Роками ніхто не згадував жодної тонкої речі.
Незважаючи на те, що DROP TABLE IF EXISTS `bla`; CREATE TABLE `bla` ( ... );здається розумним, це призводить до ситуації, коли стара таблиця вже відсутня, а нова ще не створена: деякий клієнт може спробувати отримати доступ до предметної таблиці саме в цей момент.
Кращий спосіб - створити абсолютно новий стіл і замінити його на старий (вміст таблиці втрачено):
CREATE TABLE `bla__new` (id int); /* if not ok: terminate, report error */
RENAME TABLE `bla__new` to `bla`; /* if ok: terminate, report success */
RENAME TABLE `bla` to `bla__old`, `bla__new` to `bla`;
DROP TABLE IF EXISTS `bla__old`;
- Ви повинні перевірити результат
CREATE ...і не продовжувати у випадку помилки , оскільки помилка означає, що інша нитка не закінчила той же сценарій: або тому, що вона вибилася посередині або просто ще не закінчилася - це гарна ідея огляньте речі самостійно.
- Потім слід перевірити результат першого
RENAME ...і не продовжувати у разі успіху : вся операція успішно завершена; Більше того, наступний запуск RENAME ...може (і буде) небезпечним, якщо інша нитка вже запустила ту саму послідовність (краще охопити цей випадок, ніж не охоплювати, див. примітку щодо блокування нижче).
- Другий
RENAME ...атомічно замінює визначення таблиці, детальніше див. Посібник з
MySQL
.
- Нарешті,
DROP ...просто очищає старий стіл, очевидно.
Обгортання всіх висловлювань чимось подібним SELECT GET_LOCK('__upgrade', -1); ... DO RELEASE_LOCK('__upgrade');дозволяє просто викликати всі оператори послідовно без перевірки помилок, але я не думаю, що це гарна ідея: складність збільшується і функції блокування в MySQL не безпечні для реплікації на основі висловлювань.
Якщо дані таблиці повинні пережити оновлення визначення таблиці ... У загальному випадку набагато складніший розповідь про порівняння визначень таблиць для виявлення відмінностей та створення належного ALTER ...оператора, що не завжди можливо автоматично, наприклад, коли стовпці перейменовані.
Побічна примітка 1:
Ви можете мати справу з поглядами, використовуючи той самий підхід, в цьому випадку CREATE/DROP TABLEпросто перетворюється на CREATE/DROP VIEWтой час, коли RENAME TABLEзалишається незмінним. Насправді ви навіть можете перетворити таблицю на вигляд і навпаки.
CREATE VIEW `foo__new` as ...; /* if not ok: terminate, report error */
RENAME TABLE `foo__new` to `foo`; /* if ok: terminate, report success */
RENAME TABLE `foo` to `foo__old`, `foo__new` to `foo`;
DROP VIEW IF EXISTS `foo__old`;
Побічна примітка 2:
Користувачі MariaDB повинні бути задоволені тим CREATE OR REPLACE TABLE/VIEW, що вже піклується про проблему теми, і це прекрасні моменти.