Ben doğru değeri sağlasam bile veritabanı her zaman varsayılan değerleri kontrol varsayalım, bu nedenle iki kez aynı işi yapıyorum.
Peki, neden bunu varsayıyorsun? ;-). Varsayılanların ekli oldukları sütun INSERT
deyimde mevcut olmadığında bir değer sağlamak için var olduğu göz önüne alındığında , tam tersini varsayarım: ilişkili sütun INSERT
deyimde mevcutsa tamamen yok sayılır .
Neyse ki, hiçbirimiz sorudaki bu ifade nedeniyle herhangi bir şey varsaymamız gerekmez:
Çoğunlukla performansla ilgileniyorum.
Performansla ilgili sorular neredeyse her zaman test edilebilir. Bu nedenle, SQL Server'ın (burada gerçek otorite) bu soruyu cevaplamasına izin vermek için bir test yapmamız gerekiyor.
KURMAK
Aşağıdakileri bir kez çalıştırın:
SET NOCOUNT ON;
-- DROP TABLE #HasDefault;
CREATE TABLE #HasDefault
(
[HasDefaultID] INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
[SomeInt] INT NULL,
[SomeDate] DATETIME NOT NULL DEFAULT (GETDATE())
);
-- DROP TABLE #NoDefault;
CREATE TABLE #NoDefault
(
[NoDefaultID] INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
[SomeInt] INT NULL,
[SomeDate] DATETIME NOT NULL
);
-- make sure that data file and Tran Log file are grown, if need be, ahead of time:
INSERT INTO #HasDefault ([SomeInt])
SELECT TOP (2000000) NULL
FROM [master].sys.[all_columns] ac1
CROSS JOIN [master].sys.[all_columns] ac2;
Testleri 1A ve 1B ayrı ayrı yapın, zamanlamayı çarpıttığı için birlikte değil. Her birinin ortalama zamanlamasını anlamak için her birini birkaç kez çalıştırın.
Test 1A
TRUNCATE TABLE #HasDefault;
GO
PRINT '#HasDefault:';
SET STATISTICS TIME ON;
INSERT INTO #HasDefault ([SomeDate])
SELECT TOP (1000000) '2017-05-15 10:11:12.000'
FROM [master].sys.[all_columns] ac1
CROSS JOIN [master].sys.[all_columns] ac2;
SET STATISTICS TIME OFF;
GO
Test 1B
TRUNCATE TABLE #NoDefault;
GO
PRINT '#NoDefault:';
SET STATISTICS TIME ON;
INSERT INTO #NoDefault ([SomeDate])
SELECT TOP (1000000) '2017-05-15 10:11:12.000'
FROM [master].sys.[all_columns] ac1
CROSS JOIN [master].sys.[all_columns] ac2;
SET STATISTICS TIME OFF;
GO
Testleri 2A ve 2B ayrı ayrı yapın, zamanlamayı çarpıttığı için birlikte değil. Her birinin ortalama zamanlamasını anlamak için her birini birkaç kez çalıştırın.
Test 2A
TRUNCATE TABLE #HasDefault;
GO
DECLARE @Counter INT = 0,
@StartTime DATETIME,
@EndTime DATETIME;
BEGIN TRAN;
--SET STATISTICS TIME ON;
SET @StartTime = GETDATE();
WHILE (@Counter < 100000)
BEGIN
INSERT INTO #HasDefault ([SomeDate]) VALUES ('2017-05-15 10:11:12.000');
SET @Counter = @Counter + 1;
END;
SET @EndTime = GETDATE();
--SET STATISTICS TIME OFF;
COMMIT TRAN;
PRINT DATEDIFF(MILLISECOND, @StartTime, @EndTime);
Test 2B
TRUNCATE TABLE #NoDefault;
GO
DECLARE @Counter INT = 0,
@StartTime DATETIME,
@EndTime DATETIME;
BEGIN TRAN;
--SET STATISTICS TIME ON;
SET @StartTime = GETDATE();
WHILE (@Counter < 100000)
BEGIN
INSERT INTO #NoDefault ([SomeDate]) VALUES ('2017-05-15 10:11:12.000');
SET @Counter = @Counter + 1;
END;
SET @EndTime = GETDATE();
--SET STATISTICS TIME OFF;
COMMIT TRAN;
PRINT DATEDIFF(MILLISECOND, @StartTime, @EndTime);
1A ve 1B testleri arasında veya 2A ve 2B testleri arasında gerçek bir zamanlama farkı olmadığını görmelisiniz. Yani, hayır, bir performans cezası yokDEFAULT
tanımlanmış ancak kullanılmamış .
Ayrıca, yalnızca amaçlanan davranışı belgelemenin yanı sıra, DML ifadelerinin saklı yordamlarınızda tamamen yer almasını önemseyenlerin siz olduğunu unutmayın. Destek millet umurumda değil. Gelecekteki geliştiriciler, tüm DML'leri bu saklı yordamlar içinde kapsülleme isteğinizin farkında olmayabilir veya bilmelerine rağmen dikkatli olabilirler. Ve gittikten sonra bu DB'yi kim tutarsa (başka bir proje ya da iş) umursamayabilir ya da ne kadar protesto etseler de bir ORM kullanımını engelleyemeyebilir. Öyleyse, Defaults, INSERT
özellikle ad-hoc yaparken insanlara bir "çıkış" vermelerine yardımcı olabilirINSERT
bir destek destek temsilcisi tarafından yapılan , çünkü eklemeye gerek duymadıkları bir sütun (bu yüzden denetimde her zaman varsayılanları kullanıyorum tarih sütunları).
VE bana DEFAULT
, INSERT
deyimde ilişkili sütun bulunduğunda a'nın işaretlenip denetlenmediğinin oldukça nesnel olarak gösterilebileceği bana geldi : sadece geçersiz bir değer sağlayın. Aşağıdaki test sadece bunu yapar:
-- DROP TABLE #BadDefault;
CREATE TABLE #BadDefault
(
[BadDefaultID] INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
[SomeInt] INT NOT NULL DEFAULT (1 / 0)
);
INSERT INTO #BadDefault ([SomeInt]) VALUES (1234); -- Success!!!
SELECT * FROM #BadDefault; -- just to be sure ;-)
INSERT INTO #BadDefault ([SomeInt]) VALUES (DEFAULT); -- Error:
/*
Msg 8134, Level 16, State 1, Line xxxxx
Divide by zero error encountered.
The statement has been terminated.
*/
SELECT * FROM #BadDefault; -- just to be sure ;-)
GO
Gördüğünüz gibi, bir sütun (ve anahtar kelime değil, bir değer DEFAULT
) sağlandığında, Varsayılan% 100 yoksayılır. Bunu biliyoruz çünkü INSERT
başarılı. Ancak Varsayılan kullanılırsa, sonunda yürütülmekte olan bir hata vardır.
Bir tetikleyici yürütmesinde DEFAULT kısıtlamasından kaçınmanın bir yolu var mı?
(Bu bağlamda en azından) Varsayılan Kısıtlamaları önlemek gerek ederken bütünlük uğruna buna sadece "kaçınmak" bir dahilinde Bir Hata Kısıtlama mümkün olacağını kaydetti edilebilir tamamen gereksizdir INSTEAD OF
ama, Tetikleyici değil bir mesafede AFTER
Tetikleyici. CREATE TRIGGER dokümanlarına göre :
Tetikleyici tabloda kısıtlamalar varsa, bunlar INSTEAD OF tetikleyici yürütme işleminden sonra ve AFTER tetikleyici yürütme işleminden önce kontrol edilir. Kısıtlamalar ihlal edilirse, INSTEAD OF tetikleyici eylemleri geri alınır ve AFTER tetikleyici tetiklenmez.
Tabii ki, bir INSTEAD OF
Tetik şunları gerektirir:
- Varsayılan Kısıtlamayı Devre Dışı Bırakma
AFTER
Kısıtlamayı etkinleştiren bir Tetikleyici oluşturma
Ancak, bunu tam olarak tavsiye etmem.