반응형

원격지 서버의 테이블에 대한 갱신 작업을 위해서 다음과 같이 Linked Server의 테이블을 JOIN 하여 UPDATE 하였습니다.

SET XACT_ABORT ON;

DECLARE @ano VARCHAR(30) = 'S201910250010'

BEGIN DISTRIBUTED TRAN

UPDATE Trgt
SET
    AcptYn = 'N',
    AcptEmpCode = '', 
    AcptDeptCode = '',
    AcptDateTime = NULL
FROM
    RemoteServer.RemoteDB.dbo.FIAccSlipDisappMaster AS Trgt
        JOIN RemoteServer.RemoteDB.dbo.FIAccSlipAggreationNo AS A
            ON a.SlipNo = Trgt.SlipNo
            AND A.AggregationNo = @ano

SET XACT_ABORT OFF;

COMMIT

그러나 동작은 잘 되지만 성능이 너무 나오지 않았습니다.

실행계획을 보니 원격지 테이블을 모두 읽어와서 JOIN 시키다 보니 실제 UPDATE 시킬 행은 1개 인데 수십만 건의 데이터를 읽고 있었습니다.

그래서 OpenQuery로 변경 하려고 했으나, 문제는 OpenQuery의 SQL문이 순수한 문자열만 가능 하도록 되어 있어서 파라미터(변수)를 사용할 수가 없었습니다.

SET XACT_ABORT ON;

DECLARE @ano VARCHAR(30) = 'S201910250010'

BEGIN DISTRIBUTED TRAN

UPDATE x
SET
    AcptYn = ''N'',
    AcptEmpCode = '''', 
    AcptDeptCode = '''',
    AcptDateTime = NULL
FROM
    OpenQuery (RemoteServer,
        '
        SELECT
            Trgt.*
        FROM RemoteDB.dbo.FIAccSlipAggreationNo AS A
            JOIN RemoteDB.dbo.FIAccSlipDisappMaster AS Trgt
                ON a.SlipNo = Trgt.SlipNo
        WHERE
            A.AggregationNo = ''' + @ano + '''
        '
    ) x

SET XACT_ABORT OFF;

COMMIT

그래서 최종적으로 OpenQuery를 포함한 전체 쿼리 문장을 문자열 변수에 넣고 EXEC()로 처리 하였습니다.

SET XACT_ABORT ON;

DECLARE @ano VARCHAR(30) = 'S201910250010'
DECLARE @sql varchar(max)

BEGIN DISTRIBUTED TRAN

set @sql = 
    '
    UPDATE x
    SET
        AcptYn = ''N'',
        AcptEmpCode = '''', 
        AcptDeptCode = '''',
        AcptDateTime = NULL
    FROM
        OpenQuery (RemoteServer,
            ''
            SELECT
                Trgt.*
            FROM RemoteDB.dbo.FIAccSlipAggreationNo AS A
                JOIN RemoteDB.dbo.FIAccSlipDisappMaster AS Trgt
                    ON a.SlipNo = Trgt.SlipNo
            WHERE
                A.AggregationNo = ''''' + @ano + '''''
            ''
        ) x
    '
EXEC(@sql)

SET XACT_ABORT OFF;

COMMIT

성능도 좋고, 파라미터(변수)도 처리할 수 있어서 만족할 만한 결과가 나왔습니다.
원격지 서버에 대한 갱신작업이 필요하실 때 참고 하시기 바랍니다.

반응형
반응형

SSMS 에서 Ctrl + M 을 눌러서 '실제 실행 계획 포함' 이 활성화 된 상태에서

쿼리를 실행 시키고 나면 실행계획이 함께 나타납니다.

실행계획 상의 특정 노드에 마우스를 가져가면 상세한 내용이 나타 납니다.

위 그림에서 '예상 행 수' 가 2.77684로 되어 있어 옵티마이저가 2.7행을 예상 했다고 생각할 수 있으나

실제 예상 행 수는 '예상 실행 횟수'를 곱한 값이 됩니다.

따라서 해당 노드에서 반환되는 총 예상 행 수는 2.77684 × 6985.3104807 = 19397.08956 입니다.

이 총 예상 행 수 값이 노드 하단의 분모 값 입니다.

그리고 분자 값은 '실제 행 수' 입니다. 

괄호 안의 %값은 총 예상 행 수 대비 실제 행 수의 백분율 입니다. 이 백분율 값이 100%에 가까울 수록

통계값에 의한 적절한 실행계획이 수립되었다고 볼 수 있습니다.

 

그러나 아래의 경우 처럼 이 값이 과도하게 적거나 많을 경우 통계가 제대로 갱신되지 않아서 엉뚱한 실행계획이

수립되었을 가능성이 있습니다.

이 경우 UPDATE STATISTICS 로 최신 통계로 업데이트가 필요 합니다.


※ [2020.10.29] 추가.
SSMS 버전 18.5 이후에 실행계획 항목(속성) 일부의 명칭이 바뀌고, 추가된 것으로 확인 됩니다.

SSMS v18.6

기존 '실제 행 수'가 '모든 실행에 대한 실제 행 수'로, 기존 '예상 행 수'가 '실행당 예상 행 수'로 
각각 명칭이 변경 되었습니다. 그리고 '모든 실행에 대한 예상 행 수' 속성이 추가 되었습니다.

같은 실행계획을 이전의 SSMS 에서 확인했을 때는 다음과 같았습니다.

SSMS v12.0

반응형
반응형

SSMS 이전버전에서는 로그인 암호 파일이 별도로 있어서 해당 파일만 삭제 하면 해결 되었으나,

(SQL 서버 2008 SSMS 로그인시 암호저장이 잘 안될때 참조)

SSMS v.18에서는 해당파일 자체가 존재 하지 않아서 기존방법으로는 자동로그인 된 정보를

삭제할 수가 없습니다.

 

해결방법은 의외로 간단한데, 

로그인 화면에서 '로그인(L):' 드롭박스를 클릭해서 나오는 리스트에서 아래 그림과 같이 원하는 로그인명에 마우스 커서를 둔 상태에서 Del 키로 삭제하면 됩니다.

삭제 후 다시 로그인과 암호를 입력하고 '암호 저장'에 체크를 해서 성공적으로 로그인이 되면 암호저장이 정상적으로 됩니다.

저는 처음에 이걸 몰라서 좀 애를 먹었다는...^^

반응형
반응형
아시는 바와 같이 임시 테이블은 #(로컬) 및 ##(전역)이 prefix로 붙은 테이블 입니다.
그리고 테이블변수는 TABLE 타입으로 DECLARE된 로컬변수 입니다.
 
둘 간에 여러가지 차이점이 있지만 여기서는 성능적인 이슈만 언급 하겠습니다.
테이블변수의 문제는 SQL서버가 통계정보를 생성하지 않기 때문에 적절한 실행계획 수립이 안될 수 있다는 점 입니다.
 
아래는 테이블변수를 사용한 특정 SP의 실행계획 입니다 (처리속도는 14초).

NL JOIN 으로 처리되어 과도한 Execute, Rows가 나왔습니다. SQL 서버가 NL을 선택한 것은 예상 행수가 모두 1 이기 때문 입니다.
예상 행수가 1:1 이기 때문에 NL로 처리해도 아무 문제가 없다고 판단이 되었습니다.
실제 테이블변수의 행은 1067 입니다.
 
이제 다른것은 그대로 두고 테이블변수를 임시테이블로만 변경한 후, 다시 실행계획을 확인 해봅니다 (처리속도는 6초).

이번에는 HASH JOIN 으로 처리 되었습니다. 이유는 예상행수가 1067, 617 이기 때문 입니다.
1067건과 617건을 NL JOIN 으로 처리하면 부하가 크다고 판단하고 HASH로 JOIN 전략을 변경한 겁니다.
 
결론적으로 일반적으로 행수가 적은 경우는 테이블변수를 사용해도 무관하지만, 크기가 큰 경우는 임시테이블을 사용해야 성능이슈가 발생하지 않게 됩니다.
 
 

 

반응형

+ Recent posts