TVP'ler neden READONLY olmalı ve neden diğer türdeki parametreler READONLY olamaz?


19

Bu blog'a göre bir işleve veya saklı bir yordama ait OUTPUTparametreler, eğer parametreler değilse , esasen değere göre değerlenirler ve eğer parametreler ise, esasen daha güvenli bir referans olarak değerlendirilirler OUTPUT.

İlk başta TVP'nin ilan edilmesini zorlamanın amacının, READONLYgeliştiricilere TVP'nin bir OUTPUTparametre olarak kullanılamayacağını açıkça belirtmek olduğunu düşündüm , ancak daha fazla olmalı, çünkü TVP olmayan olarak ilan edemeyiz READONLY. Örneğin, aşağıdakiler başarısız olur:

create procedure [dbo].[test]
@a int readonly
as
    select @a

Msg 346, Seviye 15, Durum 1, Prosedür testi
"@a" parametresi tablo değerli bir parametre olmadığı için READONLY olarak bildirilemez.

  1. Yana istatistikleri saklanmaz TVP DML işlemleri engelleyerek arkasındaki mantık nedir?
  2. TVP'nin OUTPUTbir nedenden dolayı parametre olmasını istememekle mi ilgili ?

Yanıtlar:


19

Açıklama, aşağıdakilerin bir kombinasyonuna bağlı gibi görünmektedir: a) bağlantılı blogdan bu soruda bahsedilmeyen bir detay, b) parametrelerin her zaman içeri ve dışarı nasıl aktarıldığına uyan TVP'lerin pragmatikleri, c) ve doğa tablo değişkenleri.

  1. Bağlantılı blog gönderisinde yer alan eksik ayrıntı, değişkenlerin Saklı Yordamlar ve İşlevlere nasıl ve nasıl aktarıldıklarıdır ("ÇIKIŞ parametreleri ise daha güvenli bir pass-by referans sürümü" sorusundaki ifadeyle ilgilidir). :

    TSQL parametreleri saklı yordamlar ve işlevlere iletmek için bir kopyala / kopyala semantik kullanır.

    ... saklanan proc yürütmeyi bitirdiğinde (bir hataya çarpmadan), depolanan proc'ta yapılan değişikliklerle iletilen parametreyi güncelleyen bir kopyalama yapılır.

    Bu yaklaşımın gerçek yararı hata durumundadır. Saklı yordamın yürütülmesinin ortasında bir hata oluşursa, parametrelerde yapılan herhangi bir değişiklik arayan kişiye geri yayılmaz.

    OUTPUT anahtar sözcüğü yoksa, kopyalama yapılmaz.

    Alt satır:
    Saklanan procs parametreleri, bir hata ile karşılaşırsa saklanan proc'un kısmen yürütülmesini asla yansıtmaz.

    Bu bulmacanın 1. kısmı parametrelerin her zaman "değere göre" iletilmesidir. Ve yalnızca parametre olarak işaretlendiğinde OUTPUT ve Saklı Yordam başarıyla tamamlandığında geçerli değerin gerçekten geri gönderilmesi gerekir. Eğer OUTPUTdeğerler gerçekten "referans olarak" geçirildi, daha sonra bu değişkenin bellekte konumu işaretçisi geçildi şey değil değerin kendisi olacaktır. İşaretçiyi (yani bellek adresi) geçirirseniz, Saklı Yordamın bir sonraki satırı bir hataya neden olsa ve yürütmeyi durdursa bile, yapılan değişiklikler hemen yansıtılır.

    Kısım 1'i özetlemek gerekirse: değişken değerler daima kopyalanır; bellek adresleri tarafından referans verilmez.

  2. Bölüm 1 göz önünde bulundurulduğunda, değişken değerleri her zaman kopyalama ilkesi, iletilen değişken oldukça büyük olduğunda kaynak sorunlarına yol açabilir. Ben damla tipleri nasıl ele alındığını görmek test etmedim ( VARCHAR(MAX), NVARCHAR(MAX), VARBINARY(MAX), XML, ve artık kullanılmaması gerekir olanlar: TEXT, NTEXT, ve IMAGE), ancak herhangi bir veri tablosu oldukça büyük olabilir geçirilen söylemek güvenlidir. TVP özelliğini geliştirenlerin, havalı yeni özelliklerinin sağlıklı sayıda sistemi yok etmesini (yani daha ölçeklenebilir bir yaklaşım istemek) önlemek için gerçek bir "referansla geçme" yeteneğini arzulamaları mantıklı olacaktır. Belgelerde gördüğünüz gibi yaptıkları bu:

    Transact-SQL girdi verilerinin bir kopyasını yapmaktan kaçınmak için tablo değerli parametreleri yordamlara başvurur.

    Ayrıca, SQL Server 2005'te tanıtılan SQLCLR API'sinde (TVP'ler SQL Server 2008'de tanıtıldı) bulunabileceğinden, bu bellek yönetimi sorunu yeni bir kavram değildi. Geçerken NVARCHARve VARBINARY(a SQLCLR Meclis içinde .NET yöntemleri yani giriş parametreleri) SQLCLR koduna veri, ya kullanarak "değeri" yaklaşımı ile gitmek seçeneğine sahip SqlStringveya SqlBinarysırasıyla, yoksa "referans ile birlikte gidebilir "ya SqlCharsda SqlBytessırasıyla kullanarak yaklaşım . SqlCharsVe SqlBytestürleri (2 GB'ye kadar sağa) bütün bir 200 MB kopyalama değer aksine büyük değerlerin küçük parçalarını indirebiliriz şekilde .NET CLR içine tam veri akışı için izin verir.

    Özetle Kısım 2: TVP'ler, doğası gereği, "değeri her zaman kopyala" modelinde kalmaları durumunda çok fazla bellek (ve dolayısıyla performansı düşürür) kullanma eğiliminde olurlar. Bu nedenle TVP'ler gerçek bir "referansla geçer" yapar.

  3. Son bölüm, Bölüm 2'nin neden önemli olduğudur: Bir TVP'ye neden bir kopyasını değiştirmek yerine gerçekte "referans olarak" geçmek istesin. Ve bu, Bölüm 1: Başarıyla tamamlanmayan Saklı Yordamlar için temel olan tasarım hedefi tarafından yanıtlanır, herhangi bir şekilde, işaretlenmiş olsun OUTPUTveya olmasın, giriş parametrelerinin hiçbirini değiştirmemelidir. DML işlemlerine izin vermek, çağrı bağlamında var olduğu için TVP'nin değeri üzerinde hemen bir etkiye sahip olacaktır (referansla geçmek, iletilen şeyin bir kopyasını değil, geçirilen şeyi değiştirdiğiniz anlamına gelir).

    Şimdi, bir yerlerde, birisi bu noktada muhtemelen monitörleriyle konuşuyor, "Eh, sadece Saklı Yordam'a geçildiyse TVP parametrelerinde yapılan değişiklikleri geri almak için bir otomajik tesiste inşa edin. Duh. Sorun çözüldü." Çok hızlı değil. Tablo Değişkenlerinin niteliği burada devreye girer: Tablo Değişkenlerinde yapılan değişiklikler İşlemler ile sınırlı değildir! Yani değişiklikleri geri almanın bir yolu yok. Ve aslında, bu bir geri alma olması gerekiyorsa bir işlem içinde oluşturulan bilgileri kaydetmek için kullanılan bir hile :-).

    Özetle Bölüm 3: Tablo Değişkenleri, Saklı Yordamın iptal edilmesine neden olan bir hata durumunda kendilerine yapılan "geri alma" değişikliklerine izin vermez. Bu da kısmi yürütmeyi asla yansıtmayan parametrelere sahip olmanın tasarım amacını ihlal eder (Bölüm 1).

Ergo:READONLY TVP'lerde DML işlemlerini önlemek için anahtar kelime gereklidir, çünkü bunlar gerçekte "referans olarak" iletilen Tablo Değişkenleri'dir ve bu nedenle Kayıtlı Prosedür bir hatayla karşılaşsa bile bunlarda yapılacak değişiklikler hemen yansıtılır. bunu önlemenin başka bir yolu.

Ek olarak, diğer veri türlerinin parametreleri kullanılamaz READONLYçünkü bunlar zaten aktarılanların kopyalarıdır ve bu nedenle zaten korunmayan hiçbir şeyi korumaz. Bu, ve diğer veri türlerinin parametrelerinin çalışma şeklinin okuma-yazma olması amaçlanmıştır, bu nedenle API'nin şimdi salt okunur bir konsept içerecek şekilde değiştirilmesi muhtemelen daha da fazla iş olacaktır.


Çok ayrıntılı bir açıklama. Teşekkürler. Bu nedenle, geçirilen bir tablo değişkenini (bir kullanıcı TVP TYPEdeğişkeni veya a DECLARE x as TABLE (...)) saklı yordamla değiştirmenin bir yolu yok mu? Bunun yerine bir işlevle, daha büyük bir bellek ayak izi de olsa yapabilir misin set @tvp = myfunction(@tvp)benim işlevin eğer RETURNSdeğer TVP türü ile aynı DDL ile tablodur?
mpag

@mpag Teşekkürler. Bir JP olan bir fark yoktur, bir tablo değişkeni. Yazmayı geçmezsiniz, bir türden veya açık bir şema bildiriminden oluşturulan bir tablo değişkenini iletirsiniz. Ayrıca, SETbir tablo değişkeni olamaz , en azından farkında değilim. Ve yapabilseniz bile: a) =operatör aracılığıyla bir sonuç kümesine erişemezsiniz ve b) TVP hala olarak işaretlenir READONLY, bu yüzden ayarlanması bunu ihlal eder. İçeriği geçici tabloya veya proc içinde oluşturduğunuz başka bir tablo değişkenine dökün.
Solomon Rutzky

Tekrar teşekkürler. Aslında geçici bir tablo yaklaşımı kullanmaya karar verdim.
mpag

5

Topluluk Wiki cevabı Martin Smith tarafından soru üzerine yapılan bir yorumdan üretildi

Bunun için aktif bir Connect öğesi (Erland Sommarskog tarafından gönderilen) var:

SP'ler birbirini çağırdığında tablo parametrelerinin salt okunur olması gerektiği kısıtlamasını gevşetin

Microsoft tarafından şu ana kadar verilen tek yanıt şöyle diyor (vurgu eklendi):

Bu konuyla ilgili geri bildiriminiz için teşekkür ederiz. Çok sayıda müşteriden benzer geri bildirimler aldık. Tablo değerli parametrelerin okunmasına / yazılmasına izin vermek, SQL Engine tarafında ve istemci protokollerinde biraz çalışma gerektirir. Zaman / kaynak kısıtlamaları ve diğer öncelikler nedeniyle, bu çalışmayı SQL Server 2008 sürümünün bir parçası olarak kabul edemeyiz. Ancak, bu sorunu araştırdık ve SQL Server'ın bir sonraki sürümünün bir parçası olarak bunu ele almak için radarımızda sağlam bir şekilde ele aldık. Biz burada geribildirim için teşekkür ederiz.

Srini Acharya
Kıdemli Program Yöneticisi
SQL Server İlişkisel Motoru

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.