Eu costumo projetar meus bancos de dados seguindo as próximas regras:
- Ninguém além de db_owner e sysadmin tem acesso às tabelas do banco de dados.
- As funções do usuário são controladas na camada do aplicativo. Eu costumo usar uma função de banco de dados para conceder acesso às visualizações, procedimentos armazenados e funções, mas em alguns casos, adiciono uma segunda regra para proteger alguns procedimentos armazenados.
- Eu uso TRIGGERS para validar inicialmente informações críticas.
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 é executado usando procedimentos armazenados:
sp_MyTable_Insert(@Field1, @Field2, @Field3, ...);
sp_MyTable_Delete(@Key1, @Key2, ...);
sp_MyTable_Update(@Key1, @Key2, @Field3, ...);
Você acha que, nesse cenário, vale a pena usar DEFAULT CONSTRAINTs, ou estou adicionando um trabalho extra e desnecessário ao servidor DB?
Atualizar
Eu entendo que usando a restrição DEFAULT estou dando mais informações para outra pessoa que deve administrar o banco de dados. Mas estou mais interessado no desempenho.
Presumo que o banco de dados esteja sempre verificando os valores padrão, mesmo que eu forneça o valor correto, portanto, estou fazendo o mesmo trabalho duas vezes.
Por exemplo, existe uma maneira de evitar a restrição DEFAULT em uma execução de gatilho?
Hum, por que você assumiria isso? ;-). Dado que Defaults existem para fornecer um valor quando a coluna à qual eles estão anexados não está presente na
INSERT
declaração, eu diria exatamente o oposto: que eles são completamente ignorados se a coluna associada estiver presente naINSERT
declaração.Felizmente, nenhum de nós precisa assumir nada devido a esta afirmação na pergunta:
Perguntas sobre desempenho são quase sempre testáveis. Então, só precisamos criar um teste para permitir que o SQL Server (a verdadeira autoridade aqui) responda a essa pergunta.
CONFIGURAR
Execute o seguinte uma vez:
Execute os testes 1A e 1B individualmente, não juntos, pois isso distorce o tempo. Execute cada um várias vezes para ter uma noção do tempo médio de cada um.
Teste 1A
Teste 1B
Execute os testes 2A e 2B individualmente, não juntos, pois isso distorce o tempo. Execute cada um várias vezes para ter uma noção do tempo médio de cada um.
Teste 2A
Teste 2B
Você deve ver que não há diferença real no tempo entre os testes 1A e 1B, ou entre os testes 2A e 2B. Portanto, não, não há penalidade de desempenho para ter um
DEFAULT
definido, mas não usado.Além disso, além de documentar o comportamento pretendido, você precisa ter em mente que é principalmente você quem se preocupa com as instruções DML sendo completamente contidas em seus procedimentos armazenados. As pessoas de apoio não se importam. Os desenvolvedores futuros podem não estar cientes de seu desejo de ter todo o DML encapsulado nesses procedimentos armazenados ou se importar, mesmo que saibam. E quem mantiver esse banco de dados depois que você se for (outro projeto ou trabalho) pode não se importar ou não ser capaz de impedir o uso de um ORM, não importa o quanto eles protestem. Então, Defaults, pode ajudar na medida em que eles dão às pessoas um "out" ao fazer um
INSERT
, especialmente um ad-hocINSERT
feito por um representante de suporte, já que essa é uma coluna que eles não precisam incluir (e é por isso que eu sempre uso defaults em auditoria colunas de data).E, acabou de me ocorrer que pode ser mostrado de maneira bastante objetiva se a
DEFAULT
é verificado ou não quando a coluna associada está presente naINSERT
instrução: basta fornecer um valor inválido. O teste a seguir faz exatamente isso:Como você pode ver, quando uma coluna (e um valor, não a palavra-chave
DEFAULT
) é fornecida, o Padrão é 100% ignorado. Sabemos disso porque oINSERT
sucesso. Mas se o Default for usado, haverá um erro, pois ele finalmente está sendo executado.Embora a necessidade de evitar Default Constraints (pelo menos neste contexto) seja completamente desnecessária, por uma questão de completude pode-se notar que só seria possível "evitar" uma Default Constraint dentro de um
INSTEAD OF
Trigger, mas não dentro de umAFTER
Trigger. De acordo com a documentação para CREATE TRIGGER :Claro, usar um
INSTEAD OF
Trigger exigiria:AFTER
gatilho que habilita a restriçãoNo entanto, eu não recomendaria exatamente fazer isso.
Não vejo nenhum dano significativo em ter restrições padrão. Na verdade, vejo uma vantagem em particular - você definiu o padrão no mesmo nível de lógica que a própria definição da tabela. Se você tiver um valor padrão fornecido em seu procedimento armazenado, alguém precisará ir até lá para descobrir qual é o valor padrão; e, isso não é algo óbvio para alguém novo no sistema, necessariamente (se, por exemplo, você herdar um bilhão de dólares amanhã, comprar sua própria ilha tropical, sair e se mudar para lá, deixando algum outro pobre coitado para descobrir as coisas por conta própria).