역시나 sqlleader.com 에 질문 & 답

-----------

제 목    Re) 패키지 외부에서 변수값 넘기는 예제에서 질문
· 작성자    한대성 (MVP)
· 글정보
   조회 : 10, 등록일 : 2007/04/17 16:57

안녕하세요..박노철 님..^^ 오랫만입니다..
언제 조만간 온라인에서 자주 뵌 분드라고 번개 한 번 합시다.ㅎㅎ
 
해결 방법으로는, 값을 지정하기 전에 EvaluateAsExpression 의 속성 값을 False로 해 버리는 것도 같이 추가하면 됩니다.
 
예)
 /SET "\Package.Variables[사용자::day].Properties[EvaluateAsExpression]";False /SET "\Package.Variables[사용자::day].Properties[Value]";2

패키지 많이 작성하시는가 보내요..^^
좋은 자료나 특이한 상황, 경험 있으시면 같이 공유 부탁.ㅎㅎ
 
그럼 수고하세요.


작성자 : 박노철 , 등록일 : 2007-04-17 오후 3:49:00
dtexec 로 패키지 실행할 때 패키지 내부의 변수값을 조작하기 위해서
 
/SET '\Package.Variables[사용자::day].Properties[Value]';'16'
 
이렇게 커맨드 라인에 추가를 했는데요 값이 바뀌지가 않습니다. 패키지 내부에서 사용자::day 변수는 다음과 같이 선언되어 있습니다.
 
사용자::day      (DT_WSTR,2)(DAY(GETDATE())
(EvaluateAsExpression 은 True 입니다)
 
제 생각에는 커맨드 라인에서 값을 정상적으로 넘기긴 했지만, 실제로 패키지가 수행될 때는 변수에 정의된 것이 수행되면서 값을 바꿔버리는게 아닌가 하는 추측을 해봤습니다. 그래서 저 변수의 EvaluateAsExpression 을 False 로 하고 값은 01 로 바꿨습니다. 즉 상수로 고정시킨거죠. 그러니까 원래 의도했던대로 16이 들어가더군요. 이런게 필요한 이유는 이렇습니다. 매일 한번씩 FTP로 데이터를 읽어서 DB에 넣는 패키지가 있는데요, 이게 정상적으로 수행되면 문제가 없지만 혹시라도 실패해서 전날이나 전전날걸 돌려야 할 때 수동으로 값을 넣기 위함입니다. 그런데 예제에는 ExecDate 라는 값을 20070201 인가로 고정했더군요. 하지만 실제로는 SQL Agent 에 걸어놓고 지가 알아서 그날치 데이터를 읽어오길 원하므로 수행날짜 변수에 GETDATE() 를 사용할 수 밖에 없는 상황입니다만...
 
정리하자면 질문은 이렇습니다.
 
'EvaluateAsExpression = True 인 변수에 대해서도 커맨드 라인에서 값을 넘겨주는 방법은 없는가?'
 
입니다. 언제나 많은 도움 감사드리고 있습니다. 그럼 수고하세요 ^^
 

박노철 예 번개 좋지요~ ㅎㅎㅎ 저런 간단한 방법이 있었다니 콜럼버스 달걀깨듯 하시는군요 ㅋ 감사합니다 ^^ 2007/04/18  

Posted by maceo

04 18, 2007 10:16 04 18, 2007 10:16
, ,
Response
No Trackback , No Comment
RSS :
http://merritt.co.kr/tt/rss/response/96

역시나 sqlleader.com 에서 주고받은 문답...

----------

제 목   Re) 조회 변환 캐싱하는거 병렬 진행 맞나요???
· 작성자    한대성
· 글정보   Hit : 14, Date : 2007/03/19 21:34

안녕하세요..^^
 

전에 다음과 같은 질문에 대해 이렇게 답변 드린 적이 있었네요..
 
   Q) 그림은 순차적이지만 조회 변환을 위한 데이터 캐시는 한꺼번에 하는게 맞는건가요??
   A) 넵.. 패키지 내에 있는 조회 변환 데이터를 먼저 와장창 캐싱 한 후에 작업을 수행합니다.
 
조회 변환에 대해 테스트 할 때 다른 작업들에 비해 먼저 캐싱하는 것만 확인하였지, 개별 조회 작업 간의 순서에 대해서는 별 생각 없어서 "와장창 (한번에)" 라는 표현으로 설명드렸는데, 질문 올리신 것 보고 테스트 해 보니 박노철님 말씀대로 순차적으로 캐싱되네요..
 
혹시나 해서 Execution Tree를 여러 개 생성되도록 해보고, 여러 데이터 흐름 작업에 대해 동시에 실행을 시켜도 모두 순차적으로 캐싱되는 것 같습니다.
 
아마도 하나의 Lookup Cache 영역을 이용하기 때문이지 않을까 싶네요..(추측)
 
테스트 하다가 재미있는 것을 확인했는데요.. 동일한 조회 쿼리(or 테이블)에 대해 동일한 열을 캐싱시킬 때에는 한 번만 캐싱한다는 것입니다..(자료를 찾아보니 실제로 그렇다고 하네요..^^)
 
훔훔훔... 재미있는 것 알게 되었습니다..^^캄사.....ㅎㅎ
 
 
 
 
 
 
작성자 : 박노철 , 등록일 : 2007-03-19 오후 3:40:00
안녕하세요. 간만에 질문드립니다. ^^
 
조회 변환의 설정을 디폴트로 해놓고  
조회 변환에 쿼리 입력하고
이런 조회 변환을 20개를 주욱 이어붙였을 경우 '동시에' 20개의 커넥션을 DB에 열어서
데이터를 주우욱 읽어오는 걸로 알고 있었습니다. 예전에 그렇게 설명해주신 것 같구요..
그런데 오늘 로그를  살펴보니까 각 조회 변환이 데이터 캐시하는게 순차적이더군요...
간단하게 정리하면 이렇습니다.
 
--goodsdaq_brand
ssis 15:05:05 ~ 15:05:08
--maker
ssis 15:05:09 ~ 15:05:10
--dealersettletbl
ssis 15:05:12 ~ 15:05:30
--custom
ssis 15:05:32 ~ 15:07:36
--dsdeliverygroup
ssis 15:07:46 ~ 15:07:52
--goods_discount_list
ssis 15:07:54 ~ 15:07:59
--freeint_charge_goods
ssis 15:08:03 ~ 15:08:12
--fn_get_goods_satisfaction_point
ssis 15:08:14 ~ 15:11:11
 
(후략..)
 
그림상으로 goodsdaq_brand 이 가장 첫번째 오는 조회변환입니다. 사실 조회 변환 전에 OLEDB 원본 3개에서 테이블을 하나씩 읽어서 병합 조인을 하고 그 결과를 20여개의 조회변환을 주욱 태우는 건데요, 3개의 OLEDB원본과 첫번째 조회변환 goodsdaq_brand는 동시에 시작이 됩니다만, 늘어서 있는 20개의 조회변환이 데이터를 캐시해오는 것은 순차적인 것 같네요. 이게 정상적인건가요?? 제가 잘못본건가요??? 아니면.. 설정을 뭔가 바꿀 수 있는게 있는건가요??? 사실 메모리에 데이터 다 들고 있을거면 그냥 15:05:05 에 패키지 스타트하면 커넥션 23개 동시에 열어서 모든 조회 변환의 start 시간이 동일하게 찍혀도 될 것 같은데... 어찌된 일인지 도움을 좀 부탁드립니다.
 
참고로 EngineThread 는 32, MaxConcurrentExecutables 도 32 입니다 SSIS 엔진이 도는 서버는 32way 입니다.
 
 

박노철 네... 그렇군요. 조회변환에서 캐싱하는 것 중에서 시간이 꽤 많이 걸리는 것들이 3개 정도 있어서 이걸 OLE DB 원본으로 빼고 병합조인-left join 으로 처리했더니 두배이상 느려지더군요. OLE DB 원본 3개는 동시에 읽어오니까 데이터 읽어오는 시간은 분명히 줄어드는 것을 확인했는데요, 병합조인이 3개 들어가고 그게 다 left join 이어서 그런지... 그리고 찾아보셨다는 그 자료는 어디에 있는것이죠?? ^^

Posted by maceo

03 21, 2007 11:19 03 21, 2007 11:19
,
Response
No Trackback , No Comment
RSS :
http://merritt.co.kr/tt/rss/response/95

SSIS 파생열 변환의 심각한 버그?

sqlleader.co.kr 에 올린 글임...

----------------------

한글판 BIDS 입니다.
 
OLE DB 원본에서 아무 컬럼이나 읽고, 파생열 변환하고 연결합니다.
파생열 변환에서 새 컬럼 추가하고 스크립트를 TEST_COL + "" 이렇게 해서 SAVE하고
IDE닫은 다음에 다시 열어보세요. 데이터 변환 작업 내용이 다 날아가 있을겁니다.
 
이걸 알아채기 더더욱 힘든건, 파일 크기는 왕창 줄어들어 있는데 IDE상에 그림은 제대로
떠있습니다. IDE를 닫았다가 다시 열어보거나 파일 크기를 새로 확인해보기 전엔 알 수
없습니다. 아무래도 특수문자 "" 때문인 것 같네요. 3주일치 작업한거 다 날아가서 눈물납니다. ㅠ_ㅠ
 
 
 
@제꺼에서만 그러면 대략 낭패-_-


----------------------아래는 답변---------------------

제 목   Re) BIDS 의 버그
· 작성자    한대성
· 글정보   Hit : 2, Date : 2007/02/26 18:20

안녕하세요..^^(흑..안녕치 못하신 것 같습니다..)
 
말씀대로 패키지를 구성해서 해보니 저도 동일한 현상이 발생되네요..
 

식에 문자가 들어가니 저장할 때 말씀하신 바와 같이 패키지 내용이 날라가네요..
 
강제로 패키지의 XML 문에다가 해당 문자를 추가해서 열어봤더니 다음과 같은 에러 메시지
가 출력되네요..
 
 
 
결국은, 디자인 타임에서도 저런 형태로 에러가 발생되었을 낀데 왜 출력을 안하는지 원..쩝..
 
패키지의 레이아웃은 패키지의 XML 코드에서 <diagram>  ...  </diagram>  부분에 정의
되어 있기 때문에 패키지의 외관은 유지가 되는 것 같습니다.
 
실제로 날라가는 부분은 <components>  .. </components> 부분이네요..
 
위와 같은 문자열을 추가시킬려면 파생열 변환 대신에 스크립트 구성요소-변환 을 이용해서
처리해야 할 것 같네요..^^
 
예) Row.Title1 = Row.title + Chr(8)
 
 
 
근데 왜 저런 문자를 덧붙이시나요..?? ^^

Posted by maceo

02 26, 2007 19:00 02 26, 2007 19:00
, ,
Response
No Trackback , No Comment
RSS :
http://merritt.co.kr/tt/rss/response/91

다음 SQL을 SSIS 데이터 흐름 작업으로 변환시키는 시나리오를 생각해보자.

(1) insert into STAGING_TABLE
select (필드들..)
from SOURCE_TABLE
where (조건들...)

(10000건 인서트)


(2) update st
set colA = r1.colA
from STAGING_TABLE st
     inner join REF_DATA1 r1 on st.col1 = r1.col1

(1000건 update)

(3) update st
set colA = r2.colB
from STAGING_TABLE st
     inner join REF_DATA2 r2 on st.col2 = r2.col2

(100건 update)

(1)번은 심플하다. OLE DB 원본으로 주욱 읽어들인다.
(2)도 쉽다. 조회 변환을 사용해서 REF_DATA1 을 읽고 오류 무시를 설정, 조인키는 col1, r1.colA를 조회 새로운 열 colA로 추가한다.
(3)도 쉬워보인다. 조회 변환, REF_DATA2 를 읽고 오류 무시, 조인키는 col2, r2.colB를 읽어서 (2)에서 추가한 colA에 대해서 바꾸기 colA 로 설정한다.

자 돌려보자!

이런-_-;;;;; (2) 에서 조회에 성공한 1000개의 REF_DATA1 의 값 colA가 몽땅 NULL로 바뀐 거시다!!!! ㅠ_ㅠ

이게 왜 그럴까?

그렇다.. (3) 에서 조회 성공한 100건에 대해서 colA의 값을 바꾸고 나머지 10000건 - 100건 의 데이터는 몽땅 NULL로 바꿔버리는 거시다... 이거때문에 한참 헤맸다. DB에 너무도 익숙해진 나머지 위의 조회 변환도 당연히 DB의 update 처럼 동작하는 것으로 착각한 것이다. 이걸 제대로 돌게 하려면 (3)에서 읽어들이는 값을 새로운 열 추가 colA_1 로 해놓고 파생열 변환에서 바꾸기 colA 열, !ISNULL(colA_1) ? colA_1 : ( !ISNULL(colA) ? colA : "N" ) 이런식으로 바꿔준다.

앞으로 이런 삽질을 얼마나 더 해야할까. 흑.


Posted by maceo

02 23, 2007 10:01 02 23, 2007 10:01
, ,
Response
No Trackback , No Comment
RSS :
http://merritt.co.kr/tt/rss/response/90

조회 변환을 LEFT JOIN 처럼 작동하게 하려면 보통 오류 무시를 하는데, 이때 조회 실패로 인한 오류도 무시하지만 DB에서 뱉어내는 오류도 무시해버리는 문제가 있다. 그런데 하필이면 그 오류가 데이터를 한참 넘겨주다가 데이터상의 문제로 쿼리 프로세싱이 멈춰버리는 경우라면 데이터가 다 넘어오지 않아서 문제가 되는 경우가 발생한다. 아래는 역시나 sqlleader.co.kr 에서 주고받은 글.

---------

· 제 목   조회변환에서 SELECT를 수행하던중 에러가 났을때 그대로 진행됩니다
· 작성자    박노철
· 글정보   Hit : 16, Date : 2007/02/22 17:39

 
이건 질문이라기보다는 제가 겪은 문제 상황을 해결하는 과정에서 알아낸 조회 변환의 특이한 동작? 인데요...
 
조회 변환/전체 캐시모드에서 다음과 같은 쿼리가 있었습니다.
 
select cast(col1 as int) as money_to_int_col,
(다른 컬럼들..)
from TABLE with(nolock)
where col2 > XXXX
 
원래대로라면 이 쿼리는 90만건 정도의 데이터를 반환해야 하는데 SP2 를 설치하고 로그를 확인해보니 총 반환되는 행이 45만건 밖에 안되는겁니다. 그렇다고 해서 조회 변환 로그에 에러가 찍히는 것도 아니었고 패키지 실행이 실패하지도 않았습니다. 패키지 실행중 에러가 하나라도 나면 실패하도록 해놨거든요.
 
문제는 cast() 연산에 있었는데요, col1 의 데이터중에 1000억이 넘는 값이 들어간 데이터가 있었습니다. 한 45만개 정도를 리턴하고 45만1번째 데이터가 1000억이었는데, 이걸 int로 변환하다가 overflow 가 나버린겁니다. 그래서 select 문의 실행이 중지되었지요. 데이터가 넘어가긴 했구요. 그래서 where 조건에 col1 < 20억 이렇게 넣고 나니 90만건을 모두 읽어오는군요.
 
이런 상황에서 조회 변환 컴포넌트쪽에서 에러를 내고 프로세싱이 멈췄다면 문제를 좀 더 일찍 확인할 수 있었겠는데... 조회 변환의 디폴트 설정에서 이런 에러는 무시하나 봅니다. 아니면 제가 조회 변환쪽이나 패키지 실행쪽에 뭔가 에러 처리 설정을 좀 더 상세하게 했었어야 하는 거였을까요???? 하여간 이런 문제가 있어서... 노하우 공유차 글을 올려봅니다^^
 

한대성 좋은 내용 올려주셔서 감사합니다.^^

저도 테스트 해 보고 있는데, SELECT 쿼리에서 Overflow로 인해 실패가 나는 경우 조회 변환 자체도 실패로 처리되지 않는지요?

select OrderID, CAST(CASE WHEN EmployeeID <4 THEN 1000000 ELSE 10000000000 END as int) as OrderID2 FROM Northwind..Orders

와 같은 형태로 총 830개의 데이터 중 347개만 리턴하고 Overflow 에러가 발생하도록 하고 이 쿼리를 조회 변환에서 수행해 보았는데, 저의 경우에는 조회 단계에서 에러가 나네요..

혹시나(^^) 조회 변환에서 오류 무시로 설정을 하신 건 아니신지 궁금하네요..^^

다시 한 번 감사드립니다..
2007/02/23
박노철 아 오류 무시로 했네요. 그런데 조회 변환에서 오류 무시로 해놓으면 조회가 실패했을때도 오류 무시를 하고 DB에서 데이터를 읽어오다가 실패해도 무시를 하도록 설정이 되기 때문에 문제인 것 같습니다. 조회 변환을 LEFT JOIN 처럼 동작하도록 하고 싶었기 때문에 오류 무시를 해놨는데 그게 이럴때 문제가 되네요. 처음해보는거라 좌충우돌 미숙한 점이 많습니다. ㅋ 많은 도움 감사드립니다^^ 2007/02/23  
한대성 아..그렇군요^^ 대량 데이터를 이용한 테스트가 어려운 상황에서 좋은 정보를 많이 공유해 주셔서 정말 감사합니다. 덕분에 개인적으로도 테스트 하고 익힐 수 있는 기회가 되어 많은 도움을 받고 있습니다... 저도 감사.ㅎㅎ 꾸벅 ^__^ 2007/02/23

Posted by maceo

02 23, 2007 09:35 02 23, 2007 09:35
, ,
Response
No Trackback , No Comment
RSS :
http://merritt.co.kr/tt/rss/response/89

역시나 sqlleader.co.kr 에서 주고받은 글...

---------

제 목   Re) NULL 데이터와 ? : 3항 연산자와 파생열 변환이 함께 쓰였을 때 이상한 동작
· 작성자    한대성
· 글정보   Hit : 7, Date : 2007/02/23 00:32

Null에 대한 처리로 인한 것 같습니다..
 
(is_dnt_goods_yn1 == "Y") ? "Y" : "N"
의 조건식에서 is_dnt_goods_yn1이 NULL 인 경우에는 "N"이 아닌 NULL로 처리됩니다.
 
NULL 이 "Y"는 아니지만, 그렇다고 해서 "Y"가 아닌 것도 아니기 때문에..
 
말씀하신 조건에 대한 조건식은 다음과 같이 하면 어떨까 합니다..
 
is_dnt_goods_yn2 == "A" && !ISNULL(is_dnt_goods_yn2) ? "A" : (is_dnt_goods_yn1 == "Y" && !ISNULL(is_dnt_goods_yn1) ? "Y" : "N")
 
조건 중에 "A가 아니면, ... Y가 아니면..." 이라는 조건 때문에 단순히   !ISNULL()   로만 판단하면 안되지 않을까 생각되네요..^^
 
 




 
작성자 : 박노철 , 등록일 : 2007-02-22 오후 5:31:00
 
파생열 변환과 관련하여 아무래도 이해가 잘 되지 않는 점이 있어서 다시 질문드립니다. 다음과 같은 소스 데이터가 있습니다.
 
select * from is_dnt_goods_src
 
is_dnt_goods_yn1 is_dnt_goods_yn2
---------------- ----------------
Y                NULL
Y                NULL
Y                NULL
Y                NULL
Y                NULL
NULL             A
NULL             A
NULL             A
NULL             A
Y                NULL
Y                NULL
Y                NULL
Y                NULL
Y                NULL
Y                NULL
Y                NULL
NULL             A
NULL             A
NULL             A
NULL             A
NULL             A
NULL             A
Y                NULL
Y                NULL
Y                NULL
Y                NULL
Y                NULL
Y                NULL
 
여기서 필요한 비즈니스 로직은 is_dnt_goods_yn 이라는 필드값을 파생열 변환을 사용해서 새 열로 만들어내는데,
 
'is_dnt_goods_yn2 가 A 면 A를 리턴하고 A가 아니면(NULL이거나 다른값) 이면 is_dnt_goods_yn1 을 검사해서 그 값이 Y면 Y를 리턴하고 그게 아니면(NULL이거나 다른값) 이면 N 를 리턴한다'
 
입니다. 위의 로직을 파생열 변환에서 다음과 같이 구현해보았습니다.
 
is_dnt_goods_yn      <새열로 추가>   is_dnt_goods_yn2 == 'A' ? 'A' : ((is_dnt_goods_yn1 == 'Y') ? 'Y' : 'N')
 
결과는 다음과 같습니다.
is_dnt_goods_yn1 is_dnt_goods_yn2 is_dnt_goods_yn
---------------- ---------------- ---------------
Y                NULL             NULL
Y                NULL             NULL
Y                NULL             NULL
Y                NULL             NULL
Y                NULL             NULL
NULL             A                A
NULL             A                A
NULL             A                A
NULL             A                A
Y                NULL             NULL
Y                NULL             NULL
Y                NULL             NULL
Y                NULL             NULL
Y                NULL             NULL
Y                NULL             NULL
Y                NULL             NULL
NULL             A                A
NULL             A                A
NULL             A                A
NULL             A                A
NULL             A                A
NULL             A                A
Y                NULL             NULL
Y                NULL             NULL
Y                NULL             NULL
Y                NULL             NULL
Y                NULL             NULL
Y                NULL             NULL
 
A는 제대로 넘어오는데 Y값이 제대로 채워지지 않습니다. 아무래도 이상해서 파생열 변환의 expression 을 바꿨습니다.
 
!ISNULL(is_dnt_goods_yn2) ? is_dnt_goods_yn2 : (!ISNULL(is_dnt_goods_yn1) ? is_dnt_goods_yn1 : 'N')
 
NULL을 검사하도록 했죠. 그랬더니 다음과 같이 나왔습니다.
 
is_dnt_goods_yn1 is_dnt_goods_yn2 is_dnt_goods_yn
---------------- ---------------- ---------------
Y                NULL             Y
Y                NULL             Y
Y                NULL             Y
Y                NULL             Y
Y                NULL             Y
NULL             A                A
NULL             A                A
NULL             A                A
NULL             A                A
Y                NULL             Y
Y                NULL             Y
Y                NULL             Y
Y                NULL             Y
Y                NULL             Y
Y                NULL             Y
Y                NULL             Y
NULL             A                A
NULL             A                A
NULL             A                A
NULL             A                A
NULL             A                A
NULL             A                A
Y                NULL             Y
Y                NULL             Y
Y                NULL             Y
Y                NULL             Y
Y                NULL             Y
Y                NULL             Y
 
정확한 결과가 나왔습니다.
 
제가 expression 을 잘못 사용한 것일까요? 3항 연산자 evaluate 하는데 버그가 있는 것일까요? -_-;;;;
이거때문에 정말 한참을 헤맸습니다. 흑. 혹시 이런 경우를 겪어 보셨는지요????
 
 
 
 

박노철 아.. 그렇군요. 감사합니다. DB에서 적용되던 TRUE, FALSE, NULL 의 원리가 SSIS 스크립트에서도 그대로 적용되는 모양이군요. 보통 프로그래밍 언어에서 하듯이 하면 될 줄 알았는데. 다시 한번 감사드립니다^^ 2007/02/23  

Posted by maceo

02 23, 2007 09:28 02 23, 2007 09:28
, ,
Response
No Trackback , No Comment
RSS :
http://merritt.co.kr/tt/rss/response/88

SSIS의 병합 조인 vs 조회 변환 성능 테스트

sqlleader.co.kr 의 Q&A 게시판에 올린 글임.
(IBM 메인프레임에서 내려오는 데이터에 대해서는 속수무책인 것 같아 보이긴 하는데... 일반적인 환경에서라면 SSIS 상당히 훌륭하다. 잘 활용하면 배치잡 튜닝에 좋은 효과를 볼 수 있을 듯...)

--------------------------
 
다음과 같은 형태의 쿼리가 있습니다.
 
insert into remote_server.dbo.TARGET_TABLE (col1 ~ coln)
select col1 ~ coln
from MAIN_BIG_TABLE m (1000만건)
    inner join SUB_BIG_TABLE1 s1 (1000만건)
    inner join SUB_BIG_TABLE2 s2 (1000만건)
    inner join SUB_TINY_TABLE1 t1 (5000건)
    inner join SUB_TINY_TABLE2 t2 (5000건)
    inner join SUB_TINY_TABLE3 t3 (5000건)
where m.col1 = 'XXX'
and s1.col1 = 'XXX'
and s2.col1 = 'XXX'
(이하생략)
 
위의 쿼리를 돌리면 300만건이 insert 가 됩니다. 즉, s1, s2, t1, t2, t3 을 inner join 하면서 700만건이 떨어져 나가는 것이죠. 현재 돌고 있는 배치잡에서 위 쿼리가 가장 시간이 많이 걸리는 부분이었습니다. 대략 30분 정도가 걸렸죠. 
이걸 SSIS 를 이용해서 개선을 해보았습니다. 다음 두가지 방식으로 시도를 했습니다.
 
1. 조회변환을 여러번 이용
MAIN_BIG_TABLE 은 OLE DB 원본으로 읽어오고 SUB테이블들을 모두 조회 변환으로 읽어왔습니다. SSIS 엔진이 도는 서버의 사양이 매우 좋아서 조회 변환에 대한 메모리 제한은 두지 않았습니다. 원본 서버와 대상 서버에 대해서 dbcc dropcleanbuffers, dbcc freeproccache 를 모두 수행해서 반복테스트시 캐싱이 미치는 영향은 제거했습니다. 결과는 다음과 같습니다.
 
5번 반복 테스트 결과 대상 서버에 OLE DB 대상으로 BULK INSERT 하는데 평균 11분
메모리 사용량 : 최고 1.4GB
 
2. BIG_TABLE간의 inner join 을 SSIS의 병합 조인으로 대체
BIG_TABLE 3개는 마침 clustered index 가 동일한 컬럼에 만들어져 있었습니다. 그리고 이 컬럼을 join key 로 사용하죠. (사실 BIG_TABLE 3개는 MAIN을 기준으로 1:1 mandatory 관계에 있는 테이블들입니다. 그냥 하나로 합쳐도 될텐데.... 모델링상 문제가 좀 있죠...) 따라서 clustered index scan 을 유도하고 order by 를 줘도 DB에 order by 부하 없이 join key 에 대해서 동일한 순서로 데이터가 넘어옵니다. 이는 실행계획상에서도 확인을 했습니다. BIG_TABLE 이 이미 정렬되어 있는 상태로 넘어오므로 BIG_TABLE 들간의 join 을 병합 조인으로 대체했습니다. SMALL_TABLE 들에 대해서는 그대로 조회 변환을 사용했습니다. 마찬가지로 원본, 대상 서버의 버퍼 풀과 프로시저 캐시는 비웠습니다.
 
5회 반복 테스트 결과 평균 7분의 시간이 걸렸습니다.
메모리 사용량 : 최고 900MB
 
아무래도 조회 변환은 메모리 사용 제한이 없으면 BIG_TABLE의 모든 데이터를 들고 있어야 하므로 메모리 사용이 많을 수 밖에 없는 반면, 병합 조인은 조인이 완료된 rowset 에 대해서는 더이상 메모리에 들고 있을 필요가 없기 때문에 data 가 흘러가면서 메모리 사용을 해제할 수 있기 때문에 이런 결과가 나온게 아닌가 싶습니다. 그리고 원본 서버에서 master..sysprocesses 을 확인해보니까 병합 조인으로 했을 때는 3개의 BIG_TABLE의 데이터를 동시에 읽어가는 것을 확인했습니다. 하지만 조회 변환으로 하면 아무래도 순차적으로 처리하다 보니까 최고 2개의 BIG_TABLE에 대해서만 select 가 들어오더군요.
 
위의 테스트를 통해서 배운 바를 정리하자면,
 
"매우 큰 테이블의 join key 들에 대해서 데이터가 이미 정렬되어 있는 경우, 병합 조인을 사용하는 것이 메모리 사용과 수행 시간면에서 유리하다."
 
가 되겠습니다. 중요한 것은 "데이터가 이미 정렬되어 있는 경우" 가 아닐까 합니다.
이렇게 하든 저렇게 하든 3배 ~ 4배 정도 속도가 빨라졌으니 대단히 만족하고 있습니다. ^_^

Posted by maceo

02 12, 2007 16:24 02 12, 2007 16:24
, ,
Response
No Trackback , No Comment
RSS :
http://merritt.co.kr/tt/rss/response/87


블로그 이미지

가늘어도 긴놈이 장땡

- maceo

Archives

Authors

  1. maceo

Calendar

«   3 2010   »
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

Site Stats

Total hits:
170331
Today:
29
Yesterday:
46