SQL Server 연결된 서버 성능 : 원격 쿼리가 왜 그렇게 비쌉니까?


14

연결된 서버를 통해 연결된 두 개의 데이터베이스 서버가 있습니다. 둘 다 SQL Server 2008R2 데이터베이스이며 연결된 서버 연결은 현재 로그인의 보안 컨텍스트를 사용하여 일반 "SQL Server"링크를 통해 이루어집니다. 연결된 서버는 모두 동일한 데이터 센터에 있으므로 연결에 문제가 없어야합니다.

다음 쿼리를 사용하여 identifier원격으로 사용할 수 있지만 로컬에서는 사용할 수없는 열 값을 확인 합니다.

SELECT 
    identifier 
FROM LinkedServer.RemoteDb.schema.[TableName]

EXCEPT

SELECT DISTINCT
    identifier 
FROM LocalDb.schema.[TableName] 

두 테이블 모두 열에 비 클러스터형 인덱스가 identifier있습니다. 로컬에는 약 260 만 개의 행이 있으며 원격으로는 54 개입니다. 그러나 쿼리 계획을 볼 때 실행 시간의 70 %가 "원격 쿼리 실행"에 전념합니다. 또한 전체 쿼리 계획을 연구 할 때 예상 로컬 행 수는 1대신 2695380(다음에 오는 쿼리 만 선택할 때 예상 행 수 ) 대신에 사용됩니다 EXCEPT. 실행 계획 이 쿼리를 실행할 때 시간이 오래 걸립니다.

궁금합니다 : 왜 이런가요? 추정이 "정확한"방법입니까, 아니면 연결된 서버의 원격 쿼리가 실제로 그렇게 비쌉니까?


2
BTW : 인덱스 탐색을 위해 "추정 된 실행 횟수"입니다. 예상 행 수는 실행 당 행 출력이며 계획에 전체 스캔이 없으면 테이블 자체의 행 수와 관련이 없습니다.
Martin Smith

답변:


9

당신이 지금 가지고있는 계획은 나에게 가장 최적 인 계획처럼 보입니다.

2.6M 행을 원격 서버로 보내는 다른 답변의 주장에 동의하지 않습니다.

계획은 원격 쿼리에서 반환 된 54 행 각각에 대해 로컬 테이블로 인덱스 검색을 수행하여 일치하는지 여부를 결정하는 것처럼 보입니다. 이것은 거의 최적의 계획입니다.

테이블의 크기가 주어지면 해시 조인 또는 병합 조인으로 대체하는 것은 비생산적이며 중간 #temp테이블을 추가하면 아무런 이점이없는 추가 단계가 추가됩니다.


6

원격 리소스에 연결하는 데 많은 비용이 듭니다. 기간.

모든 프로그래밍 환경에서 가장 비싼 작업 중 하나는 네트워크 IO입니다 (디스크 IO가이를 감소시키는 경향이 있음).

이것은 원격으로 연결된 서버로 확장됩니다. 원격 연결된 서버를 호출하는 서버는 먼저 연결을 설정 한 다음 원격 서버에서 쿼리를 실행하고 결과를 반환하고 연결을 닫아야합니다. 이 모든 것은 네트워크를 통해 시간이 걸립니다.


또한 와이어를 통해 최소 데이터를 전송하는 방식으로 쿼리를 구성해야합니다. DB가 당신을 위해 최적화 될 것으로 기대하지 마십시오.

이 쿼리를 작성하려면 원격 데이터를 테이블 변수 또는 임시 테이블로 선택한 다음 로컬 테이블과 함께 사용합니다. 이를 통해 전송해야하는 데이터 만 보장됩니다.

실행중인 쿼리는 EXCEPT절 을 처리하기 위해 2.6M 개의 행을 원격 서버로 쉽게 보낼 수 있습니다 .


좋아, 그래서 연결을 설정하는 데 높은 시작 비용이 있습니다. 쿼리를 전송하고 원격으로 처리해야하며 (네트워크에 네트워크가 필요하지 않음) 마지막으로 결과를 다시 전송하고 처리해야합니다. 그러나 네트워크 연결을 통해 데이터를 전송하는 데 몇 분이 걸리지 않습니까?
vstrien

@vstrien-그럴 수도 있습니다. 네트워크 연결, 대기 시간, 채도 및 기타 요인에 따라 다릅니다. 요점-결정적이지 않습니다.

@vstrien-내 답변에 더 많은 정보가 추가되었습니다. 작성된 쿼리가 처리를 위해 로컬 행을 원격 서버로 보냅니다.

2
2.6M 행을 원격 서버로 전송한다는 사실을 어디에서 추론합니까? 원격 쿼리 연산자를 사용한 계획에 대해서는별로 경험이 없지만 54 행이 원격 쿼리 연산자에서 나오는 것처럼 보이면 로컬 테이블에 대해 반 세미 조인을 수행하는 것 같습니다.
Martin Smith

2
@Lieven-논리적 일 수 있지만 표시된 계획에서 올바른 것으로 생각하지 마십시오.
Martin Smith

1

저는 전문가는 아니지만 Union, Except 또는 Intersect를 사용하는 경우 "고유"를 사용할 필요가 없습니다. LocalDb.schema. [TableName]의 값에 따라 쿼리 성능이 향상 될 수 있습니다.

SELECT 
    identifier 
FROM LinkedServer.RemoteDb.schema.[TableName]

EXCEPT

SELECT 
    identifier 
FROM LocalDb.schema.[TableName]

0

Oded가 옳습니다. 성능 문제는 2.6M 행을 원격 서버로 전송하여 발생합니다.

이 문제를 해결하려면 temp 또는 in 메모리 테이블을 사용하여 원격 데이터 (54 행)를 보내도록 할 수 있습니다.

임시 테이블 사용

SELECT  identifier 
INTO    #TableName
FROM    LinkedServer.RemoteDb.schema.[TableName]

SELECT  identifier
FROM    #TableName
EXCEPT
SELECT  DISTINCT identifier 
FROM    LocalDb.schema.[TableName] 

DROP    #TableName

중첩 루프는 54 행에 대해서만 합리적으로 보이지만 임시 테이블을 사용하면 카디널리티 추정에 도움이 될 수 있습니다.
Martin Smith

임시 테이블을 사용하면 54 행에서 올바르게 작동합니다. 그러나 양쪽에 큰 테이블이있는 경우 더 이상 불가능합니다. 동일한 크기의 두 개의 "거대한"테이블에 대한 솔루션은 무엇입니까? 다른 데이터베이스에 UserTable을 만드시겠습니까?
vstrien

1
@vstrien-두 개의 동일한 크기의 거대한 테이블에는 실제로 좋은 해결책이 없습니다. 아마도 Distributed Partitioned View를 만드는 것이 관심이 있지만 그 경험이 전혀 없습니다.
Lieven Keersmaekers

0

쿼리하는 서버에 원격 테이블을 복제 한 다음 모든 SQL을 로컬로 실행하는 것이 좋습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.