На работе для SQL Server мы пишем сценарии изменения схемы, которые сначала откатывают внесенное изменение (идемпотентно, поэтому раздел отката работает нормально, даже если изменение схемы еще не применено), а затем раздел к применить изменения. В TSQL легко заглянуть в системный каталог или другие таблицы, чтобы увидеть, существуют ли таблицы / столбцы / индексы / строки, и ничего не делать, если нет.
В PostgreSQL вы немного более ограничены тем, какие команды вы можете просто отправлять на сервер, но, с другой стороны, DDL является транзакционным, поэтому изменение схемы, примененной наполовину, не должно происходить. Я адаптировал схему, к которой я привык на работе, для использования в моих собственных маленьких проектах довольно хорошо (излишество? Но даже здесь у меня есть база данных dev / test и "настоящая" база данных), например:
\echo Rolling back schema change #35
BEGIN;
DELETE FROM schema_version WHERE schema_id = 35;
DROP TABLE IF EXISTS location_coordinates;
DROP FUNCTION IF EXISTS location_coordinates_populate();
END;
\echo Applying schema change #35
BEGIN;
INSERT INTO schema_version(schema_id, description) VALUES(35, 'Add location_coordinates table');
CREATE TABLE location_coordinates(
location_id INT PRIMARY KEY REFERENCES location(location_id),
latitude FLOAT NOT NULL,
longitude FLOAT NOT NULL,
earth_coordinates earth NOT NULL,
box_10miles cube NOT NULL
);
GRANT SELECT, INSERT, UPDATE, DELETE ON location_coordinates TO ui;
CREATE FUNCTION location_coordinates_populate() RETURNS TRIGGER LANGUAGE 'plpgsql' AS $$
BEGIN
new.earth_coordinates := ll_to_earth(new.latitude, new.longitude);
new.box_10miles := earth_box(new.earth_coordinates, 10 * 1609.344);
RETURN new;
END
$$;
CREATE TRIGGER location_coordinates_populate BEFORE INSERT OR UPDATE ON location_coordinates
FOR EACH ROW EXECUTE PROCEDURE location_coordinates_populate();
INSERT INTO location_coordinates(location_id, latitude, longitude)
SELECT location_id, latitude, longitude FROM location WHERE latitude IS NOT NULL AND longitude IS NOT NULL;
CREATE INDEX location_coordinates_10miles ON location_coordinates USING gist (box_10miles);
END;
\echo Done
Этот сценарий может быть запущен в базе данных просто с помощью "psql -f schema-changes / 35.sql". Просто вырезав сообщение «apply ...», я могу получить команды для его отката. И, как вы можете видеть, изменение поддерживает таблицу метаданных "schema_version", поэтому я могу видеть, какие изменения применяются. Все изменение сделано как транзакция, миграция данных и все. Здесь я использовал возможность «IF EXISTS» команд DROP, чтобы сделать откат откликом счастливым, даже если изменение не применено. Одна вещь, которую мы сделали для работы с Oracle, - это запись изменений схемы в PL / SQL - возможно, в plpgsql могут быть некоторые функции, помогающие вносить изменения?
Обратите внимание, что в приведенном выше изменении, где я перемещаю столбцы "широта" и "долгота" (которые можно обнулять) из "местоположения" в отдельное отношение "location_coordinates" (и добавляю в материал earthdistance), Я не бросил старые колонны. Мы должны быть осторожны, чтобы изменения схемы были обратно совместимы, если это возможно. Поэтому я могу применить это изменение схемы перед обновлением приложения для использования новых таблиц. У меня было бы второе изменение, чтобы удалить старые столбцы, чтобы применить после обновления приложения. На работе это можно сделать в двух разных циклах выпуска, поэтому во время выпуска X у нас все еще есть возможность откатить приложение до выпуска X-1 без необходимости откатывать все изменения схемы в первую очередь; а также возможность развертывания изменений схемы в отдельном окне перед приложениями. (Технически я должен был написать триггер, чтобы обновления старой таблицы синхронизировались с новой таблицей, но я этого не сделал, потому что это слишком похоже на работу:))
У нас также есть такие вещи, как приложение, которое отслеживает все наши базы данных, чтобы увидеть, что находится в таблице schema_version
, и отслеживает изменения, так что люди могут даже видеть, какие изменения были внесены без подключения, и получить представление об истории. каждого изменения (мы отслеживаем «откат в dev», «применение в dev» и т. д.). В работе наша таблица schema_version также включает информацию об авторстве и т. Д. Волшебный способ применения информации о версии из системы управления версиями был бы крут - одна из проблем, с которой мы столкнулись, заключается в том, что если SC применяется, например, в QA, то изменяется в Perforce, а может и один замечает. Таким образом, был бы полезен способ отследить это изменение схемы 35 редакция № 4.
Стоит отметить, что изменения схемы для нас нумеруются независимо от версий приложения. Очевидно, что они связаны между собой - это еще одна вещь, в которую приложение spidering позволяет людям входить, - но мы стараемся внести множество небольших изменений, а не гигантский патч «Вот и все для релиза X». Изменения схемы также используются для таких вещей, как добавление новых индексов, поэтому могут вообще не зависеть от приложений. В целом, изменения схемы «принадлежат» разработчикам, а не администраторам баз данных, хотя в приведенном выше примере «создания индекса» администратор баз данных выступает в роли разработчика и владеет изменением схемы. Да, мы настаиваем на высоком уровне SQL-возможностей со стороны разработчиков, хотя другие группы в компании работают немного по-другому и дают больше работы команде БД.