따라서 CAST
원격 인스턴스가 아닌 로컬에서 수행되고 있음을 깨닫고 오류를 재현 할 수있었습니다 . 이전에이 문제를 해결하기 위해 SP3로 업그레이드하는 것이 좋습니다 (부분적으로 SP3에서 오류를 재현 할 수없고 부분적으로는 좋은 아이디어이기 때문에). 그러나 이제 오류를 재현 할 수 있으므로 SP3로 이동하면 여전히 좋은 생각이지만이 문제를 해결하지 못할 것입니다. 또한 SQL Server 2008 R2 RTM 및 2014 SP1에서 오류를 재현했습니다 (세 가지 경우 모두 "루프백"로컬 연결 서버 사용).
이 문제와 함께 할 것 같다 경우 쿼리가 실행 또는 적어도 어디 부분 (들) 이 실행된다의. 나는 CAST
작업을 수행 할 수 있었지만 로컬 DB 객체에 대한 참조를 포함 시켜야만하기 때문에 이것을 말합니다 .
SELECT rmt.*, CAST(NULL AS UNIQUEIDENTIFIER) AS [GUID]
FROM [Local].[database_name].[dbo].[table_name] rmt
CROSS JOIN (SELECT TOP (1) 1 FROM [sys].[data_spaces]) tmp(dummy);
실제로 작동합니다. 그러나 다음은 원래 오류가 발생합니다.
SELECT rmt.*, CAST(NULL AS UNIQUEIDENTIFIER) AS [GUID]
FROM [Local].[database_name].[dbo].[table_name] rmt
CROSS JOIN (VALUES (1)) tmp(dummy);
로컬 참조가 없으면 전체 쿼리가 원격 시스템으로 전달되어 실행될 수 있으며 어떤 이유로 NULL
s로 변환 할 수 없거나 OLE DB 드라이버가 잘못 변환 한 UNIQUEIDENTIFIER
것으로 추측됩니다 NULL
.
내가 수행 한 테스트를 기반으로, 이것은 버그 인 것처럼 보이지만 버그가 SQL Server 또는 SQL Server Native Client / OLEDB 드라이버 내에 있는지 확실하지 않습니다. 그러나, 변환 오류가 OLEDB 드라이버 내에서 발생하는, 그래서 반드시에서 변환 문제가되지 않습니다 INT
에 UNIQUEIDENTIFIER
드라이버 때문에 (SQL 서버에서 허용되지 않는 변환) 변환을 (SQL 서버도하지 않습니다 할 SQL 서버를 사용하지 않는 변환 수 INT
를 DATE
테스트 중 하나)에 도시 한 바와 같이, 아직 성공적 OLEDB 드라이버 핸들.
나는 세 가지 테스트를 실행했다. 성공한 두 가지에 대해 원격으로 실행중인 쿼리를 보여주는 XML 실행 계획을 살펴 보았습니다. 세 가지 모두에 대해 SQL Profiler를 통해 예외 또는 OLEDB 이벤트를 캡처했습니다.
행사 :
- 오류 및 경고
- OLEDB
- TSQL
- 다음을 제외한 모두 :
- SQL : StmtRecompile
- XQuery 정적 유형
열 필터 :
테스트
시험 1
CAST(NULL AS UNIQUEIDENTIFIER)
작동합니다
SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
, (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
XML 실행 계획의 관련 부분 :
<DefinedValue>
<ColumnReference Column="Expr1002" />
<ScalarOperator ScalarString="NULL">
<Const ConstValue="NULL" />
</ScalarOperator>
</DefinedValue>
...
<RemoteQuery RemoteSource="Local" RemoteQuery=
"SELECT 1 FROM "TEMPTEST"."sys"."objects" "Tbl1001""
/>
시험 2
CAST(NULL AS UNIQUEIDENTIFIER)
그 실패
SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
-- , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
(참고 : 하위 쿼리를 거기에 보관하고 주석 처리 했으므로 XML 추적 파일을 비교할 때 차이가 적습니다.)
시험 3
SELECT TOP (2) CAST(NULL AS DATE) AS [Something]
-- , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
(참고 : 하위 쿼리를 거기에 보관하고 주석 처리 했으므로 XML 추적 파일을 비교할 때 차이가 적습니다.)
XML 실행 계획의 관련 부분 :
<DefinedValue>
<ColumnReference Column="Expr1002" />
<ScalarOperator ScalarString="[Expr1002]">
<Identifier>
<ColumnReference Column="Expr1002" />
</Identifier>
</ScalarOperator>
</DefinedValue>
...
<RemoteQuery RemoteSource="Local" RemoteQuery=
"SELECT TOP (2) NULL "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001""
/>
테스트 # 3을 보면 SELECT TOP (2) NULL
, "원격"시스템에서 작동하는 것입니다. SQL 프로파일 러 추적은이 원격 필드의 데이터 유형이 실제로 있음을 보여줍니다 INT
. 추적은 또한 클라이언트 측의 필드 (예 : 쿼리를 실행하는 위치)가 DATE
예상대로 있음을 보여줍니다. SQL Server에서 오류가 발생하는 에서 INT
로 변환 DATE
하는 것은 OLEDB 드라이버 내에서 잘 작동합니다. 원격 값은 NULL
이므로 직접 반환되므로 <ColumnReference Column="Expr1002" />
.
테스트 # 1을 보면 SELECT 1
, "원격"시스템에서 수행됩니다. SQL 프로파일 러 추적은이 원격 필드의 데이터 유형이 실제로 있음을 보여줍니다 INT
. 추적은 또한 클라이언트 측의 필드 (예 : 쿼리를 실행하는 위치)가 GUID
예상대로 있음을 보여줍니다. 에서 변환 INT
하려면 GUID
OLEDB를 드라이버 내에서 잘 작동, SQL 서버에 오류가 발생합니다 뭔가를 (이 드라이버 내에서 수행되며, OLEDB는 "GUID"이라고 부른다, 기억). 원격 값이 없다 NULL
가 리터럴로 대체되므로 NULL
, 이에 따라이 <Const ConstValue="NULL" />
.
테스트 # 2는 실패하므로 실행 계획이 없습니다. 그러나 "원격"시스템을 성공적으로 쿼리하지만 결과 집합을 전달할 수는 없습니다. SQL 프로파일 러가 캡처 한 쿼리는 다음과 같습니다.
SELECT TOP (2) NULL "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001"
그것은 테스트 # 1에서 수행되는 것과 똑같은 쿼리이지만 여전히 실패합니다. 다른 사소한 차이가 있지만 OLEDB 통신을 완전히 해석 할 수는 없습니다. 그러나 원격 필드는 여전히 INT
(wType = 3 = adInteger / 4 바이트 부호있는 정수 / DBTYPE_I4)로 표시되고 "client"필드는 여전히 GUID
(wType = 72 = adGUID / 전역 고유 식별자 / DBTYPE_GUID)로 표시됩니다. OLE DB 설명서는 GUID 데이터 형식 변환 , DBDATE 데이터 형식 변환 및 I4 데이터 형식 변환이 I4 에서 GUID 또는 DBDATE 로 변환하는 것이 지원되지 않지만 DATE
쿼리는 작동 하는 것으로 나타 났으므로 도움 이되지 않습니다 .
세 가지 테스트에 대한 Trace XML 파일은 PasteBin에 있습니다. 각 테스트와 다른 테스트의 차이점에 대한 세부 정보를 보려면 로컬로 저장 한 다음 "diff"를 수행하십시오. 파일은 다음과 같습니다
- NullGuidSuccess.xml
- NullGuidError.xml
- NullDateSuccess.xml
어고?
어떻게해야합니까? SQL Native Client-- SQLNCLI11
는 SQL Server 2012에서 더 이상 사용되지 않는다는 점을 감안할 때 맨 위 섹션에서 언급 한 해결 방법 일 것 입니다. SQL Server Native Client 주제에 대한 대부분의 MSDN 페이지에는 상단:
경고
SNAC (SQL Server Native Client)는 SQL Server 2012 이상에서 지원되지 않습니다. 새로운 개발 작업에서 SNAC를 사용하지 말고 현재이를 사용하는 응용 프로그램을 수정하십시오. SQL Server 용 Microsoft ODBC 드라이버는 마이크로 소프트 SQL 서버와 마이크로 소프트 애저 SQL 데이터베이스에 윈도우에서 기본 연결을 제공합니다.
자세한 내용은 다음을 참조하십시오.
ODBC ??
다음을 통해 ODBC 연결된 서버를 설정했습니다.
EXEC master.dbo.sp_addlinkedserver
@server = N'LocalODBC',
@srvproduct=N'{my_server_name}',
@provider=N'MSDASQL',
@provstr=N'Driver={SQL Server};Server=(local);Trusted_Connection=Yes;';
EXEC master.dbo.sp_addlinkedsrvlogin
@rmtsrvname=N'LocalODBC',
@useself=N'True',
@locallogin=NULL,
@rmtuser=NULL,
@rmtpassword=NULL;
그런 다음 시도했습니다.
SELECT CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
FROM [LocalODBC].[tempdb].[sys].[objects] rmt;
다음과 같은 오류가 발생했습니다.
연결된 서버 "LocalODBC"에 대한 OLE DB 공급자 "MSDASQL"이 "요청 된 변환이 지원되지 않습니다."라는 메시지를 반환했습니다.
메시지 7341, 수준 16, 상태 2, 줄 53 줄
"(사용자 생성 식) .Expr1002"의 현재 행 값을 연결된 서버 "LocalODBC"에 대한 OLE DB 공급자 "MSDASQL"에서 가져올 수 없습니다.
추신
원격 서버와 로컬 서버 간의 GUID 전송과 관련하여 NULL이 아닌 값은 특수 구문을 통해 처리됩니다. 실행했을 때 SQL 프로파일 러 추적에서 다음 OLE DB 이벤트 정보를 발견했습니다 CAST(0x00 AS UNIQUEIDENTIFIER)
.
<RemoteQuery RemoteSource="Local" RemoteQuery=
"SELECT {guid'00000000-0000-0000-0000-000000000000'} "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001""
/>
PPS
또한 OPENQUERY
다음 쿼리 를 통해 테스트했습니다 .
SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
--, (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM OPENQUERY([Local], N'SELECT 705 AS [dummy] FROM [TEMPTEST].[sys].[objects];') rmt;
로컬 객체 참조가 없어도 성공했습니다. SQL 프로파일 러 추적 XML 파일은 다음 위치에 PasteBin에 게시되었습니다.
NullGuidSuccessOPENQUERY.xml
XML 실행 계획은 NULL
테스트 # 1과 같은 상수를 사용하여 보여줍니다 .