해당 스크립트의
1~3은 테스트 환경에서
4~5는 라이브 환경에서
스크립트 작성 배경
- 안내 문구내 삽입된 도메인의 변경 등의 요건에 따라 특정 키워드에 대한 검색 및 변경이 필요함
- 대량의 데이터에서 Like 조건 검색시 서버 부하 및 잠금 현상으로 인한 서비스 이슈 발생
- 별도 환경에서 변경 대상 검색 후 라이브 환경에서 Row단위 변경 필요 (SCAN -> Seek )
동작 설명 (세부 스탭은 제외)
해당 스크립트 사용 전재
- 라이브 환경에서는 Update 쿼리 (키워드 치환)만 수행
- 변경 대상 파악 및 Update 쿼리 추출은 테스트환경에서 진행 (최근 일자 라이브 백업본 필요)
실제 라이브 작업은 4단계 진행 (step3만 첨부)
- step1: A.com / 고유키 identity & X – 일괄적용 / 점검
- step2: i.A.com / 고유키 identity & X – 일괄적용 / 점검
- step3: A.com / 고유키 PK – 1건씩 Update&delay 반복 / 업무시간중 진행
- step4: i.A.com /고유키 PK – 1건씩 Update&delay 반복 / 업무시간중 진행
작업 진행 순서
- (in Test) 라이브 DB 복원 → (in Test) 스크립트 1~3 수행→ 서비스 담당자 변경 대상 확인 → 제외 및 추가 요건에 따른 쿼리 재수정
- (in Test) 스크립트 1~3 수행 → (in Test) 스크립트 4~5 수행 → 부하 확인 및 Update 결과 서비스 담당자 검증 → (in Live) 4~5수행
스크립트 설명
- 0_문자분할함수 : 3_결과추출쿼리.txt 내에서 IDX 키 추출시 사용
- 1_저장테이블스키마
- targetlist_cidx -문자열컬럼 리스트 및 추출 건수 기록
- Results_cidx - 변경 대상 Row 별 정보 기록
- 2_타겟리스트수집쿼리 : 타겟DB내 'char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext' 자료형 컬럼을 수집
- 3_결과추출쿼리_기본 : 2의 수집 대상 (테이블.컬럼)에 대해 아래의 작업 진행
- PK (본스크립트는 최대 4개)/ Identity 컬럼 추출
- 변경 대상 Row 에 대한 테이블/컬럼/PK 값/Update 쿼리 추출
- 추출 결과 예시
- 4_Step단위분할 : Step3만 작성. 3에서 추출된 Update 문을 별도 추출
- 5_실행 : While문을 통한 단건씩 변경
스크립트
0_문자분할함수 (https://tjddnjs625.tistory.com/14)
USE targetDB
GO
create FUNCTION [dbo].[Fn_get_split_index]
(@StrValue VARCHAR(500), @SplitChar CHAR(1), @idx INT
)
returns NVARCHAR(200)
AS
BEGIN
DECLARE @word CHAR(100), @sTextData VARCHAR(600), @num SMALLINT;
SET @num = 1;
SET @sTextData = Ltrim(Rtrim(@StrValue)) + @SplitChar;
WHILE @idx >= @num
BEGIN
IF Charindex(@SplitChar, @sTextData) > 0
BEGIN
SET @word = Substring(@sTextData, 1, Charindex(@SplitChar, @sTextData)- 1);
SET @word = Ltrim(Rtrim(@word));
SET @sTextData = Ltrim(Rtrim(RIGHT(@sTextData, Len(@sTextData) - ( Len(@word) + 1 ))))
END
ELSE
BEGIN
SET @word = NULL;
END
SET @num = @num + 1
END
RETURN( @word );
END
GO
1_저장테이블스키마
USE collectDB
CREATE TABLE [dbo].[targetlist_cidx](
[TableName] [nvarchar](100) NULL, [ColumnName] [nvarchar](100) NULL, [seq] [int] IDENTITY(1,1) NOT NULL, [cnt] [bigint] NULL
)
CREATE TABLE [dbo].[Results_cidx](
[rowNum] [bigint] IDENTITY(1,1) NOT NULL, [seq] [int] NULL, [tablename] [nvarchar](100) NULL, [ColumnName] [nvarchar](100) NULL,
[ColumnValue] [nvarchar](max) NULL, [cidx1] [nvarchar](100) NULL, [cidx2] [nvarchar](100) NULL, [cidx3] [nvarchar](100) NULL,
[cidx4] [nvarchar](100) NULL, [UPDQuery] [nvarchar](max) NULL
)
2_타겟리스트수집쿼리
use targetDB
go
SET NOCOUNT ON
DECLARE @SearchStr nvarchar(100), @ReplaceStr nvarchar(100) = null, @test bit = null,@updateSQL nvarchar(255)
DECLARE @TableName nvarchar(100), @ColumnName nvarchar(100), @SearchStr2 nvarchar(100)
SET @TableName = ''
SET @SearchStr2 = QUOTENAME('%' + @SearchStr + '%', '''')
WHILE @TableName IS NOT NULL
BEGIN
SET @ColumnName = ''
SET @TableName =
(
SELECT MIN(QUOTENAME(TABLE_NAME))
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE' AND QUOTENAME(TABLE_NAME) > @TableName
AND OBJECTPROPERTY(OBJECT_ID(QUOTENAME(TABLE_NAME)), 'IsMSShipped') = 0
)
WHILE(@TableName IS NOT NULL) AND(@ColumnName IS NOT NULL)
BEGIN
SET @ColumnName =
(
SELECT MIN(QUOTENAME(COLUMN_NAME))
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = PARSENAME(@TableName, 1) AND DATA_TYPE IN('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext')
AND QUOTENAME(COLUMN_NAME) > @ColumnName
)
IF @ColumnName IS NOT NULL
BEGIN
print 'insert into collectDB..targetlist_cidx (tablename,columnname) values ('''+ @TableName+''','''+@ColumnName+''')'
END
END
END
3_결과추출쿼리
USE targetDB
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
--[search_keyword_replace_v3] 'i.abc.com','zx.net',1
create PROCEDURE [dbo].[search_keyword_replace_v3](@SearchStr nvarchar(100), @ReplaceStr nvarchar(100) = null, @test bit = null)
AS BEGIN
SET NOCOUNT ON
DECLARE @updateSQL nvarchar(max), @TableName nvarchar(100), @ColumnName nvarchar(100), @SearchStr2 nvarchar(100) ,@checkrcnt bigint=0, @CIDXName nvarchar(500) =''
declare @cidx1 nvarchar(100) ='',@cidx2 nvarchar(100) ='',@cidx3 nvarchar(100) ='',@cidx4 nvarchar(100) ='',@cidxcolm nvarchar(500)='',@cidxcolm2 nvarchar(500)='',@cnt int =0
SET @TableName = ''
SET @SearchStr2 = QUOTENAME('%' + @SearchStr + '%', '''')
select @cnt= max(seq) from collectDB..targetlist_cidx where cnt is null
WHILE (@cnt >0)
BEGIN
select @TableName = tablename,@ColumnName = ColumnName from collectDB..targetlist_cidx where seq=@cnt
select @cidxcolm='' ,@cidxcolm2='' ,@cidx1='',@cidx2='',@cidx3='',@cidx4='',@CIDXName=''
SELECT @CIDXName= STUFF((SELECT ',' + COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE B
WHERE A.TABLE_NAME = B.TABLE_NAME
FOR XML PATH('')), 1, 1, '')
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE A
where A.TABLE_NAME = replace(replace(@tableName,'[',''),']','');
if (@CIDXName ='')
begin
SELECT @CIDXName= A.name
FROM syscolumns A
JOIN sysobjects B ON B.id = A.id
WHERE A.status = 128 and b.name = replace(replace(@tableName,'[',''),']','');
end
--print @tableName +'||'+@CIDXName
select @cidx1=dbo.[Fn_get_split_index](@CIDXName,',',1) ,@cidx2=dbo.[Fn_get_split_index](@CIDXName,',',2) ,
@cidx3=dbo.[Fn_get_split_index](@CIDXName,',',3) ,@cidx4=dbo.[Fn_get_split_index](@CIDXName,',',4)
select @cidxcolm = @cidxcolm+ case when @cidx1!='' then ''''+rtrim(@cidx1)+'=''+cast(['+ rtrim(@cidx1)+'] as nvarchar(100)),' else '''None'',' end
select @cidxcolm = @cidxcolm+ case when @cidx2!='' then ''''+rtrim(@cidx2)+'=''+cast(['+ rtrim(@cidx2)+'] as nvarchar(100)),' else '''None'',' end
select @cidxcolm = @cidxcolm+ case when @cidx3!='' then ''''+rtrim(@cidx3)+'=''+cast(['+ rtrim(@cidx3)+'] as nvarchar(100)),' else '''None'',' end
select @cidxcolm = @cidxcolm+ case when @cidx4!='' then ''''+rtrim(@cidx4)+'=''+cast(['+ rtrim(@cidx4)+'] as nvarchar(100)),' else '''None'',' end
select @cidxcolm =case when len(@cidxcolm)!=0 then left(@cidxcolm, len (@cidxcolm)-1) else @cidxcolm end
if(@cidx1!='')
begin
select @cidxcolm2 = @cidxcolm2+
case when st.Name in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext','datetime') then ' AND ['+rtrim(@cidx1)+"]="+"'''+cast(["+ rtrim(@cidx1)+"] as nvarchar(100)) +'''"
when st.Name in ('int','bigint') then ' AND ['+rtrim(@cidx1)+']=''+cast(['+ rtrim(@cidx1)+"] as nvarchar(100)) +'"
else ' ' end
from sys.sysobjects so
join sys.syscolumns sc on sc.id = so.id
join sys.systypes st on st.xusertype = sc.xusertype
where so.name = replace(replace(@tableName,'[',''),']','') and sc.name=@cidx1
end
if(@cidx2!='')
begin
select @cidxcolm2 = @cidxcolm2+
case when st.Name in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext','datetime') then ' AND ['+rtrim(@cidx2)+"]="+"'''+cast(["+rtrim(@cidx2)+"] as nvarchar(100)) +'''"
when st.Name in ('int','bigint') then ' AND ['+rtrim(@cidx2)+']=''+cast(['+ rtrim(@cidx2)+"] as nvarchar(100)) +'"
else ' ' end
from sys.sysobjects so
join sys.syscolumns sc on sc.id = so.id
join sys.systypes st on st.xusertype = sc.xusertype
where so.name = replace(replace(@tableName,'[',''),']','') and sc.name=@cidx2
end
if(@cidx3!='')
begin
select @cidxcolm2 = @cidxcolm2+
case when st.Name in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext','datetime') then ' AND ['+rtrim(@cidx3)+"]="+"'''+cast(["+ rtrim(@cidx3)+"] as nvarchar(100)) +'''"
when st.Name in ('int','bigint') then ' AND ['+rtrim(@cidx3)+']=''+cast(['+ rtrim(@cidx3)+"] as nvarchar(100)) +'"
else ' ' end
from sys.sysobjects so
join sys.syscolumns sc on sc.id = so.id
join sys.systypes st on st.xusertype = sc.xusertype
where so.name = replace(replace(@tableName,'[',''),']','') and sc.name=@cidx3
end
if(@cidx4!='')
begin
select @cidxcolm2 = @cidxcolm2+
case when st.Name in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext','datetime') then ' AND ['+rtrim(@cidx4)+"]="+"'''+cast(["+ rtrim(@cidx4)+"] as nvarchar(100)) +'''"
when st.Name in ('int','bigint') then ' AND ['+rtrim(@cidx4)+']=''+cast(['+ rtrim(@cidx4)+"] as nvarchar(100)) +'"
else ' ' end
from sys.sysobjects so
join sys.syscolumns sc on sc.id = so.id
join sys.systypes st on st.xusertype = sc.xusertype
where so.name = replace(replace(@tableName,'[',''),']','') and sc.name=@cidx4
end
select @cidxcolm2 =case when len(@cidxcolm2)!=0 then left(@cidxcolm2, len (@cidxcolm2)-0)+"'" else @cidxcolm2+'''' end
if (@cidx1!='')
begin
SET @updateSQL= 'UPDATE ' + @TableName + ' SET ' + @ColumnName + ' = REPLACE(convert(nvarchar(max),' + @ColumnName + '), ''' + QUOTENAME(@SearchStr, '''') + ''', ''' + QUOTENAME(@ReplaceStr, '''') + ''') WHERE 1=1 ' + @cidxcolm2
end
else
begin
SET @updateSQL= 'UPDATE ' + @TableName + ' SET ' + @ColumnName + ' = REPLACE(convert(nvarchar(max),' + @ColumnName + '), ''' + QUOTENAME(@SearchStr, '''') + ''', ''' + QUOTENAME(@ReplaceStr, '''') + ''') WHERE 1=1 ' + ' and ' + @ColumnName + ' LIKE '+"'" + @SearchStr2 +"'" + " OPTION (MAXDOP 3)'"
end
INSERT INTO collectDB..[Results_cidx] (seq,tablename,cidx1,cidx2,cidx3,cidx4,UPDQuery,ColumnName,columnvalue)
exec
(
'SELECT '+ @cnt +',''' + @TableName + ''',' + @cidxcolm + ',''' +@updateSQL+','''
+ @ColumnName + ''', LEFT(convert(nvarchar(max),' + @ColumnName + '), 255) FROM ' + @TableName + ' WITH (NOLOCK) ' + ' WHERE ' + @ColumnName + ' LIKE ' + @SearchStr2 + ' OPTION (MAXDOP 5)'
)
update collectDB..targetlist_cidx
set cnt= @@ROWCOUNT
where seq = @cnt
set @cnt=@cnt-1
END
END
4_Step단위분할
CREATE TABLE [collectDB].[dbo].[Apply_step3](
[loopNum] [bigint] IDENTITY(1,1) NOT NULL, [rowNum] bigint not null,
[seq] [int] NULL, [UPDQuery] [nvarchar](max) NULL, [isrun] int null
)
select rownum,seq,updQuery into collectDB.[dbo].[Apply_step4] (rownum,seq,updQuery) from collectDB.[dbo].[Results_cidx] order by rownum asc --pk
--where seq not in
CREATE UNIQUE CLUSTERED INDEX [PK_loopNum] ON collectDB.[dbo].[Apply_step3] ( [loopNum] ASC);
CREATE NONCLUSTERED INDEX [NC_rowNum] ON collectDB.[dbo].[Apply_step3] ( [rowNum] ASC);
5_실행
SET NOCOUNT ON
DECLARE @cnt bigint,@query nvarchar(max);
select @cnt= max([loopNum]) from collectDB..Apply_step3 where isrun is null
WHILE (@cnt >0)
BEGIN
set @query= null;
select @query = updquery +';' from collectDB.[dbo].[Apply_step3] with (nolock) where [loopNum]= @cnt
if @query is null
continue
exec (@query)
update collectDB..Apply_step3
set isrun= 1
where [loopNum] = @cnt
set @cnt=@cnt-1
waitfor delay '00:00:00.100';
end
'SQL Server > 스크립트' 카테고리의 다른 글
[스크립트] DB 배치 정보 확인 (0) | 2022.01.05 |
---|---|
[스크립트]미러링/오류로그/배치/세션유입 체크 (0) | 2021.06.12 |
[스크립트] TRN 복원 쿼리 생성 스크립트 (0) | 2021.02.22 |
[스크립트] 특정경로 Full백업 일괄 복원 (0) | 2021.02.22 |
[스크립트] ActiveSession 수집 결과 리포팅 형태로 가공 (0) | 2021.02.22 |