代码之家  ›  专栏  ›  技术社区  ›  Mark Pim

更改表架构时的错误处理和数据完整性

  •  1
  • Mark Pim  · 技术社区  · 15 年前

    我们有一些拥有大型数据集的客户,在升级过程中,我们需要修改各种表的模式(添加一些列、重命名其他列、偶尔更改数据类型,但这很少见)。

    以前,我们一直在使用新模式浏览一个临时表,然后删除原始表并重命名临时表,但我希望通过使用 ALTER table ... 相反。

    我的问题是,我需要考虑哪些数据完整性和错误处理问题?我应该在事务中包含对表的所有更改吗(如果是,如何?)或者,DBMS会在一个变更操作上保证原子性和完整性吗?

    我们已经强烈建议客户在开始升级之前备份他们的数据,因此这应该始终是一个回退选项。

    我们需要以SQLServer2005和Oracle为目标,但是很明显,如果条件代码需要不同的方法,我可以添加它们。

    4 回复  |  直到 15 年前
        1
  •  3
  •   dpbradley    15 年前

    仅限Oracle的注释:

    • 表更改是DDL,因此事务的概念不适用-每个DDL语句在操作期间都锁定表,并且要么成功,要么失败。

    • 正在添加(可以为空!)列或重命名现有列是一个相对轻量级的过程,如果可以获取表锁,则不应出现任何问题。

    • 如果要添加/修改约束(非空或其他更复杂的检查约束),除非将ENABLE NOVALIDATE子句添加到约束DDL中,否则Oracle将检查现有数据以验证约束。对大型表来说,验证现有数据可能是一个漫长的过程。

    • 如果您正在编写要作为SQL*PLUS脚本运行的升级脚本,请使用“每当sqlError退出sql.sqlcode”指令在第一次失败时中止脚本,以便更轻松地检查部分实现的升级,从而省去许多麻烦。

    • 如果必须在既不能控制事务又不能忽略事务的实时系统上执行升级,请考虑使用Oracle DBMS重新定义包,该包自动创建临时表配置和触发器,以便在“后台”重新定义表时捕获飞行中的事务。警告-此选项需要大量工作和陡峭的学习曲线。

        2
  •  1
  •   Neil Barnwell    15 年前

    如果您使用的是SQL Server,那么DDL语句是事务性的,所以将其包装在事务中(不过我认为这不适用于Oracle)。

    我们将升级分成单独的补丁,这些补丁与特定的功能相匹配。应用了哪些补丁 database_patch_history 表,很容易看到应用了哪些补丁以及如何回滚它们。

    如你所说,在开始之前做个备份是很重要的。

        3
  •  1
  •   Jesse Taber    15 年前

    在过去,我必须做这样的改变,并且总是对数据丢失非常偏执。为了帮助降低这种风险,我总是对“沙盒”数据库进行大量的测试,这些数据库在模式和数据中尽可能紧密地反映了目标数据库。在推出流程之前,尽可能多地测试它,就像在应用程序的任何其他领域一样。

        4
  •  0
  •   Jamie Rumbelow    15 年前

    如果您显著地更改列的任何数据类型,例如将varchar更改为int,DBMS将死机,您可能会丢失该数据。幸运的是,现在DBMS足够智能,可以在不丢失数据的情况下进行一些数据类型转换,但是您不希望在进行更改时冒损坏任何数据类型的风险。

    您不应该通过重命名列来释放任何数据,也绝对不应该通过添加新列来释放任何数据,这是您移动数据时必须考虑的问题。

    首先,备份整个表,包括模式和数据,这样,一秒钟后您就可以回滚到以前的模式。第二,看看你想做的改变,看看它们有多剧烈——试着弄清楚到底需要改变什么。如果要进行数据类型转换,请首先将该数据推送到一个中间表中,其中包含3列、外键(ID或其他可以定位行的内容)、旧数据和新列。然后直接将旧数据推送到新列,或者在应用程序级别转换它。

    当所有类型都正确并且一切都成功时,运行alter语句并重新填充数据库!做起来很简单,只需要一个逻辑思维过程。