架构补丁实践

Posted

技术标签:

【中文标题】架构补丁实践【英文标题】:Schema Patches Practices 【发布时间】:2010-10-29 23:30:56 【问题描述】:

我们在 Postgres 中有一个模式,我们想建立一个应用模式补丁的好方法。

目前,我们有一系列用于创建架构、表、序列、函数等的 DDL 文件。我们还有一个用于测试环境的填充脚本。这些文件都用于重新创建我们的数据库环境,用于开发、测试等。

我们还有许多与我们系统版本相对应的“补丁”文件。 IE。 patch/1.0.0.sql、patches/1.0.1.sql 等。这些文件用于更新我们的暂存和生产数据库。

到目前为止,这个过程对我们很有效,但内部存在一些关于如何最好地修补架构的争论。

我很好奇其他人有什么作为一个流程来修补登台和生产模式以及如何管理数据库的版本。

谢谢!

【问题讨论】:

【参考方案1】:

在工作中,对于 SQL Server,我们编写架构更改脚本,首先回滚要进行的更改(幂等,因此即使架构更改尚未应用,回滚部分也可以正常运行),然后是应用更改。在 TSQL 中,很容易在系统目录或其他表中查看表/列/索引/行是否已经存在,如果不存在则不执行任何操作。

在 PostgreSQL 中,您可以简单地发送到服务器的命令受到更多限制 - 但另一方面,DDL 是事务性的,因此不应该发生半应用模式更改。我已经将我在工作中习惯的方案很好地用于我自己的小项目(矫枉过正?但即使在这里我也有一个开发/测试数据库和一个“真实”数据库),例如:

\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”即可在数据库上运行此脚本。通过只删除“正在应用...”消息,我可以获得将其回滚的命令。如您所见,更改维护了一个元数据表“schema_version”,因此我可以看到应用了哪些更改。整个更改以事务、数据迁移等方式完成。在这里,我使用了 DROP 命令的“IF EXISTS”功能来使回滚部分快乐,即使更改未应用。我们在为 Oracle 工作时所做的一件事是将模式更改编写为 PL/SQL——您也许可以在 plpgsql 中提供一些函数来帮助进行更改?

请注意,在上面的更改中,我将“纬度”和“经度”列(可以为空)从“位置”迁移到单独的“位置坐标”关系(并添加了地球距离的东西),我没有删除旧列。我们必须注意的一件事是尽可能使模式更改向后兼容。因此,我可以在更新应用程序以使用新表之前应用此架构更改。我将进行第二次更改以删除旧列以在 更新应用程序后应用。在工作中,这些将在两个不同的发布周期中完成,因此在发布 X 期间,我们仍然可以选择回滚应用程序以发布 X-1,而不必先回滚所有架构更改;以及能够在应用程序之前在单独的窗口中部署架构更改。 (从技术上讲,我应该编写一个触发器,以便对旧表的更新同步到新表,但我没有这样做,因为这太像工作了 :))

我们还有一个应用程序,它可以爬取我们所有的数据库以查看 schema_version 表中的内容并跟踪更改,因此人们甚至可以在无需连接的情况下查看所做的更改,并了解历史记录每次更改(我们跟踪“在开发中回滚”、“在开发中应用”等)。在工作中,我们的 schema_version 表还包括作者信息等。从版本控制中应用版本信息的一种神奇方式会很酷 - 我们遇到的一个问题是,例如,如果在 QA 中应用 SC,然后在 Perforce 中进行更改,则可能不会-一个通知。因此,应用一种跟踪架构更改 35 修订版 #4 的方法会很好。

需要注意的一点 - 对我们而言,架构更改的编号与应用程序版本无关。显然它们是相关的——这是蜘蛛应用程序允许人们进入的另一件事——但我们尝试进行很多小的更改,而不是一个巨大的“这里是发布 X 的所有内容”补丁。架构更改也用于添加新索引之类的事情,因此可能根本不是应用程序驱动的。通常,模式更改由开发人员“拥有”,而不是 DBA - 尽管在上面的“创建索引”示例中,DBA 基本上扮演开发人员角色并拥有模式更改。是的,我们坚持让开发人员具备高水平的 SQL 能力——尽管公司中的其他团队的工作方式略有不同,并且将更多的工作交给了 DB 团队。

【讨论】:

谢谢 aragnid。在我们公司,开发人员的角色也包括创建适当的模式补丁。单个进程用于实际处理补丁。我喜欢 schema_version 表的想法,我们已经在我的工作场所讨论过,并且看到你也使用了一个表来验证这一点。

以上是关于架构补丁实践的主要内容,如果未能解决你的问题,请参考以下文章

转://Oracle数据库补丁分析实践

维护不同 Worklight Studio 补丁程序版本的最佳实践

[硬货分享] Linux 4.1 内核热补丁成功实践

实践热补丁(hotfix)发布内容指标机制

监控系统实践第6天:给CentOS打补丁升级内核与升级软件包

腾讯bugly干货分享微信Android热补丁实践演进之路