Eu tenho usado o seguinte padrão para validar parâmetros FOREIGN KEY (FK) para procedimentos armazenados que executam INSERTs:
CREATE PROC spCreateChildFoo
@ForeignKey_Id int,
@Attribute varchar(50)
AS
IF NOT EXISTS (SELECT ForeignKey_Id FROM ForeignTable WHERE ForeignKey_Id = @ForeignKey_Id)
BEGIN
RAISERROR ('The input ForeignKey_Id does not exist', 16, 1)
RETURN;
END
INSERT INTO ChildTable (ForeignKey_Id, Attribute)
VALUES (@ForeignKey_Id, @Attribute)
Fiz isso porque queria capturar entradas FK inválidas no início da execução do procedimento armazenado antes que qualquer dado fosse inserido, especialmente para procs que executam vários INSERTs. Também pensei que seria uma boa maneira de retornar mensagens de erro precisas para facilitar a depuração. Esse padrão funciona bem para atender a esses dois objetivos.
Perguntas
Isso é uma perda de tempo?
Mais especificamente, devo confiar apenas nas restrições FK para validar os parâmetros FK e reverter se falhar?
Em última análise, isso prejudicará o desempenho do meu aplicativo à medida que o banco de dados cresce?
Sim, isso é uma perda de tempo, pelo menos quando seu procedimento armazenado é apenas a instrução INSERT que pode causar a violação da chave estrangeira. Onde uma chave estrangeira está em vigor, a validação de qualquer tentativa de valor FK é feita na tabela de referência pelo próprio mecanismo de banco de dados.
Se o valor não existir na tabela de referência, você receberá uma exceção e terá sua instrução INSERT abortada.
Então, isso seria perfeitamente suficiente:
Por outro lado, se seu procedimento for mais do que uma única instrução INSERT e você quiser interromper todo o procedimento em uma inserção inválida em seu início, a verificação preliminar do valor FK pode não ser totalmente inútil. No entanto, valores FK válidos ainda estariam causando pesquisas duplas, e isso não é bom nem necessário. Para obter o mesmo efeito de abortar todo o procedimento, basta colocar o corpo do procedimento em um bloco TRY/CATCH:
Mais informações: