문제점 : sp_executesql에 대한 매개 변수로 사용자 정의 테이블 유형에 알려진 문제점이 있습니까? 답변-아니요, 저는 바보입니다.
스크립트 설정
이 스크립트는 각 테이블, 프로 시저 및 사용자 정의 테이블 형식 중 하나를 만듭니다 (제한된 SQL Server 2008+ 만 해당).
힙의 목적은 예, 데이터가이를 프로 시저로 만들었다는 감사를 제공하는 것입니다. 데이터가 삽입되는 것을 막을 수있는 제약은 없습니다.
프로시 저는 사용자 정의 테이블 유형을 매개 변수로 사용합니다. 모든 프로세스는 테이블에 삽입됩니다.
사용자 정의 테이블 유형은 단순하지만 단 하나의 열입니다.
나는에 대해 다음을 실행 한 11.0.1750.32 (X64)
및 10.0.4064.0 (X64)
예, 나는 그것을 제어하지 않는, 그 상자를 패치 할 수 있습니다 알고있다.
-- this table record that something happened
CREATE TABLE dbo.UDTT_holder
(
ServerName varchar(200)
, insert_time datetime default(current_timestamp)
)
GO
-- user defined table type transport mechanism
CREATE TYPE dbo.UDTT
AS TABLE
(
ServerName varchar(200)
)
GO
-- stored procedure to reproduce issue
CREATE PROCEDURE dbo.Repro
(
@MetricData dbo.UDTT READONLY
)
AS
BEGIN
SET NOCOUNT ON
INSERT INTO dbo.UDTT_holder
(ServerName)
SELECT MD.* FROM @MetricData MD
END
GO
문제 재현
이 스크립트는 문제를 보여 주며 실행하는 데 5 초가 걸립니다. 사용자 정의 테이블 형식의 두 인스턴스를 만든 다음에 전달하는 두 가지 다른 방법을 시도합니다 sp_executesql
. 첫 번째 호출의 매개 변수 매핑은 SQL 프로파일 러에서 캡처 한 내용을 모방합니다. 그런 다음 sp_executesql
랩퍼 없이 프로 시저를 호출합니다 .
SET NOCOUNT ON
DECLARE
@p3 dbo.UDTT
, @MetricData dbo.UDTT
INSERT INTO @p3 VALUES(N'SQLB\SQLB')
INSERT INTO @MetricData VALUES(N'SQLC\SQLC')
-- nothing up my sleeve
SELECT * FROM dbo.UDTT_holder
SELECT CONVERT(varchar(24), current_timestamp, 121) + ' Firing sp_executesql' AS commentary
-- This does nothing
EXECUTE sp_executesql N'dbo.Repro',N'@MetricData dbo.UDTT READONLY',@MetricData=@p3
-- makes no matter if we're mapping variables
EXECUTE sp_executesql N'dbo.Repro',N'@MetricData dbo.UDTT READONLY',@MetricData
-- Five second delay
waitfor delay '00:00:05'
SELECT CONVERT(varchar(24), current_timestamp, 121) + ' Firing proc' AS commentary
-- this does
EXECUTE dbo.Repro @p3
-- Should only see the latter timestamp
SELECT * FROM dbo.UDTT_holder
GO
결과 : 아래는 내 결과입니다. 테이블은 처음에 비어 있습니다. 현재 시간을 내고에 두 번 전화를 sp_executesql
겁니다. 5 초 동안 기다렸다가 현재 시간을 내 보낸 다음 저장 프로 시저 자체를 호출하고 마지막으로 감사 테이블을 덤프합니다.
타임 스탬프에서 볼 수 있듯이 B 레코드의 레코드는 스트레이트 스토어드 프로 시저 호출에 해당합니다. 또한 SQLC 레코드가 없습니다.
ServerName insert_time
------------------------------------------------------------------------
commentary
-------------------------------------------------
2012-02-02 13:09:05.973 Firing sp_executesql
commentary
-------------------------------------------------
2012-02-02 13:09:10.983 Firing proc
ServerName insert_time
------------------------------------------------------------------------
SQLB\SQLB 2012-02-02 13:09:10.983
스크립트를 찢어
이 스크립트는 객체를 올바른 순서로 제거합니다 (프로 시저 참조가 제거되기 전에 유형을 삭제할 수 없음)
-- cleanup
DROP TABLE dbo.UDTT_holder
DROP PROCEDURE dbo.Repro
DROP TYPE dbo.UDTT
GO
이것이 중요한 이유
코드는 어리석은 것처럼 보이지만 proc에 대한 "직선적 인"호출에 대한 sp_execute의 사용을 많이 제어 할 수는 없습니다. 콜 체인을 높이면 ADO.NET 라이브러리를 사용하고 이전 과 같이 TVP를 전달 합니다. 매개 변수 유형은 System.Data.SqlDbType.Structured 로 올바르게 설정되고 CommandType은 System.Data.CommandType.StoredProcedure 로 설정됩니다 .
내가 멍청한 이유
Rob과 Martin Smith는 내가 보지 못한 것을 보았습니다. sp_executesql에 전달 된 명령문은 @MetricData
매개 변수를 사용하지 않았습니다 . 전달되지 않은 / 매핑 된 매개 변수는 사용되지 않습니다.
작업중인 C # 테이블 반환 매개 변수 코드를 PowerShell로 변환하고 컴파일 된 이후 오류가 발생한 코드 일 수 없습니다 . 제외했다. 이 질문을 쓰는 동안, 나는 내가 설정하지 않았 실현 CommandType
에 StoredProcedure
난 그 라인을 추가하고 코드를 재 - 실행하지만이 문제가되지 않았 음을 가정 있도록 프로파일 러의 추적이 변경하지 않은 때문에.
재미있는 이야기- 업데이트 된 파일을 저장 하지 않으면 실행해도 차이가 없습니다. 오늘 아침에 다시 저장 한 후 (저장 후) ADO.NET에서 제대로 EXEC dbo.Repro @MetricData=@p3
작동 하는 것으로 변환했습니다 .
dbo.Repro
전달 된 매개 변수를 전혀 사용하지 않습니다.