ฉันคิดว่าฐานข้อมูลกำลังตรวจสอบค่าเริ่มต้นเสมอแม้ว่าฉันจะให้ค่าที่ถูกต้องดังนั้นฉันจึงทำงานเดียวกันสองครั้ง
อืมทำไมคุณถึงคิดเช่นนั้น? ;-) ระบุว่าค่าเริ่มต้นมีอยู่เพื่อให้ค่าเมื่อคอลัมน์ที่แนบมานั้นไม่ปรากฏในINSERT
คำสั่งฉันจะถือว่าตรงกันข้าม: พวกเขาจะถูกละเว้นอย่างสมบูรณ์หากคอลัมน์ที่เกี่ยวข้องอยู่ในINSERT
งบ
โชคดีที่พวกเราทั้งคู่ไม่จำเป็นต้องคาดเดาสิ่งใดเนื่องจากคำแถลงนี้ในคำถาม:
ฉันสนใจการแสดงเป็นส่วนใหญ่
คำถามเกี่ยวกับประสิทธิภาพมักทดสอบได้ ดังนั้นเราเพียงแค่ต้องทำการทดสอบเพื่อให้ SQL Server (ผู้มีอำนาจที่แท้จริงที่นี่) ตอบคำถามนี้
ติดตั้ง
รันต่อไปนี้หนึ่งครั้ง:
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;
ดำเนินการทดสอบ 1A และ 1B เป็นรายบุคคลไม่ได้อยู่ด้วยกันเพราะจะทำให้จังหวะนั้นแย่ เรียกใช้แต่ละคนหลายครั้งเพื่อให้ได้ความรู้สึกของเวลาเฉลี่ยสำหรับแต่ละคน
ทดสอบ 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
ทดสอบ 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
ดำเนินการทดสอบแบบ 2A และ 2B แบบแยกทีละตัว เรียกใช้แต่ละคนหลายครั้งเพื่อให้ได้ความรู้สึกของเวลาเฉลี่ยสำหรับแต่ละคน
ทดสอบ 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);
ทดสอบ 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 และ 1B หรือระหว่างการทดสอบ 2A และ 2B ดังนั้นไม่มีการลงโทษที่จะมีDEFAULT
กำหนด แต่ไม่ได้ใช้
นอกจากนี้ยังเป็นเพียงแค่การบันทึกพฤติกรรมที่ตั้งใจคุณต้องจำไว้ว่าส่วนใหญ่คุณที่ใส่ใจเกี่ยวกับคำสั่ง DML ที่มีอยู่อย่างสมบูรณ์ภายในขั้นตอนการจัดเก็บของคุณ ฝ่ายสนับสนุนไม่สนใจ นักพัฒนาในอนาคตอาจไม่ทราบว่าคุณต้องการให้ DML ทั้งหมดถูกห่อหุ้มไว้ในกระบวนงานที่เก็บไว้หรือไม่สนใจแม้ว่าพวกเขาจะรู้ และใครก็ตามที่รักษาฐานข้อมูลนี้หลังจากที่คุณหายไป (ไม่ว่าจะเป็นโครงการหรืองานอื่น) อาจไม่สนใจหรืออาจไม่สามารถป้องกันการใช้ ORM ได้ไม่ว่าพวกเขาจะประท้วงเท่าใด ดังนั้นค่าเริ่มต้นสามารถช่วยในการที่พวกเขาให้คน "ออก" เมื่อทำINSERT
โดยเฉพาะอย่างยิ่งโฆษณาที่INSERT
ทำโดยตัวแทนสนับสนุนเนื่องจากเป็นหนึ่งคอลัมน์ที่พวกเขาไม่จำเป็นต้องรวม (ซึ่งเป็นเหตุผลที่ฉันมักจะใช้ค่าเริ่มต้นในการตรวจสอบ คอลัมน์วันที่)
และมันเพิ่งเกิดขึ้นกับฉันว่ามันสามารถแสดงค่อนข้างเป็นกลางหรือไม่มีการDEFAULT
ตรวจสอบเมื่อคอลัมน์ที่เกี่ยวข้องอยู่ในINSERT
งบ: เพียงแค่ให้ค่าที่ไม่ถูกต้อง การทดสอบต่อไปนี้ไม่เพียงแค่นั้น:
-- 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
อย่างที่คุณเห็นเมื่อมีการระบุคอลัมน์ (และค่าไม่ใช่คำหลักDEFAULT
) ค่าเริ่มต้นจะถูกละเว้น 100% เรารู้สิ่งนี้เพราะINSERT
ประสบความสำเร็จ แต่หากมีการใช้ค่าเริ่มต้นจะมีข้อผิดพลาดตามที่ได้รับการดำเนินการในที่สุด
มีวิธีใดที่จะหลีกเลี่ยงข้อ จำกัด DEFAULT ภายในการเรียกใช้ทริกเกอร์ได้หรือไม่
ในขณะที่ต้องการหลีกเลี่ยงข้อ จำกัด เริ่มต้น (อย่างน้อยในบริบทนี้) ไม่จำเป็นอย่างสมบูรณ์เพื่อความสมบูรณ์ของมันก็สามารถสังเกตได้ว่ามันจะเป็นไปได้ที่จะ "หลีกเลี่ยง" ข้อ จำกัด เริ่มต้นภายในINSTEAD OF
ทริกเกอร์ แต่ไม่อยู่ภายในAFTER
ทริกเกอร์ ตามเอกสารประกอบของCREATE TRIGGER :
หากมีข้อ จำกัด ในตารางทริกเกอร์พวกเขาจะถูกตรวจสอบหลังจากการดำเนินการทริกเกอร์ INSTEAD OF และก่อนการดำเนินการทริกเกอร์ AFTER หากมีการละเมิดข้อ จำกัด การกระทำของทริกเกอร์ INSTEAD OF จะถูกย้อนกลับและทริกเกอร์ AFTER จะไม่เริ่มทำงาน
แน่นอนว่าการใช้INSTEAD OF
Trigger จำเป็นต้องมี:
- ปิดการใช้งานข้อ จำกัด เริ่มต้น
- การสร้าง
AFTER
ทริกเกอร์ที่เปิดใช้งานข้อ จำกัด
อย่างไรก็ตามฉันไม่แนะนำให้ทำเช่นนี้