西拉免费代理IP

你当前的位置:西拉免费代理IP   >   新闻中心   >   将数据库从开发迁移到研发

将数据库从开发迁移到研发

来源: 西拉IP   作者: 张祁无   2018年12月20日 15:22

如果您在一家小公司工作,那么您的开发,测试和生产数据库可能位于同一台服务器上。但是,大多数组织都意识到与此类设置相关的风险。如果您的服务器因磁盘故障或停电而变得无法使用,您不仅会损失当前客户的业务,还会损失宝贵的开发时间。如果您使用生产数据库进行开发并且开发人员犯了错误,那么您的在线客户将不得不等到从备份恢复生产数据库。最重要的是,不应该在生产服务器上进行认真的开发。应在一台服务器上开发应用程序,在另一台服务器(有时称为质量保证服务器)上的类似生产的环境中进行测试,然后将其部署到生产服务器。

数据库的初始迁移很容易; 您只需在开发服务器上备份数据库并在生产服务器上将其还原。但是,如果您对已部署的应用程序进行了后续发布或增强,会发生什么?那么,备份和恢复不再是一种选择 - 您将丢失生产中收集的所有数据。只有当您的数据库结构在所有服务器上都相同时,DTS才有用。在大多数情况下,您的数据库结构将从一个版本更改为下一个版本; 因此,您需要某种类型的机制来比较两台服务器上的数据库,并提出同步它们的计划。在本文中,我将为您提供一个脚本,用于比较两台服务器上的表,索引和约束,并生成一个全面的差异报告。

正如您可能猜到的,诀窍在于检查系统表和/或信息架构视图。脚本本身并不是非常复杂,但如果您的情况需要比较数据库结构,它将为您开发自己的解决方案提供良好的开端。一旦了解了数据库结构之间的差异,就可以使用脚本对生产数据库进行适当的更改,并从开发环境中传输/转换其他数据。

以下脚本比较了测试服务器上的开发和生产数据库。如果必须比较同一服务器上的两个数据库,请替换数据库名称。如果您有单独的服务器,则必须将远程服务器设置为链接服务器,并修改此脚本以查询远程数据库。有关详细信息,请参阅内联注释

SET NOCOUNT ON
DECLARE @table_name VARCHAR(100),
@index_name VARCHAR(100),
@sql VARCHAR(4000)

-- temp tables to keep intermediate values:
CREATE TABLE #dev_columns (
table_name VARCHAR(100) NULL,
column_id INT NULL,
column_name VARCHAR(100) NULL,
data_type VARCHAR(100) NULL,
length INT,
nullable BIT)

CREATE TABLE #production_columns (
table_name VARCHAR(100) NULL,
column_id INT NULL,
column_name VARCHAR(100) NULL,
data_type VARCHAR(100) NULL,
length INT,
nullable BIT)

CREATE TABLE #dev_indexes (
table_name VARCHAR(100),
index_name VARCHAR(100),
column_name VARCHAR(100),
ordinal_position_of_column INT,
isclustered BIT)

CREATE TABLE #production_indexes (
table_name VARCHAR(100),
index_name VARCHAR(100),
column_name VARCHAR(100),
ordinal_position_of_column INT,
isclustered BIT)

CREATE TABLE #dev_constraints (
table_name VARCHAR(100),
constraint_type VARCHAR(25),
constraint_name VARCHAR(100),
column_name VARCHAR(100),
constraint_value VARCHAR(255))

CREATE TABLE #production_constraints (
table_name VARCHAR(100),
constraint_type VARCHAR(25),
constraint_name VARCHAR(100),
column_name VARCHAR(100),
constraint_value VARCHAR(255))

-- get all columns, indexes, and constraints from first db:
USE Development
DECLARE table_cursor CURSOR FOR
SELECT name
FROM Development.dbo.sysobjects
WHERE type = 'u'
AND name <> 'dtproperties'
ORDER BY 1

OPEN table_cursor
FETCH NEXT FROM table_cursor
INTO @table_name
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @sql = 'INSERT #dev_columns (
table_name ,
column_id ,
column_name ,
data_type ,
length ,
nullable )

SELECT ''' + @table_name + ''' ,
colid, a.name,
b.name,
a.length,
a.isnullable
FROM syscolumns a
INNER JOIN systypes b
ON a.xtype = b.xtype
and a.xusertype = b.xusertype
WHERE
a.id = OBJECT_ID(''' + @table_name + ''')'
EXEC(@sql)

SELECT @sql = ' '

SELECT @sql = 'INSERT #dev_indexes
SELECT DISTINCT b.name AS table_name,
a.name AS index_name,
d.name AS column_name,
c.keyno AS ordinal_position_of_column,
''CLUSTERED'' = CASE
WHEN a.indid = 1 THEN 1
ELSE 0
END
FROM sysindexes a INNER JOIN sysobjects b
ON a.id = b.id
AND b.type = ''u''
and b.name <> ''dtproperties''
INNER JOIN sysindexkeys c
ON a.indid = c.indid AND c.id = b.id
INNER JOIN syscolumns d
ON d.colid = c.colid
AND d.id = b.id
WHERE a.indid <> 0
AND a.indid <> 255
AND a.name NOT LIKE ''_wa%''
AND b.name = ''' + @table_name + '''
ORDER BY 1, 2, 4'
EXEC(@sql)

SELECT @sql = ' '

SELECT @sql = 'INSERT #dev_constraints
SELECT b.name AS table_name,
constraint_type =
CASE
WHEN a.type = ''c''
THEN ''CHECK''
WHEN a.type = ''d''
THEN ''DEFAULT''
END,
a.name AS constraint_name,
COL_NAME(b.id, a.info)
AS column_name,
c.text AS constraint_value
FROM sysobjects a
INNER JOIN sysobjects b
ON b.id = a.parent_obj
LEFT JOIN syscomments c
ON c.id = a.id
WHERE a.type IN (''c'', ''d'')
AND b.name = ''' + @table_name +''''

EXEC(@sql)

FETCH NEXT FROM table_cursor
INTO @table_name
END
CLOSE table_cursor
DEALLOCATE table_cursor
-- get all columns, indexes, and constraints from second db:
USE Production

/*******************************************
* if using a remote server then remove
* "USE production" statement and use
* four-part identifier for querying
* the tables, as in following
*
* SELECT name
* FROM
* linked_server.remote_database.dbo.sysobjects
****************************************
*/
DECLARE table_cursor CURSOR FOR
SELECT name FROM Production.dbo.sysobjects
WHERE type = 'u'
AND name <> 'dtproperties'
ORDER BY 1

OPEN table_cursor
FETCH NEXT FROM table_cursor INTO @table_name
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @sql = 'INSERT #production_columns (
table_name ,
column_id ,
column_name ,
data_type ,
length ,
nullable )

SELECT ''' + @table_name + ''' ,
colid,
a.name,
b.name,
a.length,
a.isnullable
FROM syscolumns a INNER JOIN systypes b
ON a.xtype = b.xtype
and a.xusertype = b.xusertype
WHERE a.id = OBJECT_ID(''' + @table_name + ''')'

EXEC(@sql)

SELECT @sql = ' '

SELECT @sql = 'INSERT #production_indexes
SELECT
DISTINCT
b.name AS table_name,
a.name AS index_name,
d.name AS column_name,
c.keyno AS ordinal_position_of_column,
'CLUSTERED' =
CASE
WHEN a.indid = 1 THEN 1
ELSE 0
END
FROM sysindexes a
INNER JOIN sysobjects b
ON a.id = b.id
AND b.type = ''u''
INNER JOIN sysindexkeys c
ON a.indid = c.indid AND c.id = b.id
INNER JOIN syscolumns d
ON d.colid = c.colid AND d.id = b.id
WHERE a.indid <> 0
AND a.indid <> 255
AND a.name NOT LIKE ''_wa%''
AND b.name = ''' + @table_name + '''
ORDER BY 1, 2, 4'

EXEC(@sql)

SELECT @sql = ' '

SELECT @sql = 'INSERT #production_constraints
SELECT b.name AS table_name,
constraint_type =
CASE
WHEN a.type = ''c''
THEN ''CHECK''
WHEN a.type = ''d''
THEN ''DEFAULT''
END,
a.name AS constraint_name,
COL_NAME(b.id, a.info)
AS column_name,
c.text AS constraint_value
FROM sysobjects a INNER JOIN sysobjects b
ON b.id = a.parent_obj
LEFT JOIN syscomments c ON c.id = a.id
WHERE a.type IN (''c'', ''d'')
AND
b.name = ''' + @table_name +''''

EXEC(@sql)

FETCH NEXT FROM table_cursor INTO @table_name

END
CLOSE table_cursor
DEALLOCATE table_cursor

-- now compare the values:
SELECT 'the following tables are in development, but not in production database:'
SELECT DISTINCT table_name FROM #dev_columns
WHERE table_name NOT IN
(SELECT table_name FROM #production_columns)

SELECT 'the following tables are in production, but not in development database:'
SELECT DISTINCT table_name
FROM #production_columns
WHERE table_name
NOT IN (SELECT table_name FROM #dev_columns)

SELECT 'the following columns are in development, but not in production database:'
SELECT a.* FROM #dev_columns a
WHERE a.column_name
NOT IN (SELECT column_name
FROM #production_columns b
WHERE a.table_name = b.table_name)

SELECT 'the following columns are in production, but not in development database:'
SELECT a.* FROM #production_columns a
WHERE a.column_name NOT IN
(SELECT column_name FROM #dev_columns b
WHERE a.table_name = b.table_name)

SELECT 'the following columns have varying data types, length or nullability:'
SELECT
DISTINCT
a.table_name,
a.column_name,
a.data_type AS dev_dt,
a.length AS dev_length,
a.nullable AS dev_nullability,
b.data_type AS production_dt,
b.length AS production_length,
b.nullable AS production_nullability
FROM #dev_columns a
INNER JOIN #production_columns b ON
a.column_name = b.column_name
AND
a.table_name = b.table_name
AND
(a.data_type <> b.data_type
OR
a.length <> b.length
OR
a.nullable <> b.nullable)
ORDER BY 1

DROP TABLE #dev_columns, #production_columns

SELECT 'the following tables have indexes in dev, but not
production:'
SELECT DISTINCT table_name
FROM #dev_indexes
WHERE table_name
NOT IN (SELECT table_name
FROM #production_indexes)

SELECT 'the following tables have indexes in production, but
not dev:'
SELECT DISTINCT table_name
FROM #production_indexes
WHERE table_name
NOT IN (SELECT table_name FROM #dev_indexes)

SELECT 'the following indexes appear in dev, but not in
production:'
SELECT * FROM #dev_indexes a
WHERE index_name NOT IN
(SELECT index_name
FROM #production_indexes b
WHERE a.table_name = b.table_name)

SELECT 'the following indexes appear in production, but not in development:'
SELECT * FROM #production_indexes a
WHERE index_name NOT IN
(SELECT index_name FROM #dev_indexes b
WHERE a.table_name =
b.table_name)

SELECT 'the ordinal position of columns is different in
following indexes:'
SELECT
a.table_name,
a.index_name,
a.ordinal_position_of_column as 'dev_position',
b.ordinal_position_of_column as 'production_position'
FROM #dev_indexes a
INNER JOIN #production_indexes b ON
a.table_name = b.table_name
AND
a.index_name = b.index_name
AND
a.column_name = b.column_name
AND
a.ordinal_position_of_column <>
b.ordinal_position_of_column

SELECT 'the following indexes are clustered in development
but not in production, or vice versa:'
SELECT
a.table_name,
a.index_name,
a.isclustered AS isclustered_in_dev,
b.isclustered AS isclustered_in_production
FROM #dev_indexes a
INNER JOIN #production_indexes b ON
a.table_name = b.table_name
AND
a.index_name = b.index_name
AND
a.isclustered <> b.isclustered

DROP TABLE #dev_indexes, #production_indexes

SELECT 'the following constraints appear in development,
but not in production:'
SELECT * FROM #dev_constraints WHERE constraint_name
NOT IN
(SELECT DISTINCT constraint_name
FROM #production_constraints)

SELECT 'the following constraints appear in production but not in development:'
SELECT * FROM #production_constraints
WHERE constraint_name NOT IN
(SELECT DISTINCT constraint_name
FROM #dev_constraints)

DROP TABLE #dev_constraints, #production_constraints

读者评论:我发现在链接服务器上调用OBJECT_ID函数不起作用,你可以更改添加前缀。但是你可以修改格式的两行:

WHERE a.id = OBJECT_ID('''+ @ table_name +''')'

...to be like:

WHERE a.id = (
SELECT id
FROM server2.db_name.dbo.sysobjects
WHERE name = ''' + @table_name + '''
)'

阅读 446   

相关推荐

全世界最大的APT组织发起的APT通缉,算不算是APT? 全世界最大的APT组织发起的APT通缉,算不算是APT?
全世界最大的APT组织发起的APT通缉,算不算是APT?

APT(Advanced Persistent Threat)是指高级持续性威胁。 利用先进的攻击手段对特定目标进行长期持续性网络攻击的攻击形式。 . . .

2018年12月21日
黑客都是怎么检查电脑是否中病毒! 黑客都是怎么检查电脑是否中病毒!
黑客都是怎么检查电脑是否中病毒!

电脑病毒相信大家都不陌生,现在的病毒已经从以前的破坏电脑程序到如今的偷偷窃取用户隐私信息,实在是可恶至极。今天来教大家检查电脑是否中病毒。 . . .

2018年12月20日
WebSocket WebSocket
WebSocket

WebSocket是一种通信协议,用于从用户的Web浏览器到服务器的持久,双向,全双工 TCP连接。 . . .

2018年12月20日
逆向 | 指针、数组、结构体与对象 逆向 | 指针、数组、结构体与对象
逆向 | 指针、数组、结构体与对象

从逆向的角度去理解数组与指针,并学习怎样识别它们,从而能以多个角度去理解C语言中较为复杂的指针问题。 我们先看一段分别以数组下标和指针方式访问数据的代码,如代码清单1所示。 . . .

2018年12月20日
使用查询来记录SQL Server数据库

您是否知道可以使用查询来记录SQL Server数据库?这个关于系统表的简单查询就是这样做的。您可以轻松地将结果剪切并粘贴到Word文档中,并改善外观。想象一下你将节省的打字数量!我使用此查询 . . .

2018年12月20日
如何使用SQL查询来记录数据库

您是否知道可以使用SQL查询来记录SQL Server 2000数据库?这个关于系统表的简单查询就是这样做的。您可以轻松地将结果剪切并粘贴到Word文档中,并改善外观。想象一下你将节省的打字数 . . .

2018年12月20日
Microsoft的网络访问保护可以确保安全合规性

计算机安全一直是关于更新和限制的。更新确保计算机具有适当的补丁和软件版本以防止恶意代码,而限制(无论是通过网络还是系统控制)确保只允许在计算环境中发生预先批准的行为。 但安全 . . .

2018年12月19日
了解Microsoft的网络访问保护的内部和外部组件 了解Microsoft的网络访问保护的内部和外部组件
了解Microsoft的网络访问保护的内部和外部组件

Microsoft的网络访问保护是一种复杂的安全解决方案,而不是简单的“下一步,下一步完成”IT项目。它需要集成多个组件,并了解这些组件 - 以及它们连接的方式和原因 - 将为您设计最适合您业 . . .

2018年12月19日
Microsoft网络策略和访问服务(Microsoft NPAS)

Microsoft网络策略和访问服务(Microsoft NPAS)是Windows Server 2008和Windows Server 2012中的服务器角色,允许管理员提供本地和远程网络 . . .

2018年12月19日
MX记录(邮件交换记录)

MX记录(邮件交换记录)是域名系统(DNS)服务器记录,其中包含有关域用于接收邮件的邮件服务器的信息。 当存在托管邮件过滤过程时,MX记录可指向邮件服务器或 代理 . . .

2018年12月19日

新闻中心 代理分享 | 蜘蛛地图

全网最大的免费网页代理ip平台,提供大量免费http代理服务器免费ip代理地址

© 2016 - 2021. 西拉免费代理ip, All rights reserved. 鄂ICP备18017015号-4

在线客服