I usually design my databases following next rules:
- Nobody else than db_owner and sysadmin have access to the database tables.
- User roles are controlled at application layer. I usually use one db role to grant access to the views, stored procedures and functions, but in some cases, I add a second rule to protect some stored procedures.
- I use TRIGGERS to initially validate critical information.
CREATE TRIGGER <TriggerName>
ON <MyTable>
[BEFORE | AFTER] INSERT
AS
IF EXISTS (SELECT 1
FROM inserted
WHERE Field1 <> <some_initial_value>
OR Field2 <> <other_initial_value>)
BEGIN
UPDATE MyTable
SET Field1 = <some_initial_value>,
Field2 = <other_initial_value>
...
END
- DML is executed using stored procedures:
sp_MyTable_Insert(@Field1, @Field2, @Field3, ...);
sp_MyTable_Delete(@Key1, @Key2, ...);
sp_MyTable_Update(@Key1, @Key2, @Field3, ...);
Do you think that, on this scenario, worth it to use DEFAULT CONSTRAINTs, or I'm adding an extra and unnecessary job to the DB server?
Update
I understand that by using DEFAULT constraint I'm giving more information to someone else that must to administer the database. But I'm mostly interested on performance.
I assume that the database is checking always default values, even if I supply the correct value, hence I'm doing the same job twice.
For example, Is there a way to avoid DEFAULT constraint within a trigger execution?
Best Answer
Um, why would you assume that? ;-). Given that Defaults exist to provide a value when the column that they are attached to is not present in the
INSERT
statement, I would assume the exact opposite: that they are completely ignored if the associated column is present in theINSERT
statement.Fortunately, neither of us needs to assume anything due to this statement in the question:
Questions about performance are nearly always testable. So we just need to come up with a test to allow SQL Server (the true authority here) to answer this question.
SETUP
Run the following once:
Execute tests 1A and 1B individually, not together as that skews the timing. Run each one several times to get a sense of the average timing for each one.
Test 1A
Test 1B
Execute tests 2A and 2B individually, not together as that skews the timing. Run each one several times to get a sense of the average timing for each one.
Test 2A
Test 2B
You should see that there is no real difference in timing between tests 1A and 1B, or between tests 2A and 2B. So, no, there is no performance penalty to have a
DEFAULT
defined but not used.Also, besides merely documenting intended behavior, you need to keep in mind that it is mostly you who cares about the DML statements being completely contained within your stored procedures. Support folks do not care. Future developers might not be aware of your desire to have all DML encapsulated within those stored procedures, or care even if they do know. And whoever maintains this DB after you are gone (either another project or job) might not care, or might not be able to prevent the use of an ORM no matter how much they protest. So, Defaults, can help in that they give folks an "out" when doing an
INSERT
, especially an ad-hocINSERT
done by a support rep, as that is one column they no need to include (which is why I always use defaults on audit date columns).AND, it just occurred to me that it can be shown rather objectively whether or not a
DEFAULT
is checked when the associated column is present in theINSERT
statement: simply provide an invalid value. The following test does just that:As you can see, when a column (and a value, not the keyword
DEFAULT
) is provided, the Default is 100% ignored. We know this because theINSERT
succeeds. But if the Default is used, there is an error as it is finally being executed.While needing to avoid Default Constraints (at least in this context) is completely unnecessary, for the sake of completeness it can be noted that it would only be possible to "avoid" a Default Constraint within an
INSTEAD OF
Trigger, but not within anAFTER
Trigger. According to the documentation for CREATE TRIGGER:Of course, using an
INSTEAD OF
Trigger would require:AFTER
Trigger that enables the ConstraintHowever, I wouldn't exactly recommend doing this.