我觉得我的商店有一个漏洞,因为我们没有一个可靠的流程来版本化我们的数据库模式更改。我们做了很多备份,所以我们或多或少都被覆盖了,但以这种方式依赖你的最后一道防线是不好的做法。
令人惊讶的是,这似乎是一个共同点。我说过的很多商店都忽略了这个问题,因为他们的数据库并没有经常变化,而且他们基本上只是一丝不苟。
然而,我知道这个故事是怎么回事。事情排列错误只是一个时间问题而且缺少某些东西。
对此有什么最佳做法吗?有哪些策略对你有用?
答案 0 :(得分:380)
必须阅读Get your database under version control。查看K. Scott Allen的一系列帖子。
在版本控制方面,数据库通常是第二类甚至是三等公民。从我所看到的情况来看,那些在没有版本控制的情况下永远不会想到编写代码的团队在一百万年之内 - 这是正确的 - 在某种程度上可以完全忘记对应用程序所依赖的关键数据库进行版本控制的需求。我不知道当你的数据库与其他代码完全没有完全相同的源代码控制级别时,你怎么称自己为软件工程师并保持直面。不要让这件事发生在你身上。在版本控制下获取数据库。
答案 1 :(得分:134)
数据库本身?否
创建它们的脚本,包括静态数据插入,存储过程等;当然。它们是文本文件,它们包含在项目中,并像其他所有内容一样进行检入。
当然,在理想的世界中,您的数据库管理工具会这样做;但你必须对此保持纪律处分。
答案 2 :(得分:36)
我非常喜欢Rails ActiveRecord迁移。它将DML抽象为ruby脚本,然后可以在源代码库中轻松进行版本化。
然而,通过一些工作,你可以做同样的事情。任何DDL更改(ALTER TABLE等)都可以存储在文本文件中。保留文件名的编号系统(或日期戳),并按顺序应用它们。
Rails在数据库中还有一个“版本”表,用于跟踪上次应用的迁移。你可以轻松地做到这一点。
答案 3 :(得分:33)
使用源代码管理检查LiquiBase以管理数据库更改。
答案 4 :(得分:29)
您永远不应该只是登录并开始输入“ALTER TABLE”命令来更改生产数据库。我所在的项目在每个客户站点都有数据库,所以对数据库的每次更改都在两个地方进行,一个用于在新客户站点上创建新数据库的转储文件,以及一个运行的更新文件每次更新时,会根据文件中的最大数字检查当前数据库版本号,并更新您的数据库。例如,最后几次更新:
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
我确信有更好的方法可以做到这一点,但到目前为止它对我有用。
答案 5 :(得分:17)
是。代码是代码。我的经验法则是,我需要能够从头开始构建和部署应用程序,而无需查看开发或生产机器。
答案 6 :(得分:14)
我见过的最佳做法是创建一个构建脚本,以便在登台服务器上废弃和重建数据库。每次迭代都有一个用于数据库更改的文件夹,所有更改都使用“Drop ... Create”编写。这样,您可以随时将构建指向要版本的文件夹,从而回滚到早期版本。
我相信这是用NaNt / CruiseControl完成的。
答案 7 :(得分:11)
是的,我认为对数据库进行版本控制非常重要。不是数据,而是某些模式。
在Ruby On Rails中,这由具有“迁移”的框架处理。每次更改数据库时,都会创建一个应用更改并将其检入源代码管理的脚本。
我的商店非常喜欢这个想法,我们在基于Java的构建using shell scripts和Ant中添加了这些功能。我们将流程集成到我们的部署例程中。编写脚本以在其他框架中执行相同的操作相当容易,这些框架不支持开箱即用的DB版本控制。
答案 8 :(得分:8)
要求开发团队使用SQL数据库源代码管理系统并不是防止问题发生的灵丹妙药。数据库源代码控制本身带来了额外的开销,因为开发人员需要在单独的SQL脚本中保存他们对对象所做的更改,打开源代码控制系统客户端,使用客户端签入SQL脚本文件然后将更改应用于实时数据库。
我可以建议使用名为ApexSQL Source Control的SSMS加载项。它允许开发人员通过SSMS直接从向导轻松地使用源控制系统映射数据库对象。该加载项包括对TFS,Git,Subversion和其他SC系统的支持。它还包括对源控制静态数据的支持。
下载并安装ApexSQL Source Control后,只需右键单击要进行版本控制的数据库,然后导航到SSMS中的ApexSQL Source Control子菜单。单击“链接数据库到源代码管理”选项,选择源代码管理系统和开发模型。之后,您需要为您选择的源控制系统提供登录信息和存储库字符串。
您可以阅读本文以获取更多信息:http://solutioncenter.apexsql.com/sql-source-control-reduce-database-development-time/
答案 9 :(得分:8)
Visual Studio中的新数据库项目提供源代码控制和更改脚本。
他们有一个很好的工具可以比较数据库,并且可以生成一个脚本,将一个模式转换为另一个,或者将数据更新为一个以匹配另一个。
db schema被“粉碎”以创建许多小的.sql文件,每个DDL命令一个,用于描述数据库。
+汤姆
其他信息2008-11-30
过去一年我一直在使用它作为开发人员而且非常喜欢它。它可以轻松地将我的开发工作与生产进行比较,并生成用于发布的脚本。我不知道DBA是否缺少“企业级”项目所需的功能。
因为模式被“粉碎”成sql文件,所以源代码控制工作正常。
一个问题是,当您使用数据库项目时,您需要有不同的心态。该工具在VS中有一个“db项目”,它只是sql,加上一个自动生成的本地数据库,它具有模式和一些其他管理数据 - 但是没有您的应用程序数据,还有您用于的本地dev db应用数据开发工作。你很少知道自动生成的数据库,但你必须知道它在那里,所以你可以不管它:)。这个特殊的数据库清晰可辨,因为它的名字中有一个Guid,
VS DB项目可以很好地将其他团队成员进行的数据库更改集成到本地项目/关联数据库中。但您需要采取额外步骤将项目架构与本地dev db架构进行比较并应用mod。这是有道理的,但一开始看起来很尴尬。
DB Projects是一个非常强大的工具。它们不仅可以生成脚本,还可以立即应用它们。一定不要用它来销毁你的生产数据库。 ;)
我非常喜欢VS DB项目,我希望将此工具用于我的所有数据库项目。
+汤姆
答案 10 :(得分:6)
我通过保存创建/更新脚本和生成采样数据的脚本来实现。
答案 11 :(得分:6)
我们对所有dabase创建的对象进行源代码控制。只是为了让开发人员保持诚实(因为你可以在没有源代码控制的情况下创建对象),我们的dbas会定期查找不在源代码控制中的任何内容,如果他们发现任何内容,他们会在不询问是否正常的情况下删除它。
答案 12 :(得分:6)
我在项目中使用过的最成功的方案是将备份和差异SQL文件结合起来。基本上我们会在每次发布后备份我们的数据库并执行SQL转储,这样我们就可以从头开始创建一个空白模式。然后,只要您需要对DB进行更改,就可以在版本控制下的sql目录中添加alter scrip。我们总是将序列号或日期作为文件名的前缀,因此第一次更改将类似于01_add_created_on_column.sql,下一个脚本将是02_added_customers_index。我们的CI计算机会检查这些并按顺序在从备份恢复的数据库的新副本上运行它们。
我们还有一些脚本可供devs使用一个命令将其本地数据库重新初始化为当前版本。
答案 13 :(得分:6)
是的,我们通过将SQL作为构建的一部分来实现 - 我们保留DROP.sql,CREATE.sql,USERS.sql,VALUES.sql和版本控制这些,所以我们可以恢复到任何标记版本
我们还有ant任务,可以在需要时重新创建数据库。
另外,SQL随后会与您的源代码一起被标记。
答案 14 :(得分:5)
我使用SchemaBank版本控制我的所有数据库架构更改:
我们的团队规则是永远不要直接触摸数据库服务器而不先存储设计工作。但它发生了,为方便起见,有人可能会试图违反规则。我们会再次将模式转储导入到schemabank中,如果发现差异,就让它做差异并打击某人。虽然我们可以从中生成alter脚本以使我们的数据库和模式设计同步,但我们只是讨厌它。
顺便说一句,他们还允许我们在版本控制树中创建分支,以便我可以维护一个用于分段,一个用于生产。还有一个用于编码沙箱。
一个非常简洁的基于Web的架构设计工具,具有版本控制和变更管理。
答案 15 :(得分:4)
我们对数据库周围的所有内容进行版本控制和控制:
我们使用Change Manager和一些自定义脚本完成所有这些操作。我们让Change Manager监控这些更改并通知它们何时完成。
答案 16 :(得分:4)
关于数据库模型本身已有很多讨论,但我们也将所需数据保存在.SQL文件中。
例如,为了有用,您的应用程序可能需要在安装中使用它:
INSERT INTO Currency (CurrencyCode, CurrencyName)
VALUES ('AUD', 'Australian Dollars');
INSERT INTO Currency (CurrencyCode, CurrencyName)
VALUES ('USD', 'US Dollars');
我们在subversion下会有一个名为currency.sql
的文件。作为构建过程中的手动步骤,我们将之前的currency.sql与最新的currency.sql进行比较并编写升级脚本。
答案 17 :(得分:4)
我相信每个数据库都应该受源代码控制,开发人员应该有一种简单的方法从头开始创建本地数据库。受Visual Studio for Database Professionals的启发,我创建了一个脚本MS SQL数据库的开源工具,并提供了将它们部署到本地数据库引擎的简便方法。试试http://dbsourcetools.codeplex.com/。玩得开心, - 内森。
答案 18 :(得分:4)
如果您的数据库是SQL Server,我们可能只有您正在寻找的解决方案。 SQL Source Control 1.0现已发布。
http://www.red-gate.com/products/SQL_Source_Control/index.htm
它集成到SSMS中,并提供数据库对象和VCS之间的粘合剂。 “脚本输出”是透明地发生的(它使用了引擎盖下的SQL Compare引擎),这使得它的使用非常简单,不会阻止开发人员采用这个过程。
另一种Visual Studio解决方案是ReadyRoll,它是作为SSDT数据库项目的子类型实现的。这采用迁移驱动的方法,更适合DevOps团队的自动化要求。
答案 19 :(得分:4)
我使用从MySQL Workbech导出的SQL CREATE脚本,然后使用他们的“导出SQL ALTER”功能,我最终得到了一系列创建脚本(编号当然)和可以在它们之间应用更改的alter脚本。
3.-导出SQL ALTER脚本 通常,您现在必须手动编写ALTER TABLE语句,以反映您对模型所做的更改。但是你可以聪明,让Workbench为你努力工作。只需选择文件 - &gt;出口 - &gt;从主菜单中转发工程师SQL ALTER脚本....
这将提示您指定应与当前模型进行比较的SQL CREATE文件。
从步骤1中选择SQL CREATE脚本。然后,该工具将为您生成ALTER TABLE脚本,您可以对数据库执行此脚本以使其保持最新。
你可以使用MySQL Query Browser或mysql client.Voila来做到这一点!您的模型和数据库现已同步!
来源:MySQL Workbench Community Edition: Guide to Schema Synchronization
所有这些脚本当然都在版本控制之下。
答案 20 :(得分:4)
是的,永远。您应该能够在需要时使用一组有用的示例数据重新创建生产数据库结构。如果你不这样做的话,随着时间的推移,一些细微的变化会让事情变得困难,那么有一天你会感到被咬,很大的时候。保险,你可能认为你不需要,但在你做它的那天,它的价格超过10倍!
答案 21 :(得分:4)
我拥有从裸机重建数据库所需的一切,减去数据本身。我确信有很多方法可以做到这一点,但是我的所有脚本都存储在subversion中,我们可以重建数据库结构,例如通过从subversion中提取所有内容并运行安装程序。
答案 22 :(得分:4)
我通常为每个更改构建一个SQL脚本,另一个用于还原这些更改,并将这些脚本保留在版本控制之下。
然后我们可以根据需要创建新的最新数据库,并且可以轻松地在修订版之间移动。每次我们进行发布时,我们都会将脚本放在一起(需要一些手动工作,但实际上很少硬)所以我们还有一组可以在不同版本之间进行转换的脚本。
是的,在你说出来之前,这与Rails和其他人的做法非常相似,但它似乎工作得很好,所以我承认我无耻地解除了这个想法没有问题:)
答案 23 :(得分:3)
我在http://dbdeploy.com/使用了ThoughtWorks的dbdeploy工具。它鼓励使用迁移脚本。在每个版本中,我们将更改脚本合并到一个文件中,以便于理解并允许DBA“祝福”更改。
答案 24 :(得分:3)
在我们的业务中,我们使用数据库更改脚本。运行脚本时,它的名称将存储在数据库中,并且不会再次运行,除非删除该行。脚本根据日期,时间和代码分支命名,因此可以进行受控执行。
在脚本在实时环境中运行之前完成了大量的测试,所以“oopsies”只会在开发数据库上发生。
答案 25 :(得分:3)
这是一个穷人的示例解决方案,用于在sql server 2005/2008数据库上实现跟踪db对象更改(通过DDL状态)的触发器。我还包含一个简单的示例,说明如何在数据库上运行的每个sql命令的源代码中强制使用所需的someValue xml标记+跟踪当前的db版本和类型(dev,test,qa,fb,prod ) 可以使用其他必需属性扩展它,例如等。 代码相当长 - 它创建了空数据库+所需的跟踪表结构+所需的数据库函数以及所有在[ga]模式下运行的填充触发器。
USE [master]
GO
/****** Object: Database [DBGA_DEV] Script Date: 04/22/2009 13:22:01 ******/
CREATE DATABASE [DBGA_DEV] ON PRIMARY
( NAME = N'DBGA_DEV', FILENAME = N'D:\GENAPP\DATA\DBFILES\DBGA_DEV.mdf' , SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
LOG ON
( NAME = N'DBGA_DEV_log', FILENAME = N'D:\GENAPP\DATA\DBFILES\DBGA_DEV_log.ldf' , SIZE = 6208KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO
ALTER DATABASE [DBGA_DEV] SET COMPATIBILITY_LEVEL = 100
GO
IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))
begin
EXEC [DBGA_DEV].[dbo].[sp_fulltext_database] @action = 'enable'
end
GO
ALTER DATABASE [DBGA_DEV] SET ANSI_NULL_DEFAULT OFF
GO
ALTER DATABASE [DBGA_DEV] SET ANSI_NULLS OFF
GO
ALTER DATABASE [DBGA_DEV] SET ANSI_PADDING ON
GO
ALTER DATABASE [DBGA_DEV] SET ANSI_WARNINGS OFF
GO
ALTER DATABASE [DBGA_DEV] SET ARITHABORT OFF
GO
ALTER DATABASE [DBGA_DEV] SET AUTO_CLOSE OFF
GO
ALTER DATABASE [DBGA_DEV] SET AUTO_CREATE_STATISTICS ON
GO
ALTER DATABASE [DBGA_DEV] SET AUTO_SHRINK OFF
GO
ALTER DATABASE [DBGA_DEV] SET AUTO_UPDATE_STATISTICS ON
GO
ALTER DATABASE [DBGA_DEV] SET CURSOR_CLOSE_ON_COMMIT OFF
GO
ALTER DATABASE [DBGA_DEV] SET CURSOR_DEFAULT GLOBAL
GO
ALTER DATABASE [DBGA_DEV] SET CONCAT_NULL_YIELDS_NULL OFF
GO
ALTER DATABASE [DBGA_DEV] SET NUMERIC_ROUNDABORT OFF
GO
ALTER DATABASE [DBGA_DEV] SET QUOTED_IDENTIFIER OFF
GO
ALTER DATABASE [DBGA_DEV] SET RECURSIVE_TRIGGERS OFF
GO
ALTER DATABASE [DBGA_DEV] SET DISABLE_BROKER
GO
ALTER DATABASE [DBGA_DEV] SET AUTO_UPDATE_STATISTICS_ASYNC OFF
GO
ALTER DATABASE [DBGA_DEV] SET DATE_CORRELATION_OPTIMIZATION OFF
GO
ALTER DATABASE [DBGA_DEV] SET TRUSTWORTHY OFF
GO
ALTER DATABASE [DBGA_DEV] SET ALLOW_SNAPSHOT_ISOLATION OFF
GO
ALTER DATABASE [DBGA_DEV] SET PARAMETERIZATION SIMPLE
GO
ALTER DATABASE [DBGA_DEV] SET READ_COMMITTED_SNAPSHOT OFF
GO
ALTER DATABASE [DBGA_DEV] SET HONOR_BROKER_PRIORITY OFF
GO
ALTER DATABASE [DBGA_DEV] SET READ_WRITE
GO
ALTER DATABASE [DBGA_DEV] SET RECOVERY FULL
GO
ALTER DATABASE [DBGA_DEV] SET MULTI_USER
GO
ALTER DATABASE [DBGA_DEV] SET PAGE_VERIFY CHECKSUM
GO
ALTER DATABASE [DBGA_DEV] SET DB_CHAINING OFF
GO
EXEC [DBGA_DEV].sys.sp_addextendedproperty @name=N'DbType', @value=N'DEV'
GO
EXEC [DBGA_DEV].sys.sp_addextendedproperty @name=N'DbVersion', @value=N'0.0.1.20090414.1100'
GO
USE [DBGA_DEV]
GO
/****** Object: Schema [ga] Script Date: 04/22/2009 13:21:29 ******/
CREATE SCHEMA [ga] AUTHORIZATION [dbo]
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Contains the objects of the Generic Application database' , @level0type=N'SCHEMA',@level0name=N'ga'
GO
/****** Object: Table [ga].[tb_DataMeta_ObjChangeLog] Script Date: 04/22/2009 13:21:40 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [ga].[tb_DataMeta_ObjChangeLog](
[LogId] [int] IDENTITY(1,1) NOT NULL,
[TimeStamp] [timestamp] NOT NULL,
[DatabaseName] [varchar](256) NOT NULL,
[SchemaName] [varchar](256) NOT NULL,
[DbVersion] [varchar](20) NOT NULL,
[DbType] [varchar](20) NOT NULL,
[EventType] [varchar](50) NOT NULL,
[ObjectName] [varchar](256) NOT NULL,
[ObjectType] [varchar](25) NOT NULL,
[Version] [varchar](50) NULL,
[SqlCommand] [varchar](max) NOT NULL,
[EventDate] [datetime] NOT NULL,
[LoginName] [varchar](256) NOT NULL,
[FirstName] [varchar](256) NULL,
[LastName] [varchar](50) NULL,
[ChangeDescription] [varchar](1000) NULL,
[Description] [varchar](1000) NULL,
[ObjVersion] [varchar](20) NOT NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'The database version as written in the extended prop of the database' , @level0type=N'SCHEMA',@level0name=N'ga', @level1type=N'TABLE',@level1name=N'tb_DataMeta_ObjChangeLog', @level2type=N'COLUMN',@level2name=N'DbVersion'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'dev , test , qa , fb or prod' , @level0type=N'SCHEMA',@level0name=N'ga', @level1type=N'TABLE',@level1name=N'tb_DataMeta_ObjChangeLog', @level2type=N'COLUMN',@level2name=N'DbType'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'The name of the object as it is registered in the sys.objects ' , @level0type=N'SCHEMA',@level0name=N'ga', @level1type=N'TABLE',@level1name=N'tb_DataMeta_ObjChangeLog', @level2type=N'COLUMN',@level2name=N'ObjectName'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'' , @level0type=N'SCHEMA',@level0name=N'ga', @level1type=N'TABLE',@level1name=N'tb_DataMeta_ObjChangeLog', @level2type=N'COLUMN',@level2name=N'Description'
GO
SET IDENTITY_INSERT [ga].[tb_DataMeta_ObjChangeLog] ON
INSERT [ga].[tb_DataMeta_ObjChangeLog] ([LogId], [DatabaseName], [SchemaName], [DbVersion], [DbType], [EventType], [ObjectName], [ObjectType], [Version], [SqlCommand], [EventDate], [LoginName], [FirstName], [LastName], [ChangeDescription], [Description], [ObjVersion]) VALUES (3, N'DBGA_DEV', N'en', N'0.0.1.20090414.1100', N'DEV', N'DROP_TABLE', N'tb_BL_Products', N'TABLE', N' some', N'<EVENT_INSTANCE><EventType>DROP_TABLE</EventType><PostTime>2009-04-22T11:03:11.880</PostTime><SPID>57</SPID><ServerName>YSG</ServerName><LoginName>ysg\yordgeor</LoginName><UserName>dbo</UserName><DatabaseName>DBGA_DEV</DatabaseName><SchemaName>en</SchemaName><ObjectName>tb_BL_Products</ObjectName><ObjectType>TABLE</ObjectType><TSQLCommand><SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON" ANSI_PADDING="ON" QUOTED_IDENTIFIER="ON" ENCRYPTED="FALSE"/><CommandText>drop TABLE [en].[tb_BL_Products] --<Version> some</Version>
</CommandText></TSQLCommand></EVENT_INSTANCE>', CAST(0x00009BF300B6271C AS DateTime), N'ysg\yordgeor', N'Yordan', N'Georgiev', NULL, NULL, N'0.0.0')
INSERT [ga].[tb_DataMeta_ObjChangeLog] ([LogId], [DatabaseName], [SchemaName], [DbVersion], [DbType], [EventType], [ObjectName], [ObjectType], [Version], [SqlCommand], [EventDate], [LoginName], [FirstName], [LastName], [ChangeDescription], [Description], [ObjVersion]) VALUES (4, N'DBGA_DEV', N'en', N'0.0.1.20090414.1100', N'DEV', N'CREATE_TABLE', N'tb_BL_Products', N'TABLE', N' 2.2.2 ', N'<EVENT_INSTANCE><EventType>CREATE_TABLE</EventType><PostTime>2009-04-22T11:03:18.620</PostTime><SPID>57</SPID><ServerName>YSG</ServerName><LoginName>ysg\yordgeor</LoginName><UserName>dbo</UserName><DatabaseName>DBGA_DEV</DatabaseName><SchemaName>en</SchemaName><ObjectName>tb_BL_Products</ObjectName><ObjectType>TABLE</ObjectType><TSQLCommand><SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON" ANSI_PADDING="ON" QUOTED_IDENTIFIER="ON" ENCRYPTED="FALSE"/><CommandText>CREATE TABLE [en].[tb_BL_Products](
[ProducId] [int] NULL,
[ProductName] [nchar](10) NULL,
[ProductDescription] [varchar](5000) NULL
) ON [PRIMARY]
/*
<Version> 2.2.2 </Version>

*/
</CommandText></TSQLCommand></EVENT_INSTANCE>', CAST(0x00009BF300B62F07 AS DateTime), N'ysg\yordgeor', N'Yordan', N'Georgiev', NULL, NULL, N'0.0.0')
INSERT [ga].[tb_DataMeta_ObjChangeLog] ([LogId], [DatabaseName], [SchemaName], [DbVersion], [DbType], [EventType], [ObjectName], [ObjectType], [Version], [SqlCommand], [EventDate], [LoginName], [FirstName], [LastName], [ChangeDescription], [Description], [ObjVersion]) VALUES (5, N'DBGA_DEV', N'en', N'0.0.1.20090414.1100', N'DEV', N'DROP_TABLE', N'tb_BL_Products', N'TABLE', N' 2.2.2 ', N'<EVENT_INSTANCE><EventType>DROP_TABLE</EventType><PostTime>2009-04-22T11:25:12.620</PostTime><SPID>57</SPID><ServerName>YSG</ServerName><LoginName>ysg\yordgeor</LoginName><UserName>dbo</UserName><DatabaseName>DBGA_DEV</DatabaseName><SchemaName>en</SchemaName><ObjectName>tb_BL_Products</ObjectName><ObjectType>TABLE</ObjectType><TSQLCommand><SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON" ANSI_PADDING="ON" QUOTED_IDENTIFIER="ON" ENCRYPTED="FALSE"/><CommandText>drop TABLE [en].[tb_BL_Products] 
</CommandText></TSQLCommand></EVENT_INSTANCE>', CAST(0x00009BF300BC32F1 AS DateTime), N'ysg\yordgeor', N'Yordan', N'Georgiev', NULL, NULL, N'0.0.0')
INSERT [ga].[tb_DataMeta_ObjChangeLog] ([LogId], [DatabaseName], [SchemaName], [DbVersion], [DbType], [EventType], [ObjectName], [ObjectType], [Version], [SqlCommand], [EventDate], [LoginName], [FirstName], [LastName], [ChangeDescription], [Description], [ObjVersion]) VALUES (6, N'DBGA_DEV', N'en', N'0.0.1.20090414.1100', N'DEV', N'CREATE_TABLE', N'tb_BL_Products', N'TABLE', N' 2.2.2 ', N'<EVENT_INSTANCE><EventType>CREATE_TABLE</EventType><PostTime>2009-04-22T11:25:19.053</PostTime><SPID>57</SPID><ServerName>YSG</ServerName><LoginName>ysg\yordgeor</LoginName><UserName>dbo</UserName><DatabaseName>DBGA_DEV</DatabaseName><SchemaName>en</SchemaName><ObjectName>tb_BL_Products</ObjectName><ObjectType>TABLE</ObjectType><TSQLCommand><SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON" ANSI_PADDING="ON" QUOTED_IDENTIFIER="ON" ENCRYPTED="FALSE"/><CommandText>CREATE TABLE [en].[tb_BL_Products](
[ProducId] [int] NULL,
[ProductName] [nchar](10) NULL,
[ProductDescription] [varchar](5000) NULL
) ON [PRIMARY]
/*
<Version> 2.2.2 </Version>

*/
</CommandText></TSQLCommand></EVENT_INSTANCE>', CAST(0x00009BF300BC3A69 AS DateTime), N'ysg\yordgeor', N'Yordan', N'Georgiev', NULL, NULL, N'0.0.0')
SET IDENTITY_INSERT [ga].[tb_DataMeta_ObjChangeLog] OFF
/****** Object: Table [ga].[tb_BLSec_LoginsForUsers] Script Date: 04/22/2009 13:21:40 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [ga].[tb_BLSec_LoginsForUsers](
[LoginsForUsersId] [int] IDENTITY(1,1) NOT NULL,
[LoginName] [nvarchar](100) NOT NULL,
[FirstName] [varchar](100) NOT NULL,
[SecondName] [varchar](100) NULL,
[LastName] [varchar](100) NOT NULL,
[DomainName] [varchar](100) NOT NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
SET IDENTITY_INSERT [ga].[tb_BLSec_LoginsForUsers] ON
INSERT [ga].[tb_BLSec_LoginsForUsers] ([LoginsForUsersId], [LoginName], [FirstName], [SecondName], [LastName], [DomainName]) VALUES (1, N'ysg\yordgeor', N'Yordan', N'Stanchev', N'Georgiev', N'yordgeor')
SET IDENTITY_INSERT [ga].[tb_BLSec_LoginsForUsers] OFF
/****** Object: Table [en].[tb_BL_Products] Script Date: 04/22/2009 13:21:40 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [en].[tb_BL_Products](
[ProducId] [int] NULL,
[ProductName] [nchar](10) NULL,
[ProductDescription] [varchar](5000) NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
/****** Object: StoredProcedure [ga].[procUtils_SqlCheatSheet] Script Date: 04/22/2009 13:21:37 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [ga].[procUtils_SqlCheatSheet]
as
set nocount on
--what was the name of the table with something like role
/*
SELECT * from sys.tables where [name] like '%POC%'
*/
-- what are the columns of this table
/*
select column_name , DATA_TYPE , CHARACTER_MAXIMUM_LENGTH, table_name from Information_schema.columns where table_name='tbGui_ExecutePOC'
*/
-- find proc
--what was the name of procedure with something like role
/*
select * from sys.procedures where [name] like '%ext%'
exec sp_HelpText procName
*/
/*
exec sp_helpText procUtils_InsertGenerator
*/
--how to list all databases in sql server
/*
SELECT database_id AS ID, NULL AS ParentID, name AS Text FROM sys.databases ORDER BY [name]
*/
--HOW-TO LIST ALL TABLES IN A SQL SERVER 2005 DATABASE
/*
SELECT TABLE_NAME FROM [POC].INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME <> 'dtproperties'
ORDER BY TABLE_NAME
*/
--HOW-TO ENABLE XP_CMDSHELL START
-------------------------------------------------------------------------
-- configure verbose mode temporarily
-- EXECUTE sp_configure 'show advanced options', 1
-- RECONFIGURE WITH OVERRIDE
--GO
--ENABLE xp_cmdshell
-- EXECUTE sp_configure 'xp_cmdshell', '1'
-- RECONFIGURE WITH OVERRIDE
-- EXEC SP_CONFIGURE 'show advanced option', '1';
-- SHOW THE CONFIGURATION
-- EXEC SP_CONFIGURE;
--turn show advance options off
-- GO
--EXECUTE sp_configure 'show advanced options', 0
-- RECONFIGURE WITH OVERRIDE
-- GO
--HOW-TO ENABLE XP_CMDSHELL END
-------------------------------------------------------------------------
--HOW-TO IMPLEMENT SLEEP
-- sleep for 10 seconds
-- WAITFOR DELAY '00:00:10' SELECT * FROM My_Table
/* LIST ALL PRIMARY KEYS
SELECT
INFORMATION_SCHEMA.TABLE_CONSTRAINTS.TABLE_NAME AS TABLE_NAME,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE.COLUMN_NAME AS COLUMN_NAME,
REPLACE(INFORMATION_SCHEMA.TABLE_CONSTRAINTS.CONSTRAINT_TYPE,' ', '_') AS CONSTRAINT_TYPE
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE ON
INFORMATION_SCHEMA.TABLE_CONSTRAINTS.CONSTRAINT_NAME =
INFORMATION_SCHEMA.KEY_COLUMN_USAGE.CONSTRAINT_NAME
WHERE
INFORMATION_SCHEMA.TABLE_CONSTRAINTS.TABLE_NAME <> N'sysdiagrams'
ORDER BY
INFORMATION_SCHEMA.TABLE_CONSTRAINTS.TABLE_NAME ASC
*/
--HOW-TO COPY TABLE AND THE WHOLE TABLE DATA , COPY TABLE FROM DB TO DB
--==================================================START
/*
use Poc_Dev
go
drop table tbGui_LinksVisibility
use POc_test
go
select *
INTO [POC_Dev].[ga].[tbGui_LinksVisibility]
from [POC_TEST].[ga].[tbGui_LinksVisibility]
*/
--HOW-TO COPY TABLE AND THE WHOLE TABLE DATA , COPY TABLE FROM DB TO DB
--====================================================END
--=================================================== SEE TABLE METADATA START
/*
SELECT c.name AS [COLUMN_NAME], sc.data_type AS [DATA_TYPE], [value] AS
[DESCRIPTION] , c.max_length as [MAX_LENGTH] , c.is_nullable AS [OPTIONAL]
, c.is_identity AS [IS_PRIMARY_KEY] FROM sys.extended_properties AS ep
INNER JOIN sys.tables AS t ON ep.major_id = t.object_id
INNER JOIN sys.columns AS c ON ep.major_id = c.object_id AND ep.minor_id
= c.column_id
INNER JOIN INFORMATION_SCHEMA.COLUMNS sc ON t.name = sc.table_name and
c.name = sc.column_name
WHERE class = 1 and t.name = 'tbGui_ExecutePOC' ORDER BY SC.DATA_TYPE
*/
--=================================================== SEE TABLE METADATA END
/*
select * from Information_schema.columns
select table_name , column_name from Information_schema.columns where table_name='tbGui_Wizards'
*/
--=================================================== LIST ALL TABLES AND THEIR DESCRIPTOINS START
/*
SELECT T.name AS TableName, CAST(Props.value AS varchar(1000)) AS
TableDescription
FROM sys.tables AS T LEFT OUTER JOIN
(SELECT class, class_desc, major_id, minor_id,
name, value
FROM sys.extended_properties
WHERE (minor_id = 0) AND (class = 1)) AS
Props ON T.object_id = Props.major_id
WHERE (T.type = 'U') AND (T.name <> N'sysdiagrams')
ORDER BY TableName
*/
--=================================================== LIST ALL TABLES AND THEIR DESCRIPTOINS START
--=================================================== LIST ALL OBJECTS FROM DB START
/*
use DB
--HOW-TO LIST ALL PROCEDURE IN A DATABASE
select s.name from sysobjects s where type = 'P'
--HOW-TO LIST ALL TRIGGERS BY NAME IN A DATABASE
select s.name from sysobjects s where type = 'TR'
--HOW-TO LIST TABLES IN A DATABASE
select s.name from sysobjects s where type = 'U'
--how-to list all system tables in a database
select s.name from sysobjects s where type = 's'
--how-to list all the views in a database
select s.name from sysobjects s where type = 'v'
*/
/*
Similarly you can find out other objects created by user, simple change type =
C = CHECK constraint
D = Default or DEFAULT constraint
F = FOREIGN KEY constraint
L = Log
FN = Scalar function
IF = In-lined table-function
P = Stored procedure
PK = PRIMARY KEY constraint (type is K)
RF = Replication filter stored procedure
S = System table
TF = Table function
TR = Trigger
U = User table ( this is the one I discussed above in the example)
UQ = UNIQUE constraint (type is K)
V = View
X = Extended stored procedure
*/
--=================================================== HOW-TO SEE ALL MY PERMISSIONS START
/*
SELECT * FROM fn_my_permissions(NULL, 'SERVER');
USE poc_qa;
SELECT * FROM fn_my_permissions (NULL, 'database');
GO
*/
--=================================================== HOW-TO SEE ALL MY PERMISSIONS END
/*
--find table
use poc_dev
go
select s.name from sysobjects s where type = 'u' and s.name like '%Visibility%'
select * from tbGui_LinksVisibility
*/
/* find cursor
use poc
go
DECLARE @procName varchar(100)
DECLARE @cursorProcNames CURSOR
SET @cursorProcNames = CURSOR FOR
select name from sys.procedures where modify_date > '2009-02-05 13:12:15.273' order by modify_date desc
OPEN @cursorProcNames
FETCH NEXT
FROM @cursorProcNames INTO @procName
WHILE @@FETCH_STATUS = 0
BEGIN
set nocount off;
exec sp_HelpText @procName --- or print them
-- print @procName
FETCH NEXT
FROM @cursorProcNames INTO @procName
END
CLOSE @cursorProcNames
select @@error
*/
/* -- SEE STORED PROCEDURE EXT PROPS
SELECT ep.name as 'EXT_PROP_NAME' , SP.NAME , [value] as 'DESCRIPTION' FROM sys.extended_properties as ep left join sys.procedures as sp on sp.object_id = ep.major_id where sp.type='P'
-- what the hell I ve been doing lately on sql server 2005 / 2008
select o.name ,
(SELECT [definition] AS [text()] FROM sys.all_sql_modules where sys.all_sql_modules.object_id=a.object_id FOR XML PATH(''), TYPE) AS Statement_Text
, a.object_id, o.modify_date from sys.all_sql_modules a left join sys.objects o on a.object_id=o.object_id order by 4 desc
-- GET THE RIGHT LANG SCHEMA START
DECLARE @template AS varchar(max)
SET @template = 'SELECT * FROM {object_name}'
DECLARE @object_name AS sysname
SELECT @object_name = QUOTENAME(s.name) + '.' + QUOTENAME(o.name)
FROM sys.objects o
INNER JOIN sys.schemas s
ON s.schema_id = o.schema_id
WHERE o.object_id = OBJECT_ID(QUOTENAME(@LANG) + '.[TestingLanguagesInNameSpacesDelMe]')
IF @object_name IS NOT NULL
BEGIN
DECLARE @sql AS varchar(max)
SET @sql = REPLACE(@template, '{object_name}', @object_name)
EXEC (@sql)
END
-- GET THE RIGHT LANG SCHEMA END
-- SEE STORED PROCEDURE EXT PROPS end*/
set nocount off
GO
EXEC sys.sp_addextendedproperty @name=N'AuthorName', @value=N'Yordan Georgiev' , @level0type=N'SCHEMA',@level0name=N'ga', @level1type=N'PROCEDURE',@level1name=N'procUtils_SqlCheatSheet'
GO
EXEC sys.sp_addextendedproperty @name=N'ProcDescription', @value=N'TODO:ADD HERE DESCRPIPTION' , @level0type=N'SCHEMA',@level0name=N'ga', @level1type=N'PROCEDURE',@level1name=N'procUtils_SqlCheatSheet'
GO
EXEC sys.sp_addextendedproperty @name=N'ProcVersion', @value=N'0.1.0.20090406.1317' , @level0type=N'SCHEMA',@level0name=N'ga', @level1type=N'PROCEDURE',@level1name=N'procUtils_SqlCheatSheet'
GO
/****** Object: UserDefinedFunction [ga].[GetDbVersion] Script Date: 04/22/2009 13:21:42 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [ga].[GetDbVersion]()
RETURNS VARCHAR(20)
BEGIN
RETURN convert(varchar(20) , (select value from sys.extended_properties where name='DbVersion' and class_desc='DATABASE') )
END
GO
EXEC sys.sp_addextendedproperty @name=N'AuthorName', @value=N'Yordan Georgiev' , @level0type=N'SCHEMA',@level0name=N'ga', @level1type=N'FUNCTION',@level1name=N'GetDbVersion'
GO
EXEC sys.sp_addextendedproperty @name=N'ChangeDescription', @value=N'Initial creation' , @level0type=N'SCHEMA',@level0name=N'ga', @level1type=N'FUNCTION',@level1name=N'GetDbVersion'
GO
EXEC sys.sp_addextendedproperty @name=N'CreatedWhen', @value=N'getDate()' , @level0type=N'SCHEMA',@level0name=N'ga', @level1type=N'FUNCTION',@level1name=N'GetDbVersion'
GO
EXEC sys.sp_addextendedproperty @name=N'Description', @value=N'Gets the current version of the database ' , @level0type=N'SCHEMA',@level0name=N'ga', @level1type=N'FUNCTION',@level1name=N'GetDbVersion'
GO
/****** Object: UserDefinedFunction [ga].[GetDbType] Script Date: 04/22/2009 13:21:42 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [ga].[GetDbType]()
RETURNS VARCHAR(30)
BEGIN
RETURN convert(varchar(30) , (select value from sys.extended_properties where name='DbType' and class_desc='DATABASE') )
END
GO
/****** Object: Default [DF_tb_DataMeta_ObjChangeLog_DbVersion] Script Date: 04/22/2009 13:21:40 ******/
ALTER TABLE [ga].[tb_DataMeta_ObjChangeLog] ADD CONSTRAINT [DF_tb_DataMeta_ObjChangeLog_DbVersion] DEFAULT ('select ga.GetDbVersion()') FOR [DbVersion]
GO
/****** Object: Default [DF_tb_DataMeta_ObjChangeLog_EventDate] Script Date: 04/22/2009 13:21:40 ******/
ALTER TABLE [ga].[tb_DataMeta_ObjChangeLog] ADD CONSTRAINT [DF_tb_DataMeta_ObjChangeLog_EventDate] DEFAULT (getdate()) FOR [EventDate]
GO
/****** Object: Default [DF_tb_DataMeta_ObjChangeLog_ObjVersion] Script Date: 04/22/2009 13:21:40 ******/
ALTER TABLE [ga].[tb_DataMeta_ObjChangeLog] ADD CONSTRAINT [DF_tb_DataMeta_ObjChangeLog_ObjVersion] DEFAULT ('0.0.0') FOR [ObjVersion]
GO
/****** Object: DdlTrigger [trigMetaDoc_TraceDbChanges] Script Date: 04/22/2009 13:21:29 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create trigger [trigMetaDoc_TraceDbChanges]
on database
for create_procedure, alter_procedure, drop_procedure,
create_table, alter_table, drop_table,
create_function, alter_function, drop_function ,
create_trigger , alter_trigger , drop_trigger
as
set nocount on
declare @data xml
set @data = EVENTDATA()
declare @DbVersion varchar(20)
set @DbVersion =(select ga.GetDbVersion())
declare @DbType varchar(20)
set @DbType =(select ga.GetDbType())
declare @DbName varchar(256)
set @DbName =@data.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'varchar(256)')
declare @EventType varchar(256)
set @EventType =@data.value('(/EVENT_INSTANCE/EventType)[1]', 'varchar(50)')
declare @ObjectName varchar(256)
set @ObjectName = @data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'varchar(256)')
declare @ObjectType varchar(25)
set @ObjectType = @data.value('(/EVENT_INSTANCE/ObjectType)[1]', 'varchar(25)')
declare @TSQLCommand varchar(max)
set @TSQLCommand = @data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'varchar(max)')
declare @opentag varchar(4)
set @opentag= '<'
declare @closetag varchar(4)
set @closetag= '>'
declare @newDataTxt varchar(max)
set @newDataTxt= cast(@data as varchar(max))
set @newDataTxt = REPLACE ( REPLACE(@newDataTxt , @opentag , '<') , @closetag , '>')
-- print @newDataTxt
declare @newDataXml xml
set @newDataXml = CONVERT ( xml , @newDataTxt)
declare @Version varchar(50)
set @Version = @newDataXml.value('(/EVENT_INSTANCE/TSQLCommand/CommandText/Version)[1]', 'varchar(50)')
-- if we are dropping take the version from the existing object
if ( SUBSTRING(@EventType , 0 , 5)) = 'DROP'
set @Version =( select top 1 [Version] from ga.tb_DataMeta_ObjChangeLog where ObjectName=@ObjectName order by [LogId] desc)
declare @LoginName varchar(256)
set @LoginName = @data.value('(/EVENT_INSTANCE/LoginName)[1]', 'varchar(256)')
declare @FirstName varchar(50)
set @FirstName= (select [FirstName] from [ga].[tb_BLSec_LoginsForUsers] where [LoginName] = @LoginName)
declare @LastName varchar(50)
set @LastName = (select [LastName] from [ga].[tb_BLSec_LoginsForUsers] where [LoginName] = @LoginName)
declare @SchemaName sysname
set @SchemaName = @data.value('(/EVENT_INSTANCE/SchemaName)[1]', 'sysname');
--declare @Description xml
--set @Description = @data.query('(/EVENT_INSTANCE/TSQLCommand/text())')
--print 'VERSION IS ' + @Version
--print @newDataTxt
--print cast(@data as varchar(max))
-- select column_name from information_schema.columns where table_name ='tb_DataMeta_ObjChangeLog'
insert into [ga].[tb_DataMeta_ObjChangeLog]
(
[DatabaseName] ,
[SchemaName],
[DbVersion] ,
[DbType],
[EventType],
[ObjectName],
[ObjectType] ,
[Version],
[SqlCommand] ,
[LoginName] ,
[FirstName],
[LastName]
)
values(
@DbName,
@SchemaName,
@DbVersion,
@DbType,
@EventType,
@ObjectName,
@ObjectType ,
@Version,
@newDataTxt,
@LoginName ,
@FirstName ,
@LastName
)
GO
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
DISABLE TRIGGER [trigMetaDoc_TraceDbChanges] ON DATABASE
GO
/****** Object: DdlTrigger [trigMetaDoc_TraceDbChanges] Script Date: 04/22/2009 13:21:29 ******/
Enable Trigger [trigMetaDoc_TraceDbChanges] ON Database
GO
答案 26 :(得分:3)
仅供参考,Dana日前也提到了这一点...... Stored procedures/DB schema in source control
答案 27 :(得分:3)
RedGate很棒,我们在进行数据库更改时生成新的快照(一个小的二进制文件),并将该文件作为资源保存在项目中。每当我们需要更新数据库时,我们使用RedGate的工具包来更新数据库,以及能够从空数据库创建新数据库。
RedGate也制作了数据快照,虽然我没有亲自与他们合作,但它们同样强大。
答案 28 :(得分:3)
我通过脚本化所有对象(表定义,索引,存储过程等)来控制数据库模式。但是,至于数据本身,只需依靠定期备份。这可确保使用适当的修订历史记录捕获所有结构更改,但每次数据更改时都不会对数据库造成负担。
答案 29 :(得分:3)
这对我来说一直是一个很大的烦恼 - 看起来很容易快速更改你的开发数据库,保存它(忘记保存更改脚本),然后你被卡住了。您可以撤消刚刚执行的操作并重做它以创建更改脚本,或者如果您当然也想从头开始编写它,尽管编写脚本需要花费大量时间。
我过去使用过的一个工具是SQL Delta。它将向您展示两个数据库(我相信的SQL服务器/ Oracle)之间的差异,并生成迁移A-&gt; B所需的所有更改脚本。它的另一个好处是显示生产(或测试)数据库与开发数据库之间的数据库内容之间的所有差异。由于越来越多的应用程序存储对数据库表中执行至关重要的配置和状态,因此使用删除,添加和更改正确行的更改脚本可能会非常痛苦。 SQL Delta显示数据库中的行,就像它们在Diff工具中看到的那样 - 更改,添加,删除。
一个出色的工具。链接在这里: http://www.sqldelta.com/
答案 30 :(得分:3)
我们正在将所有数据库移动到源代码管理。我们正在使用sqlcompare编写数据库脚本(不幸的是专业版功能)并将结果放入SVN。
您的实施成功将取决于您组织的文化和实践。这里的人相信每个应用程序创建一个数据库。大多数应用程序都使用一组通用的数据库,这会导致大量的数据库间依赖关系(其中一些是循环的)。由于我们的系统具有数据库间依赖性,因此将数据库模式放入源代码控制中已经非常困难。
祝你好运,越早尝试就越早解决问题。
答案 31 :(得分:3)
虽然这个问题有很多好的答案,但大多数都没有包括市场上的创新变化,特别是商业工具。
以下是进行数据库版本控制的工具的简短列表,我列出了每个工具的优缺点(完整的披露者:我为DBmaestro工作)
红门 - 已经上市多年。它使用与基于文件的版本控制集成的脚本提供数据库对象的版本控制。DBVS - 使用与基于文件的版本控制集成的脚本提供数据库对象的版本控制。
DBmaestro - 提供对真实数据库对象的版本控制进程(签出/签入)的强制执行。因此,毫无疑问版本控制存储库是否与应用程序使用的数据库同步。
我鼓励您阅读由资深数据库专家Ben Taylor撰写的关于数据库强制变更管理解决方案的全面,公正的评论,他在LinkedIn上发布https://www.linkedin.com/pulse/article/20140907002729-287832-solve-database-change-mangement-with-dbmaestro
答案 32 :(得分:2)
我已经开始研究sqlHawk,其目的是围绕此问题提供(开源)工具。
它目前处于相当早的阶段,但已经支持存储和实施stored procedures并运行脚本更新。
对于有时间查看此工具的人的任何意见,我将不胜感激。
为公然的自我推销道歉,但我希望这对某人有用!
答案 33 :(得分:2)
我同意许多关于ruby的ActiveRecord迁移的帖子 - 它们是一种在每个人都可以共享的小增量文件中管理数据库的优雅方式。话虽如此,我最近使用VisualStudio的数据库项目实现了一个项目,这有点让我成为一个信徒。简短的故事 - 您创建一个数据库项目,将所有(如果有的话)现有数据库对象导入其中(tables / views / triggers / keys / users / etc)。该导入导致每个对象的“创建”脚本。要管理数据库,您需要更改创建脚本,然后在部署VS上将目标数据库与驻留在项目中的数据库状态进行比较,并应用正确的alter语句。
这真的有点神奇,我不得不承认,这是VS团队做得更好的事情之一。到目前为止,我印象非常深刻。
当然,您可以在您选择的版本控制系统中管理整个数据库项目。
答案 34 :(得分:2)
“Short version: dump your production database into a git repository for an instant backup solution.”
答案 35 :(得分:2)
我们使用复制和群集来管理我们的数据库以及备份。我们使用Serena来管理我们的SQL脚本和配置实现。在进行配置更改之前,我们会在更改管理过程中执行备份。此备份满足我们的回滚要求。
我认为一切都取决于规模。您是在谈论需要异地备份和灾难恢复的企业应用程序吗?一个运行会计应用程序的小工作组?或者介于两者之间?
答案 36 :(得分:2)
是的...我们的数据库是在ERwin中设计的,每个版本的DDL都是自动生成的。 ERwin文件保存在我们的源代码控制系统中(实际上,我们的工程文档也是如此)。
答案 37 :(得分:2)
答案 38 :(得分:2)
我总是检查我的数据库结构转储到源代码控制中。完整的数据库转储,但我通常只是压缩和存放。
答案 39 :(得分:2)
我使用RedGate SQL Compare Pro与脚本文件夹进行架构同步,然后我将所有更新提交到版本控制。它很棒。
答案 40 :(得分:2)
RedGate软件提供了一些很棒的工具,可以帮助您对数据库进行版本控制。一定要尝试让你的开发人员为开发工作构建他们自己的独立本地数据库,而不是依赖于“开发服务器”,它可能会在某个时候停止运行。
答案 41 :(得分:2)
我的团队将我们的数据库模式版本化为C#类,其余代码。我们有一个自行开发的C#程序(&lt; 500行代码),它反映了类并创建了用于构建,删除和更新数据库的SQL命令。在创建数据库之后,我们运行sqlmetal来生成linq映射,然后在另一个用于生成测试数据的项目中编译。整个过程非常有效,因为在编译时检查数据访问。我们喜欢它,因为架构存储在.cs文件中,这很容易跟踪trac / svn中的比较。
答案 42 :(得分:2)
我们在源代码管理下拥有Create / Alter脚本。至于数据库本身,当你每分钟有数百个表和大量处理数据时,所有数据库的版本都是CPU和HDD杀手。据我所知,这就是为什么备份仍然是控制数据的最佳方式。
答案 43 :(得分:1)
我版本控制创建脚本,我在其中使用svn版本标记。然后,每当我得到一个将要使用的版本时,我在dbpatches /目录中创建一个脚本,该目录被命名为要汇总的版本。该脚本的工作是在不破坏数据的情况下修改当前数据库。例如,dbpatches /可能包含名为201,220和240的文件。如果数据库当前处于201级,则应用修补程序220,然后应用修补程序240.
DROP TABLE IF EXISTS `meta`;
CREATE TABLE `meta` (
`property` varchar(255),
`value` varchar(255),
PRIMARY KEY (`property`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `meta` VALUES ('version', '$Rev: 240 $');
在考虑补丁之前,不要忘记测试代码。注意事项!
答案 44 :(得分:1)
作为一项规则,我们将所有目标代码(存储过程,视图,触发器,函数等)保存在源代码控制中,因为这些对象是代码,并且就像其他答案一样,代码属于某种形式版本控制系统。
对于CREATE,DROP,ALTER语句等(DDL),我们开发并使用BuildMaster来管理这些脚本的部署,以便它们可以针对目标数据库运行一次且仅运行一次(无论是他们失败或不失败)。一般的想法是开发人员会将更改脚本上传到系统中,当部署时,只会运行尚未针对目标环境的数据库运行的更改脚本(这与{{3}的管理方式非常相似})。脚本类型分离的原因在于,一旦操作表的结构,添加索引等,如果不编写全新的脚本或恢复数据库,您实际上无法撤消它 - 而不是您所在的目标代码可以简单地删除视图或存储过程,然后重新创建它。
例如,当您将生产数据库还原到集成环境中时,系统会自动确切地知道哪些脚本尚未运行,并且会将新恢复的数据库的表结构更改为关于发展的最新情况。
答案 45 :(得分:1)
我们每周都有一个sql转储到subversion repo中。它完全自动化,但这是一个非常强大的任务。
您需要限制修订数量,因为它在一段时间后确实会占用磁盘空间!
答案 46 :(得分:0)
是的,我们使用subversion控制我们的sql脚本。这是一个很好的做法,您可以在需要时使用默认数据重新创建模式。
答案 47 :(得分:0)
我们维护ER工具(PowerAMC)生成的DDL(有时是DML)脚本。
我们有一个shell脚本,可以在trunk分支上以数字开头重命名脚本。 每个脚本都使用bugzilla编号进行提交和标记。
然后需要在发布分支中合并这些脚本以及应用程序代码。
我们有一张表记录脚本及其状态。 每个脚本按顺序执行,并在部署工具的每次安装时记录在此表中。
答案 48 :(得分:0)
我听说有人说你绝对要把你的模式保存在数据库中。我不确定我是否同意。这实际上取决于您正在使用的系统。如果您的系统相对较小且数据不是非常重要。您需要将另一个开发环境置于在线状态的速度至关重要..然后是的...您可以从中受益。但是,如果没有数据并且数据库非常大而您的模式无用,则几乎不可能“控制”您的数据库。当然,您仍然可以将您的DDL代码保留在源代码管理中,但这基本上是无用的。没有备份/恢复,您无法获得所需的数据。
在大型数据库开发工作中,我发现备份和恢复是首选的回滚选项。当然,您可以在源代码管理中保留procs,视图,函数等,但不需要保留table.sql。此外,如果您的部署过程是密不透风的,那么您很可能永远不必“回滚”您的生产环境。
答案 49 :(得分:0)
对于oracle,我使用自编的java程序oracle-ddl2svn来自动跟踪SVN中oracle DDL方案的变化
答案 50 :(得分:0)
我们坚持更改scrips和主数据定义脚本。这些被检入CVS以及任何其他源代码。 PL / SQL(是Oracle商店)也是CVS的源代码控制。更改脚本是可重复的,可以传递给团队中的每个人。基本上,仅仅因为它是一个数据库,从来没有理由不对它进行编码并使用源控制系统来跟踪变化。
答案 51 :(得分:0)
Kira的主要用例之一是数据库升级,方法是将数据库外部的模式明确指定为代码。然后,它可以管理数据库并将其升级到任何版本的任何版本。
答案 52 :(得分:0)
我使用ActiveRecord Migrations。这个Ruby gem可以在Rails项目之外使用,并且有适配器可以处理你会遇到的大多数数据库。我的提示:如果您能够在Postgres上运行项目,那么您将获得事务模式迁移。这意味着如果迁移仅适用于一半,则不会导致数据库损坏。
答案 53 :(得分:0)
可悲的是,我看到不止一个团队正在开发PL / SQL程序(Oracle中的存储过程) - 有时是数万个LOC - 只需编辑TOAD(数据库工具)中的代码,甚至不用将源保存到文件中(部署除外)。即使数据库是经常备份的(虽然不会认为这是理所当然的),但是检索旧版本存储过程的唯一方法是恢复整个数据库,这个数据库很大。当然,当多个开发人员在同一个项目上工作时,有时一个文件中的并发更改会导致工作丢失。
答案 54 :(得分:0)
您的项目团队可以拥有一个DBA,每个开发人员都会转发他们的创建更改,删除,插入/更新(用于主数据)sql语句。 DBA将运行这些查询并成功进行所需的更新,将这些语句添加到文本文件或电子表格中。每个添加都可以标记为保存点。如果你恢复到特定的保存点,只需执行一次删除操作并运行查询,直到标记的保存点。这种方法只是一个想法...这里的一些微调可以适用于您的开发环境。
答案 55 :(得分:0)
任何数据库接口代码绝对应该进入版本控制(存储过程,函数等)。
对于结构和数据,它是一个判断调用。我个人保留了我的数据库的一个干净的结构模板,但由于它的大小,不要将它们存储在版本控制中。但是将其存储在版本控制中可能非常有用,即使只是有历史记录。
答案 56 :(得分:0)
是的,当然。每当发生变化时我们都会生成PostgreSQL模式的转储并将其检入。它已经多次保存了我,而且我只在几个月的工作中工作过。
答案 57 :(得分:0)
一个经常被忽视的大问题是,对于较大的基于Web的系统,需要采用过渡期或桶测试方法来制作新版本。这使得必须同时具有回滚和支持同一DB中的新旧模式的机制。这需要一种脚手架方法(由Agile DB人员制作民粹主义者)。在这种情况下,数据库源控制中缺少进程可能是一场灾难。一旦系统完全使用新版本(或回滚),您就需要旧的模式脚本,新的模式脚本和一组中间脚本,以及整理。
不是让脚本从头开始重新创建模式,而是需要基于状态的方法,在这种方法中,您需要脚本纯粹是为了将数据库从版本移动到版本,从前向移动到所需的状态。您的数据库成为一系列状态脚本,可以很容易地对其进行源代码控制和标记。