切換步驟:
1、停服(如果可以停的話)
2、禁用寫賬號
3、kill進程
4、禁用日誌備份job,自動傳送日誌job,日誌還原job
5、手動執行備份日誌存儲過程,備份最後一次尾日誌
6、手動執行自動傳送日誌備份
7、手動執行最後日誌還原存儲過程
8、檢查最後日誌還原節點
9、如果正確,改成recovery模式,通知開發人員改連接ip或者域名配置
10、如果一切驗證都ok,切換完畢,如果有job啓用job,後期做全備,日誌備份,搭建備庫等等後續工作
11、如果有問題,改回原來ip或者域名配置,啓用原來寫賬號,重新備份數據庫,還原數據庫,啓用日誌備份、傳輸、還原job,等待下一次切換
1.首先查看數據庫還原情況,查看指定的庫的日誌追加情況
select physical_device_name from msdb.dbo.backupmediafamily with(nolock) where physical_device_name like '%Summary_12_202002%' order by media_set_id desc
2.停止程序寫入
3.kill進程 運行下面2段sql ,然後執行
sp_block
go
select 'kill ' + ltrim(rtrim(str(spid))) from ##block where DBname='切換庫名'
然後kill掉第二個結果的數據
然後在執行一遍,查看是否有未殺死的
sp_block
go
select 'kill ' + ltrim(rtrim(str(spid))) from ##block where DBname='切換庫名'
USE [master] GO /****** Object: StoredProcedure [dbo].[sp_block] Script Date: 09/27/2013 14:17:48 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[sp_block] @status [varchar](50) = '', @is_output [tinyint] = 1 WITH encryption AS /********************** {VER EDITOR DATE COMMENT } REMARK: 1. 系統進程本身沒有connection,一個sesstion對應一個connection 2. insert data有嚴格的順序 3. 如果sys.dm_exec_requests的列值爲null,表明此requests已經不存在,session_status爲sleeping 4. if a spid is blocking and is blocked,it belong to blocked,but the blocking count has value. 5. if the sp get error info like "The statement terminated. The maximum recursion 100 has been exhausted before statement completion.",then it indicate a deadlock happened,like this: "Transaction (Process ID 67) was deadlocked on lock resources with anot her process and has been chosen as the deadlock victim. Rerun the transaction. 6. sleeping: last_request_end_time>=last_request_start_time 7. 有時查詢結果的數據出現不一致的情況,比如type=sleeping,而status=running,原因是此sp內部多次查詢的時間差 8. 不論@status輸入參數如何,blocking和blocked總是顯示,可以用此特性只顯示blocking和blocked 9. Will only display the blocking spid's query plan. 10. Will filter current spid,but if the current spid is blocking or blocked ,it will display. 11. 系統進程被阻塞,也會顯示 12. session_status 有時不匹配 request_status,原因:存在髒讀;或讀取時間不一致 13. 不考慮自己阻塞自己的情況 EXAMPLE: exec sp_block '%running%' exec sp_block '%block%' sp_block @status ='',@is_output =2 ************************/ set nocount on declare @rowcount int set @status=ltrim(rtrim(@status))+'%' declare @spid_blocked table ( spid int not null ,blocking_spid int null ,blocking_spid_sort varchar(1000) null ,wait_time int null ) declare @cte table(spid smallint ,blocking_spid smallint ,wait_time bigint ) insert @cte select distinct spid,blocked,waittime from master.dbo.sysprocesses where blocked <>0 and spid<>blocked insert into @spid_blocked select a.spid ,coalesce(d.blocking_spid,c.blocking_spid,b.blocking_spid,a.blocking_spid) as blocking_spid ,ltrim(str(a.spid))+'->'+ltrim(str(a.blocking_spid))+isnull('->'+ltrim(str(b.blocking_spid)),'')+isnull('->'+ltrim(str(c.blocking_spid)),'')+isnull('->'+ltrim(str(d.blocking_spid)),'') as blocking_spid_sort ,a.wait_time/1000 as wait_time from @cte a left join @cte b on a.blocking_spid=b.spid left join @cte c on b.blocking_spid=c.spid left join @cte d on c.blocking_spid=d.spid if @@rowcount>0 begin declare @spid_activity table ( type nvarchar(50) not null ,spid int not null ,blocking_spid int null ,blocking_spid_sort varchar(1000) null ,blocked_count int null ,wait_time int null ,blocked_time int null --seconds ) insert into @spid_activity(type,spid,blocking_spid,blocking_spid_sort,blocked_count,wait_time,blocked_time) select distinct '1_blocking',blocking_spid,0,'kill '+ltrim(str(blocking_spid)),count(blocking_spid),0,max(wait_time) from @spid_blocked group by blocking_spid union all select distinct '2_blocked',spid,blocking_spid,blocking_spid_sort,0,wait_time,wait_time from @spid_blocked select @rowcount=@@rowcount if @is_output<>2 begin ----select * from master.dbo.dba_block_debug if object_id('master.dbo.dba_block_debug') is null begin --(可刪除),收集數據 create table master.dbo.dba_block_debug( id int identity primary key, checktime datetime default(getdate()), type nvarchar(50) not null ,spid int not null ,blocking_spid int null ,blocking_spid_sort varchar(1000) null ,blocked_count int null ,wait_time int null ,blocked_time int null --seconds ) end if @rowcount>=5 and @is_output=1 begin insert into master.dbo.dba_block_debug(type,spid,blocking_spid,blocking_spid_sort,blocked_count,wait_time,blocked_time) select type,spid,blocking_spid,blocking_spid_sort,blocked_count,wait_time,blocked_time from @spid_activity delete from master.dbo.dba_block_debug where id<(select max(id) as id from master.dbo.dba_block_debug)-1000 end end end -------------- if object_id('tempdb.dbo.##block') is not null drop table ##block --10 show results ************* select case when st0.type is not null then st0.type when se1.status='running' then '3_Running' when se1.status='Sleeping' then '4_Sleeping' when se1.status='Dormant' then '5_Dormant' when se1.status='Preconnect' then '6_Preconnect' else 'Others' end as type ,se1.session_id as spid ,isnull(st0.blocking_spid_sort,'') as blocking_spid ,isnull(str(st0.blocked_count),'') as blocked_count ,isnull(dbo.udf_Duration_IntToChar(blocked_time),'') as blocked_time ,case when pr.dbid = 0 then '' else db_name(pr.dbid) end as DBname ,se1.login_name /*,db_name(re2.database_id) as DBname --20090817yf*/ ,se1.[host_name] as client_name ,co3.client_net_address as client_IP ,case when charindex('Job 0x',se1.[program_name])>0 then ( select 'SQLAgent Job: '+a.name+' Setp: '+ltrim(str(b.step_id))+' ('+b.step_name+')' from msdb.dbo.sysjobs a with (nolock) join msdb.dbo.sysjobsteps b with (nolock) on a.job_id=b.job_id where right(a.job_id,12) =substring(se1.[program_name],charindex('Job 0x',se1.[program_name])+26,12) and b.step_id=substring(se1.[program_name] ,charindex(' Step ',se1.[program_name])+6 ,charindex(')',se1.[program_name])-charindex(' Step ',se1.[program_name])-6 ) ) else se1.[program_name] end as client_program ,te2.text as running_or_last_text , ( SELECT TOP 1 SUBSTRING(te1.text,statement_start_offset/2, ( (CASE WHEN statement_end_offset= -1 THEN (LEN(CONVERT(nvarchar(max),te1.text))*2) ELSE statement_end_offset END)-statement_start_offset)/2)) AS running_sql --fix bug of "Difference of two datetime columns caused overflow at runtime." ,case when re2.wait_time is not null and se1.last_request_end_time>0 then 'wait '+dbo.udf_Duration_IntToChar(re2.wait_time/1000) when re2.wait_time is null and se1.last_request_end_time>0 then 'idle '+dbo.udf_Duration_IntToChar(datediff(ss,se1.last_request_end_time,getdate())) else 'idle from '+convert(char(20),se1.last_request_end_time,120) end as duration ,se1.status as session_status ,re2.status as request_status ,re2.command ,re2.wait_type ,re2.wait_resource ,re2.open_transaction_count as open_tran ,re2.row_count ,local_net_address as Server_IP,local_tcp_port as Port --,se1.[program_name] as client_program --,user_name(re2.[user_id]) as UserName ,se1.client_interface_name as client_interface ,se1.host_process_id as client_process ,case when st0.blocking_spid=0 then (select query_plan from sys.dm_exec_query_plan (re2.plan_handle) ) else '' end as query_plan ,se1.login_time ,se1.last_request_end_time /*,se1.last_request_start_time --20090817yf*/ ,se1.cpu_time ,se1.reads ,se1.logical_reads ,se1.Writes ,se1.is_user_process /*,se1.memory_usage,re2.cpu_time,re2.reads,re2.logical_reads ,re2.Writes,re2.nest_level --20090817yf*/ --,percent_complete --,re2.transaction_isolation_level --轉換成文字說明 --,re2.prev_error --,dbo.udf_Duration_IntToChar(re2.total_elapsed_time/1000)as total_elapsed_time --,re2.start_time --,re2.last_wait_type --,re2.open_resultset_count --,transaction_id ---,se1.lock_timeout --,re2.granted_query_memory --,re2.executing_managed_code ,blocked_time as blocked_time_ss into ##block from sys.dm_exec_sessions se1 with (nolock) left join master.dbo.sysprocesses pr with (nolock) on se1.session_id=pr.spid left join sys.dm_exec_requests re2 with (nolock) on se1.session_id=re2.session_id left join sys.dm_exec_connections co3 with (nolock) on se1.session_id=co3.session_id left join @spid_activity st0 on se1.session_id=st0.spid outer APPLY sys.dm_exec_sql_text(re2.sql_handle) AS te1 outer APPLY sys.dm_exec_sql_text(co3.most_recent_sql_handle) AS te2 where st0.type is not null or (se1.is_user_process=1 and se1.status like @status and se1.session_id<>@@SPID) order by type,st0.blocked_count desc,st0.blocked_time desc,request_status desc,se1.session_id ------ if @is_output=1 begin select * from ##block print 'select * from ##block order by login_name' print 'select login_name,count(*) as count0 from ##block group by login_name order by login_name ' end else if @is_output=2 begin declare @min_spid int select @min_spid=min(spid) from ##block where type in ('1_blocking','3_Running') select isnull(stuff(@@servername,charindex('\',@@servername),len(@@servername),''),@@servername) as ServerName ,case when a.type is null then b.type else a.type end as type ,a.spid,blocked_count,blocked_time,duration,session_status ,DBname,login_name,client_name,client_IP,client_program ,case when running_sql is null then running_or_last_text else running_sql end as running_or_last_text ,command,wait_type --,client_interface,client_process,blocking_spid,wait_resource from (select * from ##block where type in ('1_blocking','3_Running')) a full outer join (select case when @status like 'b%' then 'No_Blocking'--'當前無阻塞的進程!' when @status like 'r%' then 'No_Running'--'當前無阻塞或正運行的進程!' else 'No_Blocking_or_Running' end as type ,@min_spid as spid ) b on a.spid=b.spid end GO
USE [master] GO /****** Object: UserDefinedFunction [dbo].[udf_Duration_IntToChar] Script Date: 09/27/2013 14:19:16 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER OFF GO create FUNCTION [dbo].[udf_Duration_IntToChar] (@duration int) RETURNS varchar(50) with encryption AS /********************** REMARK: 1. The duration must be seconds EXAMPLE: declare @duration int set @duration=3672+3600*100 select dbo.udf_Duration_IntToChar(@duration) ************************/ BEGIN declare @duration_char varchar(50),@days varchar(30) set @days=case when @duration>=86400 then convert(varchar(20),convert(int,@duration/86400))+'D ' else '' end set @duration=@duration%86400 set @duration_char=@days+case when (@duration/3600)>9 then ltrim(str(@duration/3600)) else right('0'+ltrim(str(@duration/3600)),2) end +':' +right('0'+ltrim(str((@duration%3600)/60)),2)+':' +right('0'+ltrim(str((@duration%3600)%60)),2) RETURN @duration_char END GO
4.禁用日誌備份job,自動傳送日誌job,日誌還原job (原庫的2個,新的1個)
5.手動執行備份日誌存儲過程,備份最後一次尾日誌
6.手動執行自動傳送日誌備份
7.手動執行最後日誌還原存儲過程
8.檢查最後日誌還原節點
9.還原庫執行 use master restore database dbname with recovery
10.刷新一下,看庫是否可讀寫狀態了
11.通知開發人員改連接ip或者域名配置