Sorun : sp_executesql parametresi olarak kullanıcı tanımlı tablo türleriyle ilgili bilinen bir sorun var mı? Cevap - hayır, ben aptalım.
Komut dosyası oluştur
Bu komut dosyası, tablo, yordam ve kullanıcı tanımlı tablo türlerinin her birini oluşturur (yalnızca sınırlı SQL Server 2008+).
Yığın amacı, evet, verilerin prosedürü gerçekleştirdiğine dair bir denetim sağlamaktır. Hiçbir kısıtlama yoktur, verilerin eklenmesini engelleyecek hiçbir şey yoktur.
Yordam parametre olarak kullanıcı tanımlı bir tablo türünü alır. Proc'un yaptığı tüm tabloya eklemek.
Kullanıcı tanımlı tablo türü de bataklık basit, sadece tek bir sütun
Aşağıdakilere karşı çalıştım 11.0.1750.32 (X64)
ve 10.0.4064.0 (X64)
Evet, kutunun yamanabileceğini biliyorum, bunu kontrol etmiyorum.
-- 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
Problem üretimi
Bu komut dosyası sorunu gösterir ve yürütülmesi beş saniye sürer. Kullanıcı tanımlı tablo türlerimin iki örneğini oluşturuyorum ve sonra bunları iki farklı şekilde geçirmeyi deniyorum sp_executesql
. İlk çağırmadaki parametre eşlemesi, SQL Profiler'den ne aldığımı taklit eder. Daha sonra prosedürü sp_executesql
sarıcı olmadan çağırıyorum .
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
Sonuçlar : Aşağıda sonuçlarım var. Tablo başlangıçta boş. Ben şimdiki zaman yayar ve iki çağrı yapmak sp_executesql
. Geçerli zamanı geçirmek ve yaymak için 5 saniye bekledikten sonra saklı yordamın kendisini çağırıp sonunda denetim masasını dökümü bekliyorum.
Zaman damgasından görebileceğiniz gibi, B kaydının kaydı düz saklı yordam çağrısına karşılık gelir. Ayrıca, SQLC kaydı yoktur.
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
Yırtma komut dosyası
Bu komut dosyası nesneleri doğru sırada kaldırır (yordamın başvurusu kaldırılmadan türü bırakamazsınız)
-- cleanup
DROP TABLE dbo.UDTT_holder
DROP PROCEDURE dbo.Repro
DROP TYPE dbo.UDTT
GO
Bu neden önemli?
Kod aptalca görünüyor ama ben proc "düz" bir çağrı vs sp_execute kullanımı üzerinde çok kontrol yok. Çağrı zincirini daha yukarıda, ADO.NET kütüphanesini kullanıyorum ve daha önce yaptığım gibi bir TVP'ye geçiyorum . Parametrenin türü doğru System.Data.SqlDbType.Structured olarak ve CommandType da System.Data.CommandType.StoredProcedure olarak ayarlanır .
Neden bir çaylağım
Rob ve Martin Smith görmediğimi gördüler - sp_executesql'e iletilen ifade @MetricData
parametreyi kullanmadı . Geçilmemiş / eşlenmiş bir parametre kullanılmayacak.
PowerShell benim çalışma C # tablo değerli parametre kodunu tercüme edildi ve derlenmiş beri hata kodu olamazdı ; hariç. Bu soruyu yukarı yazarken, ben ayarlanmamış fark etti CommandType
üzere StoredProcedure
bu çizgiyi ekledi ve kodu yeniden koştum ama sorun değildi farz böylece profilcisine içinde iz değişmedi bu yüzden.
Komik hikaye - güncellenen dosyayı kaydetmezseniz , çalıştırmak bir fark yaratmaz. Bu sabah var ve (kaydettikten sonra) yeniden koştu ve ADO.NET EXEC dbo.Repro @MetricData=@p3
hangi gayet iyi çalışır çevirdi .
dbo.Repro
ve iletilen parametreleri hiç kullanmaz.