帮酷LOGO
  • 显示原文与译文双语对照的内容
文章标签:复制  transaction  setup  SET  repl  dba  DAYS  交易  


最近,我们需要在生产环境中执行修补程序升级。 在修复提升中,开发应用程序的供应商已经经做了一些重大改进,以修复应用程序上的Bug 。 在启动修补程序之前,我们需要将LogShipping以及事务性复制中断。 将应用修补程序的数据库大小大约为 90 GB 。 重新设置LogShipping并不是一个难问的问题,但是重新设置事务复制又让我们困难了。 in是位于孟买的larsen& Toubro tk高级 SQL Server DBA,深入讨论了在连续连续工作几天之后,他采用的方法,最终使他成功地成功。

SQL Server 版本

发布服务器:OLTP服务器,SQL Server 2005,服务包 3,32内存,8 cpu

订阅服务器:报告数据库服务器,SQL Server 2005,服务 Pack3,16 GB RAM,12 cpu

上提到的服务器都位于美国的同一数据中心。 仅供参考,订阅服务器是报表服务器,它每 15分钟通过事务复制从OLTP服务器接收数据。 同时,在设置事务性复制时,确定分发数据库将承载在OLTP服务器本身上。

要注意的一点是,在订阅服务器 换句话说,上,我们创建了大量的索引,以获得更好的Select语句性能。 在开始修复补丁之前,我确保我拥有所有索引的备份。 在对数据库执行以下查询后,我执行以下查询,针对名为 ABC ( 复制中涉及的数据库)的数据库,并驻留在订阅服务器( 报告数据库服务器) 上。然后,我决定将现有数据库中存在的所有 SQL Server 索引备份到报告服务器上。 为这里,在订阅服务器的例如 报告服务器上对名为ABC的数据库执行下面的T-SQL 。

//SELECT 
ixz.object_id,
tablename = QUOTENAME(scmz.name) + '.' + QUOTENAME((OBJECT_NAME(ixz.object_id))),
tableid = ixz.object_id,
indexid = ixz.index_id,
indexname = ixz.name, 
isunique = INDEXPROPERTY (ixz.object_id,ixz.name,'isunique'),
isclustered = INDEXPROPERTY (ixz.object_id,ixz.name,'isclustered'),
indexfillfactor = INDEXPROPERTY (ixz.object_id,ixz.name,'indexfillfactor')INTO #tmp_indexesFROM sys.indexes ixzINNERJOIN sys.objects obzON ixz.object_id = obz.object_id INNERJOIN sys.schemas scmzON obz.schema_id = scmz.schema_id WHERE ixz.index_id> 0AND ixz.index_id <255---- 0 = HEAP index, 255 = TEXT columns index--AND INDEXPROPERTY (ixz.object_id,ixz.name,'ISUNIQUE') = 0 ANDINDEXPROPERTY (ixz.object_id,ixz.name,'ISCLUSTERED') = 0ALTERTABLE #tmp_indexes ADD keycolumns VARCHAR(4000), includes VARCHAR(4000)GODECLARE@isql_keyVARCHAR(4000), @isql_inclVARCHAR(4000),@tableidINT, @indexidINTDECLARE index_cursor CURSORFORSELECT 
tableid, 
indexid FROM #tmp_indexes OPEN index_cursorFETCH NEXT FROM index_cursor INTO@tableid, @indexidWHILE@@FETCH_STATUS <> -1BEGINSELECT@isql_key = '', @isql_incl = ''SELECT--ixz.name, colz.colid, colz.name, ixcolz.index_id, ixcolz.object_id, *--key column@isql_key = CASE ixcolz.is_included_column WHEN0THENCASE ixcolz.is_descending_key WHEN1THEN@isql_key + COALESCE(colz.name,'') + ' DESC, 'ELSE@isql_key + COALESCE(colz.name,'') + ' ASC, 'ENDELSE@isql_keyEND,@isql_incl = CASE ixcolz.is_included_column WHEN1THENCASE ixcolz.is_descending_key WHEN1THEN@isql_incl + COALESCE(colz.name,'') + ', 'ELSE@isql_incl + COALESCE(colz.name,'') + ', 'ENDELSE@isql_inclENDFROM sysindexes ixzINNERJOIN sys.index_columns AS ixcolz ON (ixcolz.column_id> 0AND ( ixcolz.key_ordinal> 0OR ixcolz.partition_ordinal = 0OR ixcolz.is_included_column!= 0)
) AND ( ixcolz.index_id=CAST(ixz.indid ASINT) AND ixcolz.object_id=ixz.id
)INNERJOIN sys.columns AS colz ON colz.object_id = ixcolz.object_id AND colz.column_id = ixcolz.column_idWHERE ixz.indid> 0AND ixz.indid <255AND (ixz.status & 64) = 0AND ixz.id = @tableidAND ixz.indid = @indexidORDERBY 
ixz.name, CASE ixcolz.is_included_column WHEN1THEN ixcolz.index_column_id ELSE ixcolz.key_ordinal END--remove any trailing commas from the cursor resultsIF LEN(@isql_key)> 1SET@isql_key = LEFT(@isql_key, LEN(@isql_key) -1)IF LEN(@isql_incl)> 1SET@isql_incl = LEFT(@isql_incl, LEN(@isql_incl) -1)--put the columns collection into our temp tableUPDATE #tmp_indexes SET keycolumns = @isql_key,
includes = @isql_inclWHERE tableid = @tableidAND indexid = @indexidFETCH NEXT FROM index_cursor INTO@tableid,@indexidEND--WHILECLOSE index_cursorDEALLOCATE index_cursorDELETEFROM #tmp_indexes WHERE keycolumns = ''SETNOCOUNTONSELECT'IF NOT EXISTS(SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N''' + ' ti.TABLENAME + '''' + ') AND name = N' + '''' + ti.INDEXNAME + '''' + ')' + '' + 
'CREATE' 
+ CASE WHEN ti.ISUNIQUE = 1 THEN 'UNIQUE' ELSE '' END 
+ CASE WHEN ti.ISCLUSTERED = 1 THEN 'CLUSTERED' ELSE '' END 
+ 'INDEX' + QUOTENAME(ti.INDEXNAME) 
+ 'ON' + (ti.TABLENAME) + ''+ '(' + ti.keycolumns + ')' 
+ CASE 
WHEN ti.INDEXFILLFACTOR = 0 AND ti.ISCLUSTERED = 1 AND INCLUDES = '' 
THEN/*ti.Filter_Definition +*/'WITH (SORT_IN_TEMPDB = OFF) ON [SECONDARY]'WHEN INDEXFILLFACTOR = 0 AND ti.ISCLUSTERED = 0 AND ti.INCLUDES = '' 
THEN/*ti.Filter_Definition +*/'WITH (ONLINE = OFF, SORT_IN_TEMPDB = OFF) ON [SECONDARY]' 
WHEN INDEXFILLFACTOR <> 0 AND ti.ISCLUSTERED = 0 AND ti.INCLUDES = '' 
THEN/*ti.Filter_Definition +*/'WITH (ONLINE = OFF, SORT_IN_TEMPDB = OFF, 
 FILLFACTOR = ' + CONVERT(VARCHAR(10),ti.INDEXFILLFACTOR) + ') ON [SECONDARY]'WHEN INDEXFILLFACTOR = 0 AND ti.ISCLUSTERED = 0 AND ti.INCLUDES <> '' 
THEN ' INCLUDE ('+ti.INCLUDES+') WITH (ONLINE = OFF, SORT_IN_TEMPDB = OFF) ON [SECONDARY]'ELSE ' INCLUDE('+ti.INCLUDES+') WITH (FILLFACTOR = ' + CONVERT(VARCHAR(10),
 ti.INDEXFILLFACTOR) + ', ONLINE = OFF, SORT_IN_TEMPDB = OFF) ON [SECONDARY]'END
FROM #tmp_indexes ti
JOIN sys.indexes i ON ti.Object_id = i.object_id and ti.indexname = i.name
JOIN sys.filegroups fg on i.data_space_id = fg.data_space_id
WHERE LEFT(ti.tablename,3) NOT IN ('sys', 'dt_') --exclude system tables
ORDER BY 
ti.tablename, 
ti.indexid, 
ti.indexname 
DROP TABLE #tmp_indexes
//

执行上述sql后,我得到了保存到服务器本身特定位置的所有索引的索引生成脚本。 如果你只是想移动索引索引本身,我们将移动 SQL Server 索引,这是因为聚集索引本身是数据页本身,因此它将移动一个单独的驱动器,从而使索引保持移动。

修补程序升级后,我开始用更改恢复。 因为大多数业务用户严重依赖于报告,所以我决定首先设置事务复制,因为这很重要。 由于数据库OLTP数据库大小大约为 90 GB,所以我决定使用"没有快照的复制"。

我首先使用发布服务器创建发布服务器,创建发布服务器,我指示系统需要初始化备份集的备份。

然后我使用下面的T-SQL对OLTP服务器上的数据库进行了完整备份。

//backupdatabase ABC to disk='E:Microsoft SQL ServerMSSQLBackupUserABCt_Full_Backup_After_HotFix.bak' 
//
The IP Address of the OLTP Server was 10.1.1.1Once the FullBackup got completed, I started restoring the same on the Reporting Server using the below T-SQL.
//RESTOREDATABASE ABCFROM DISK='10.1.1.1UserABC_Full_Backup_After_HotFix.bak'WITH MOVE 'ABC'TO'D:Microsoft SQL ServerMSSQL.1MSSQLDataABC.mdf',
MOVE 'ABC_Log'TO'L:Microsoft SQL ServerMSSQL.1MSSQLDataABC_1.ldf',
stats=10,NORECOVERY 
//

完整备份使用NORECOVERY模式还原,以便在它的上应用其他备份。

将完整备份还原到报表服务器时,我开始使用下面的sql语句在OLTP服务器本身上开始差异备份。

//backupdatabase ABC to disk='E:Microsoft SQL ServerMSSQL
 BackupUserABC_Differential_Backup_After_HotFix.bak'with differential 
//

完成完整备份后,我开始使用下面的sql将差异备份还原到报表服务器上的数据库。

//RESTOREDATABASE ABCFROM DISK='10.1.1.1UserABC_Differential_Backup_After_HotFix.bak'WITH MOVE 'ABC'TO'D:Microsoft SQL ServerMSSQL.1MSSQLDataABC.mdf',
MOVE 'ABC_Log'TO'L:Microsoft SQL ServerMSSQL.1MSSQLDataABC_1.ldf',
stats=10,NORECOVERYGO//

在还原差异备份之后,我开始使用下面的sql在OLTP服务器上的数据库的事务日志备份。

//backup log ABC to disk='E:Microsoft SQL ServerMSSQLBackupUserABC_Transactional_Backup_After_HotFix.bak' 
//

然后,在报告服务器上将事务日志备份还原到名为ABC的数据库上,使用下面的。

//RESTOREDATABASE ABC FROM DISK='10.1.1.1UserABC_Transactional_Backup_After_HotFix.bak'WITH MOVE 'ABC'TO'D:Microsoft SQL ServerMSSQL.1MSSQLDataABC.mdf',
MOVE 'ABC_Log'TO'L:Microsoft SQL ServerMSSQL.1MSSQLDataABC_1.ldf',
stats=10GO 
//

订阅者在订阅服务器上命名为ABC之后,我决定使用下面的sql语句在OLTP服务器上创建订阅服务器。

//exec sp_addsubscription @publication = N'ABC',@subscriber = N'KUS1111',@destination_db = N'ABC',@subscription_type = N'Push',@sync_type = N'initialize with backup',@article = N'all',@update_mode = N'read only',@subscriber_type = 0,@backupdevicetype ='disk',@backupdevicename='10.1.1.1UserABC_Transactional_Backup_After_HotFix.bak' 
//

执行上述查询后,我收到下面的错误消息:

同步从指定备份创建的nosync订阅所需的事务在分发服务器上不可用。

在这个阶段,我意识到不要对报表服务器上的完全备份还原差异和事务性日志备份。 然后我决定在OLTP服务器上创建发布服务器,指示它初始化备份集中的备份,在报表服务器上还原完整备份,然后创建订阅服务器。

实现上述逻辑后,我成功创建了订阅服务器,但当我查看同步状态时,系统threwed出现以下错误消息:

"abc中的Primary主键约束Violation冲突"

在这个阶段,我对技术的异常行为非常困惑。 我在检查数据库时,发现在数据库中运行了t 小时,但是我惊讶地看到了数据库的代码。 触发器的T-SQL在它的顶部没有"不用于复制"子句。 我认为这可以能是一些触发器,但是我非常惊讶的是整个数据库中的"不用于复制"子句在代码上。 由于特定表生成了重复的entires,因这里日志读取器代理生成一个条目,因这里与主键约束冲突。

然后,我决定针对报表服务器上名为ABC的数据库,所有触发器都应该禁用,以便复制过程能够正常工作。

然后,我更改了在OLTP和报告数据库服务器之间设置事务性复制的策略,如下所示:

  • 在OLTP服务器上创建发布服务器并指示它从备份集初始化备份。
  • 在OLTP服务器上,对名为ABC的数据库进行完整备份。
  • 在报表服务器上,还原完整备份。
  • 在报表服务器上生成一个脚本,使报表服务器上的所有触发器都使用下面的sql语句。
//SelectDistinct'DISABLE TRIGGER ALL ON [' +object_name(parent_obj) + ']' + char(10) + 'GO'from sysobjects where parent_obj in (select objidfrom sysarticles) and xtype in ('TR', 'TA')
//
  • 上面的查询在报告服务器上针对名为ABC的数据库执行,所有的触发器都被禁用。
  • 通过在OLTP服务器上执行下面的T-SQL查询来创建订阅,方法是使用下面的T-SQL查询。
exec sp_addsubscription@publication = N'ABC',@subscriber = N'Name of the Reporting Server',@destination_db = N'ABC',@subscription_type = N'Push',@sync_type = N'initialize with backup',@article = N'all',@update_mode = N'read only',@subscriber_type = 0,@backupdevicetype ='disk',@backupdevicename = Path and name of the FullBackup taken on the OLTP Server'

这是我在OLTP和报告环境之间设置事务性复制的一种方法。 我真诚感谢所有的观众在阅读文章时提供宝贵的时间。 如果你有任何建议请告知我们。



文章标签:rep  SET  repl  setup  transaction  复制  DAYS  dba  

Copyright © 2011 HelpLib All rights reserved.    知识分享协议 京ICP备05059198号-3  |  如果智培  |  酷兔英语