我觉得我的商店有一个漏洞,因为我们没有一个可靠的过程来控制数据库模式更改的版本。我们做了很多备份,所以我们或多或少地得到了保护,但以这种方式依赖于最后一道防线是一种糟糕的做法。

令人惊讶的是,这似乎是一个共同的主线。与我交谈过的许多商店都忽略了这个问题,因为他们的数据库不会经常更改,他们基本上只是尽量做到一丝不苟。

不过,我知道这个故事是怎么发展的。这只是时间问题,迟早会出问题,会有东西丢失。

在这方面有什么最佳实践吗?你有哪些行之有效的策略?


当前回答

作为一种规则,我们将所有的对象代码(存储过程、视图、触发器、函数等)都保存在源代码控制中,因为这些对象都是代码,而且几乎所有其他答案都同意,代码属于某种形式的版本控制系统。

As for CREATE, DROP, ALTER statements, etc. (DDL), we developed and use BuildMaster to manage the deployment of these scripts such that they can be run once and only once against a target database (whether they fail or not). The general idea is that developers will upload change scripts into the system and when it comes time for deployment, only the change scripts that haven't been run against the target environment's database will be run (this is managed very similarly to Autocracy's answer). The reason for this separation of script types lies in that once you manipulate a table's structure, add an index, etc., you effectively cannot undo that without writing a brand new script, or restoring the database - as opposed to the object code where you can simply drop a view or stored procedure then recreate it.

例如,当您将生产数据库恢复到集成环境中时,可以看到一些好处,系统会自动准确地知道哪些脚本没有运行,并将更改新恢复的数据库的表结构,使其与开发相关。

其他回答

You should never just log in and start entering "ALTER TABLE" commands to change a production database. The project I'm on has database on every customer site, and so every change to the database is made in two places, a dump file that is used to create a new database on a new customer site, and an update file that is run on every update which checks your current database version number against the highest number in the file, and updates your database in place. So for instance, the last couple of updates:

if [ $VERSION \< '8.0.108' ] ; then
  psql -U cosuser $dbName << EOF8.0.108
    BEGIN TRANSACTION;
    --
    -- Remove foreign key that shouldn't have been there.
    -- PCR:35665
    --
    ALTER TABLE     migratorjobitems
    DROP CONSTRAINT migratorjobitems_destcmaid_fkey;
    -- 
    -- Increment the version
    UPDATE          sys_info
    SET             value = '8.0.108'
    WHERE           key = 'DB VERSION';
    END TRANSACTION;
EOF8.0.108
fi

if [ $VERSION \< '8.0.109' ] ; then
  psql -U cosuser $dbName << EOF8.0.109
    BEGIN TRANSACTION;
    --
    -- I missed a couple of cases when I changed the legacy playlist
    -- from reporting showplaylistidnum to playlistidnum
    --
    ALTER TABLE     featureidrequestkdcs
    DROP CONSTRAINT featureidrequestkdcs_cosfeatureid_fkey;
    ALTER TABLE     featureidrequestkdcs
    ADD CONSTRAINT  featureidrequestkdcs_cosfeatureid_fkey
    FOREIGN KEY     (cosfeatureid)
    REFERENCES      playlist(playlistidnum)
    ON DELETE       CASCADE;
    --
    ALTER TABLE     ticket_system_ids
    DROP CONSTRAINT ticket_system_ids_showplaylistidnum_fkey;
    ALTER TABLE     ticket_system_ids
    RENAME          showplaylistidnum
    TO              playlistidnum;
    ALTER TABLE     ticket_system_ids
    ADD CONSTRAINT  ticket_system_ids_playlistidnum_fkey
    FOREIGN KEY     (playlistidnum)
    REFERENCES      playlist(playlistidnum)
    ON DELETE       CASCADE;
    -- 
    -- Increment the version
    UPDATE          sys_info
    SET             value = '8.0.109'
    WHERE           key = 'DB VERSION';
    END TRANSACTION;
EOF8.0.109
fi

我相信有更好的方法来做到这一点,但到目前为止,它对我来说是有效的。

仅供参考,几天前Dana也提出了这个问题…源代码控制中的存储过程/DB模式

My team versions our database schema as C# classes with the rest of our code. We have a homegrown C# program (<500 lines of code) that reflects the classes and creates SQL commands to build, drop and update the database. After creating the database we run sqlmetal to generate a linq mapping, which is then compiled in another project that is used to generate test data. The whole things works really well because data access is checked at compile time. We like it because the schema is stored in a .cs file which is easy to track compare in trac/svn.

我已经使用RedGate SQL Compare Pro与脚本文件夹进行模式同步,然后我将所有更新提交给版本控制。效果很好。

对于oracle,我使用自己编写的java程序oracle-ddl2svn自动跟踪oracle DDL方案在SVN中的变化