Aracılığıyla paylaş


T-SQL tasarım sorunları

Şunlar için geçerlidir:SQL ServerAzure SQL VeritabanıAzure SQL Yönetilen ÖrneğiMicrosoft Fabric'te SQL veritabanı

Veritabanı projenizdeki T-SQL kodunu analiz ettiğinizde, bir veya daha fazla uyarı tasarım sorunları olarak kategorilere ayrılmış olabilir. Aşağıdaki durumlardan kaçınmak için tasarım sorunlarını gidermeniz gerekir:

  • Veritabanınızda yapılan sonraki değişiklikler, veritabanınıza bağımlı olan uygulamaları bozabilir.
  • Kod beklenen sonucu üretmeyebilir.
  • Sql Server'ın gelecek sürümleriyle çalıştırırsanız kod bozulabilir.

Genel olarak, bir tasarım sorununu gizlememeniz gerekir çünkü bu sorun uygulamanızı şimdi veya gelecekte bozabilir.

Sağlanan kurallar aşağıdaki tasarım sorunlarını tanımlar:

SR0001: Saklı yordamlarda, görünümlerde ve tablo değerli işlevlerde SELECT * kullanmaktan kaçınmalısınız

Bir tablo veya görünümdeki tüm sütunları seçmek için saklı yordam, görünüm veya tablo değerli işlevde joker karakter kullanırsanız, temel alınan tablo veya görünüm değiştiğinde döndürülen sütunların sayısı veya şekli değişebilir. Sütunun şekli, türünün ve boyutunun bir bileşimidir. Bu değişiklik, saklı yordam, görünüm veya tablo değerli işlevi kullanan uygulamalarda sorunlara neden olabilir çünkü bu kullanıcılar farklı sayıda sütun bekleyebilir.

İhlalleri düzeltme

Joker karakterini sütun adlarının tam listesiyle değiştirerek saklı yordamın, görünümün veya tablo değerli işlevin tüketicilerini şema değişikliklerinden koruyabilirsiniz.

Example

Aşağıdaki örnek önce [Tablo2] adlı bir tabloyu tanımlar ve ardından iki saklı yordamı tanımlar. İlk yordam, SR0001 kuralını ihlal eden bir SELECT *içerir. İkinci işlem, SELECT * atlayarak SELECT deyimindeki sütunları açıkça listeler.

CREATE TABLE [dbo].[Table2]
(
[ID] INT NOT NULL IDENTITY(0, 1),
[c1] INT NOT NULL,
[Comment] NVARCHAR (50)
)
ON [PRIMARY]

CREATE PROCEDURE [dbo].[procWithWarning]
AS
BEGIN
-- Contains code that breaks rule SR0001
SELECT *
FROM [dbo].[Table2]
END

CREATE PROCEDURE [dbo].[procFixed]
AS
BEGIN
-- Explicitly lists the column names in a SELECT statement
SELECT [dbo].[Table2].[ID], [dbo].[Table2].[c1], [dbo].[Table2].[Comment]
FROM [dbo].[Table2]
END

SR0008: @@IDENTITY yerine SCOPE_IDENTITY kullanmayı göz önünde bulundurun

@@IDENTITY genel bir kimlik değeri olduğundan, geçerli kapsamın dışında güncelleştirilmiş ve beklenmeyen bir değer almış olabilir. Çoğaltma tarafından kullanılan iç içe tetikleyiciler dahil olmak üzere diğer tetikleyiciler, mevcut kapsamınızın dışında @@IDENTITY güncelleyebilir.

İhlalleri düzeltme

Bu sorunu çözmek için @@IDENTITY başvurularını kullanıcı deyimi kapsamındaki en son kimlik değerini döndüren SCOPE_IDENTITY ile değiştirmeniz gerekir.

Example

İlk örnekte, @@IDENTITY tabloya veri eklemek için kullanılan bir saklı yordamda kullanılır. Tablo, birleştirme çoğaltması için yayımlanır; bu, yayımlanan tablolara tetikleyiciler ekler. Bu nedenle @@IDENTITY, kullanıcı tablosuna ekleme işlemi yerine bir çoğaltma sistemi tablosuna ekleme işleminden değeri döndürebilir.

Tablonun Sales.Customer kimlik değeri üst sınırı 29483'tür. Tabloya satır eklerseniz, @@IDENTITY ve SCOPE_IDENTITY() farklı değerler döndürür. SCOPE_IDENTITY() kullanıcı tablosuna ekleme işleminden değeri döndürür, ancak @@IDENTITY çoğaltma sistemi tablosuna ekleme işleminden değeri döndürür.

İkinci örnekte, eklenen kimlik değerine erişmek ve uyarıyı çözümlemek için SCOPE_IDENTITY() özelliğini nasıl kullanabileceğiniz gösterilmektedir.

CREATE PROCEDURE [dbo].[ProcedureWithWarning]
@param1 INT,
@param2 NCHAR(1),
@Param3 INT OUTPUT
AS
BEGIN
INSERT INTO Sales.Customer ([TerritoryID],[CustomerType]) VALUES (@param1,@param2);

SELECT @Param3 = @@IDENTITY
END

CREATE PROCEDURE [dbo].[ProcedureFixed]
@param1 INT,
@param2 NCHAR(1),
@param3 INT OUTPUT
AS
BEGIN
INSERT INTO Sales.Customer ([TerritoryID],[CustomerType]) VALUES (@param1,@param2);

SELECT @Param3 = SCOPE_IDENTITY()
END

SR0009: Boyut 1 veya 2 olan değişken uzunluğu türlerini kullanmaktan kaçının

VARCHAR, NVARCHAR ve VARBINARY gibi değişken uzunlukta veri türlerini kullandığınızda, veri türünde depolanan değerin uzunluğunu izlemek için ek bir depolama maliyetine neden olursunuz. Ayrıca, değişken uzunluktaki sütunlar sabit uzunluktaki tüm sütunlardan sonra depolanır ve bu da performans açısından etkilenebilir. VARCHAR gibi bir değişken uzunluğu türü bildirirseniz ancak uzunluk belirtmezseniz de bir uyarı alırsınız. Bu uyarı, belirtilmezse varsayılan uzunluğun 1 olması nedeniyle oluşur.

İhlalleri düzeltme

Türün uzunluğu çok küçük (boyut 1 veya 2) ve tutarlı olacaksa, bunları CHAR, NCHAR ve BINARY gibi sabit uzunlukta bir tür olarak bildirin.

Example

Bu örnekte iki tablonun tanımları gösterilmektedir. İlk tablo, uzunluğu 2 olan değişken uzunlukta bir dize bildirir. İkinci tablo bunun yerine sabit uzunlukta bir dize bildirir ve bu da uyarıyı önler.

CREATE TABLE [dbo].[TableWithWarning]
(
[ID] INT NOT NULL IDENTITY(0, 1),
[c1] INT NOT NULL PRIMARY KEY,
[c2] INT,
[c3] INT,
[SmallString] VARCHAR(2)
)
ON [PRIMARY]

CREATE TABLE [dbo].[FixedTable]
(
[ID] INT NOT NULL IDENTITY(0, 1),
[c1] INT NOT NULL PRIMARY KEY,
[c2] INT,
[c3] INT,
[SmallString] CHAR(2)
)
ON [PRIMARY]

Değişken uzunluğu türlerine ilişkin veriler, sabit uzunluk türleri için verilerden sonra fiziksel olarak depolanır. Bu nedenle, boş olmayan bir tabloda bir sütunu değişkenden sabit uzunluğa değiştirirseniz veri taşımaya neden olursunuz.

SR0010: Tabloları veya görünümleri birleştirirken kullanım dışı söz dizimi kullanmaktan kaçının

Kullanım dışı söz dizimini kullanan birleşimler iki kategoriye ayrılır:

  • İç Birleşim: İç birleşim için, birleştirilmekte olan sütunlardaki değerler =, <, >= gibi bir karşılaştırma işleci kullanılarak karşılaştırılır. İç birleşimler yalnızca her tablodan en az bir satır birleştirme koşuluyla eşleşiyorsa satırları döndürür.
  • Dış Birleşim: Dış birleşimler, FROM yan tümcesinde belirtilen tablo veya görünümlerden en az birindeki tüm satırları döndürür. Bu satırlar WHERE veya HAVING arama koşullarını karşıladığı sürece. Dış birleşim belirtmek için = veya = kullanırsanız, kullanım dışı söz dizimi kullanırsınız.

İhlalleri düzeltme

İç birleşimdeki bir ihlali düzeltmek için söz dizimini INNER JOIN kullanın.

Dış birleşimdeki bir ihlali düzeltmek için uygun OUTER JOIN söz dizimini kullanın. Aşağıdaki seçeneklere sahipsiniz:

  • LEFT OUTER JOIN veya LEFT JOIN (Sol Dış Birleştirme veya Sol Birleştirme)
  • SAĞ DIŞ BAĞLAMA veya SAĞ BAĞLAMA

Kullanım dışı söz dizimi ve güncelleştirilmiş söz dizimi örnekleri aşağıdaki örneklerde verilmiştir. Birleştirmeler hakkında daha fazla bilgi için bkz. Joins.

Examples

Altı örnek aşağıdaki seçenekleri gösterir:

  1. Örnek 1,iç birleşim için kullanım dışı söz dizimini gösterir.
  2. Örnek 2,Örnek 1'i geçerli söz dizimlerini kullanacak şekilde nasıl güncelleştirebileceğinizi gösterir.
  3. Örnek 3, sol dış birleşim için artık kullanılmayan söz dizimini gösterir.
  4. Örnek 4,Örnek 2'yi geçerli söz dizimlerini kullanacak şekilde nasıl güncelleştirebileceğinizi gösterir.
  5. Örnek 5,sağ dış birleşim için kullanım dışı söz dizimini gösterir.
  6. Örnek 6,Örnek 5'i geçerli söz dizimlerini kullanacak şekilde nasıl güncelleştirebileceğinizi gösterir.
-- Example 1: Deprecated syntax for an inner join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] T2, [dbo].[Table1] T1
WHERE [T1].[ID] = [T2].[ID]

-- Example 2: Current syntax for an inner join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] AS T2
INNER JOIN [dbo].[Table1] as T1
ON [T2].[ID] = [T2].[ID]

-- Example 3: Deprecated syntax for a left outer join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] T2, [dbo].[Table1] T1
WHERE [T1].[ID] *= [T2].[ID]

-- Example 4: Fixed syntax for a left outer join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] AS T2
LEFT OUTER JOIN [dbo].[Table1] as T1
ON [T2].[ID] = [T2].[ID]

-- Example 5: Deprecated syntax for a right outer join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] T2, [dbo].[Table1] T1
WHERE [T1].[ID] =* [T2].[ID]

-- Example 6: Fixed syntax for a right outer join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] AS T2
RIGHT OUTER JOIN [dbo].[Table1] as T1
ON [T2].[ID] = [T2].[ID]

SR0013: Çıkış parametresi (parametre) tüm kod yollarında doldurulmuyor

Bu kural, saklı yordam veya işlev aracılığıyla çıkış parametresinin bir veya daha fazla kod yolundaki bir değere ayarlanmadığı kodu tanımlar. Bu kural çıkış parametresinin hangi yollarda ayarlanması gerektiğini belirlemez. Birden çok çıkış parametresinde bu sorun varsa, her parametre için bir uyarı görüntülenir.

İhlalleri düzeltme

Bu sorunu iki yoldan biriyle düzeltebilirsiniz. Çıkış parametrelerini yordam gövdesinin başında varsayılan bir değere başlatırsanız bu sorunu en kolay şekilde düzeltebilirsiniz. Bir alternatif olarak, çıkış parametresini parametrenin ayarlanmadığı belirli kod yollarında da bir değere ayarlayabilirsiniz. Ancak, karmaşık bir yordamda yaygın olmayan bir kod yolunu gözden kaçırabilirsiniz.

Important

Yordam bildiriminde bir değer belirtilmesi sorunu CREATE PROC MyProcedure (@param1 INT = 10 OUTPUT) çözmez. Yordam gövdesindeki çıkış parametresine bir değer atamanız gerekir.

Example

Aşağıdaki örnekte iki basit yordam gösterilmektedir. İlk yordam çıkış parametresinin @Sumdeğerini ayarlamaz. İkinci yordam, yordamın @Sum başlangıcında parametresini başlatır ve bu da değerin tüm kod yollarında ayarlanmasını sağlar.

CREATE PROCEDURE [dbo].[procedureHasWarning]
(
@Value1 BIGINT,
@Value2 INT,
@Value3 INT,
@Sum INT OUTPUT
)
AS
BEGIN
-- No initialization of the output parameter
--
-- Additional statements here.
--
RETURN 0;
END
--
CREATE PROCEDURE [dbo].[procedureFixed]
(
@Value1 BIGINT,
@Value2 INT,
@Value3 INT,
@Sum INT OUTPUT
)
AS
BEGIN
-- Initialize the out parameter
SET @Sum = 0;
--
-- Additional statements here
--
RETURN 0;
END

SR0014: {Type1} öğesinden {Type2} türüne veri kaybı oluşabilir

Veri türleri sütunlara, değişkenlere veya parametrelere tutarsız bir şekilde atanmışsa, bu nesneleri içeren Transact-SQL kodu çalıştırıldığında bunlar örtük olarak dönüştürülür. Bu tür bir dönüştürme yalnızca performansı düşürmekle kalmaz, bazı durumlarda küçük veri kaybına da neden olur. Örneğin, WHERE yan tümcesindeki her sütunun dönüştürülmesi gerekiyorsa tablo taraması çalıştırılabilir. Daha da kötüsü, Unicode dizesi farklı bir kod sayfası kullanan bir ASCII dizesine dönüştürülürse veriler kaybolabilir.

Bu kural şunları YAPMAZ:

  • Hesaplanan sütunun türünü denetleyin, çünkü tür çalışma zamanına kadar bilinmez.
  • CASE deyimi içindeki her şeyi analiz edin. Ayrıca CASE deyiminin dönüş değerini analiz etmez.
  • ISNULL çağrısının giriş parametrelerini veya dönüş değerini analiz etme

Bu tabloda SR0014 kuralı kapsamındaki denetimler özetlenmiş:

Dil yapısıKontrol Edilen Nedir?Example
Parametrelerin varsayılan değeriParametre veri türü
CREATE PROCEDURE p1(@p1 INT = 1)
AS
BEGIN
END
CREATE INDEX koşuluKoşul Boole değeridir
CREATE INDEX index1 ON table1 (column1)
WHERE column1 > 10
SOL veya SAĞ işlevlerinin bağımsız değişkenleriDize bağımsız değişkeni türü ve uzunluğu
SET @v = LEFT('abc', 2)
CAST ve CONVERT işlevlerinin bağımsız değişkenleriİfade ve tipler geçerli
SET @v = CAST('abc' AS CHAR(10))
SET deyimiSol ve sağ tarafta uyumlu tipler bulunuyor
SET @v1 = 'xyz'
SELECT @v1 = c1 FROM t1
IF ifadesi şarta bağlıKoşul Boole değeridir
IF (@v > 10)
WHILE deyimi koşuluKoşul Boole değeridir
WHILE (@v > 10)
INSERT deyimiDeğerler ve sütunlar doğru
INSERT INTO t1(c1, c2) VALUES (99, 'xyz')
INSERT INTO t1 SELECT c1 FROM t2.
SELECT WHERE önermesiKoşul Boole değeridir
SELECT * FROM t1 WHERE c1 > 10
SELECT TOP ifadesiİfade bir Tamsayı veya Float türüdür
SELECT TOP 4 * FROM t1
SELECT TOP 1.5 PERCENT * FROM t1
UPDATE deyimiİfade ve sütun uyumlu türlere sahiptir
UPDATE t1 SET c1 = 100
UPDATE koşuluKoşul Boole değeridir
UPDATE t1 SET c1 = 100
WHERE c1 > 100
UPDATE TOP ifadesiİfade bir Tamsayı veya Float türüdür
UPDATE TOP 4 table1
KOŞUL İFADESİNİ SİLKoşul Boole değeridir
DELETE t1 WHERE c1 > 10
DELETE TOP ifadesiİfade bir Tamsayı veya Float türüdür
DELETE TOP 2 FROM t1
DECLARE değişken tanımlamaİlk değer ve veri türü uyumludur
DECLARE @v INT = 10
EXECUTE deyimi bağımsız değişkenleri ve dönüş türüParametreler ve bağımsız değişkenler
CREATE PROCEDURE p1 (@p1 INT) AS
GO
EXECUTE p1 100
EXECUTE @v1 = p1 100
RETURN deyimiRETURN ifadesi uyumlu bir veri türüne sahip
CREATE FUNCTION f1() RETURNS INT
AS
BEGIN
  RETURN 100
END
MERGE deyimi koşullarıKoşul Boole değeridir
MERGE t1 USING t2
ON t1.c1 = t2.c2
WHEN t1.c1 > 10 THEN DELETE

İhlalleri düzeltme

Veri türlerini tutarlı bir şekilde atayarak ve gerektiğinde türleri açıkça dönüştürerek bu sorunlardan kaçınabilir ve çözebilirsiniz. Veri türlerini açıkça dönüştürme hakkında daha fazla bilgi için Microsoft Web sitesindeki şu sayfaya bakın: CAST ve CONVERT (Transact-SQL).

Example

Örnekte, iki saklı prosedür ile bir tabloya veri ekleme işlemi gösterilmektedir. İlk yordam olan procWithWarning, bir veri türünün örtük olarak dönüştürülmesiyle sonuçlanır. İkinci yordam olan procFixed, performansı en üst düzeye çıkarmak ve tüm verileri korumak için nasıl açık dönüştürme ekleyebileceğinizi gösterir.

CREATE TABLE [dbo].[Table2]
(
[ID] INT NOT NULL IDENTITY(0, 1),
[c1] INT NOT NULL,
[c2] INT NOT NULL,
[c3] BIGINT NOT NULL,
[Comment] VARCHAR (25)
)
ON [PRIMARY]

CREATE PROCEDURE [dbo].[procWithWarning]
(
@Value1 INT,
@Value2 INT,
@Value3 BIGINT,
@Comment CHAR(30)
)
AS
BEGIN
INSERT INTO [Table2] ([c1], [c2], [c3], Comment)
VALUES (@Value1, @Value2, @Value3, @Comment)

END

CREATE PROCEDURE [dbo].[procFixed]
(
@Value1 INT,
@Value2 INT,
@Value3 BIGINT,
@Comment CHAR(10)
)
AS
BEGIN
INSERT INTO [Table2] ([c1], [c2], [c3], Comment)
VALUES (@Value1, @Value2, @Value3, CAST(@Comment AS VARCHAR(25)))

END