Estou preso em um debate no trabalho e preciso de alguns conselhos sobre possíveis armadilhas que eu poderia estar ignorando.
Imagine um cenário em que um acionador é usado para copiar registros excluídos em uma tabela de auditoria. O gatilho usa SELECT *. Todo mundo aponta e grita e nos diz o quanto isso é ruim.
No entanto, se uma modificação for feita na Estrutura da tabela principal, e a tabela de auditoria for ignorada, o gatilho gerará um erro informando às pessoas que a tabela de auditoria também precisa de modificação.
O erro será detectado durante o teste em nossos servidores DEV. Mas precisamos garantir a DEV de correspondências de produção, para que permitamos SELECT * em sistemas de produção (somente gatilhos).
Portanto, minha pergunta é: estou sendo pressionado a remover o SELECT *, mas não tenho certeza de que outra forma garantir que estamos capturando automaticamente erros de desenvolvimento dessa natureza, de alguma idéia ou é uma prática recomendada?
Reunimos um exemplo abaixo:
--Create Test Table
CREATE TABLE dbo.Test(ID INT IDENTITY(1,1), Person VARCHAR(255))
--Create Test Audit Table
CREATE TABLE dbo.TestAudit(AuditID INT IDENTITY(1,1),ID INT, Person VARCHAR(255))
--Create Trigger on Test
CREATE TRIGGER [dbo].[trTestDelete] ON [dbo].[Test] AFTER DELETE
NOT FOR REPLICATION
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.TestAudit([ID], [Person])
SELECT *
FROM deleted
END
--Insert Test Data into Test
INSERT INTO dbo.Test VALUES
('Scooby')
,('Fred')
,('Shaggy')
--Perform a delete
DELETE dbo.Test WHERE Person = 'Scooby'
UPDATE (reformular a pergunta):
Sou DBA e preciso garantir que os desenvolvedores não forneçam scripts de implantação mal pensados, contribuindo para a documentação de práticas recomendadas. SELECT * causa um erro na DEV quando o desenvolvedor ignora a tabela de auditoria (esta é uma rede de segurança), portanto o erro é detectado no início do processo de desenvolvimento. Mas em algum lugar na Constituição do SQL - a segunda alteração diz "Não usaremos SELECT *". Então agora há um esforço para se livrar da rede de segurança.
Como você substitui a rede de segurança ou devo considerar essa prática recomendada para os acionadores?
ATUALIZAÇÃO 2: (solução)
Obrigado por todas as suas contribuições, não tenho certeza se tenho uma resposta clara, porque este parece ser um assunto muito cinzento. Mas, coletivamente, você forneceu pontos de discussão que podem ajudar nossos desenvolvedores a avançar na definição de suas Melhores Práticas.
Obrigado Daevin
por sua contribuição, sua resposta fornece as bases para alguns mecanismos de teste que nossos desenvolvedores podem implementar. +1
Obrigado CM_Dayton
, suas sugestões que contribuem para as práticas recomendadas podem ser benéficas para qualquer um que esteja desenvolvendo os Acionadores de Auditoria. +1
Muito obrigado ypercube
, você refletiu bastante sobre os problemas relacionados a tabelas que sofrem diferentes formas de alteração de definição. +1
Em conclusão:
Is Select * ok in a tigger?
Sim, é uma área cinzenta, não siga cegamente a ideologia "Selecionar * é ruim".
Am I asking for Trouble?
Sim, fazemos mais do que apenas adicionar novas colunas às tabelas.
fonte
SELECT *
ser preguiçoso, mas como você tem um motivo legítimo para usá-lo, é mais cinza que preto e branco. O que você deve tentar fazer é algo como isso , mas ajustá-lo para não só têm a mesma contagem de coluna, mas que os nomes de colunas e tipos de dados são os mesmos (desde que alguém poderia alterar os tipos de dados e ainda causa problemas no db normalmente não pegou com suaSELECT *
'rede de segurança'.SELECT *
como rede de segurança, mas ela não pega todos os casos. Por exemplo, se você soltar uma coluna e adicioná-la novamente. Isso mudará a ordem das colunas e (a menos que todas as colunas sejam do mesmo tipo) as inserções na tabela de auditoria falharão ou resultarão em perda de dados devido às conversões implícitas de tipo.Respostas:
Normalmente, é considerado programação "lenta".
Como você está inserindo especificamente dois valores em sua
TestAudit
tabela aqui, tenha cuidado para garantir que seu select também esteja recebendo exatamente dois valores. Porque se, por algum motivo, essaTest
tabela tiver ou já obtiver uma terceira coluna, esse gatilho falhará.Não está diretamente relacionado à sua pergunta, mas se você estiver configurando uma tabela de auditoria, também adicionarei algumas colunas adicionais à sua
TestAudit
tabela para ...Portanto, isso resulta em uma consulta como:
Dessa forma, você obtém as colunas exatas necessárias e audita o que / quando / por que / quem é o evento de auditoria.
fonte
Comentei isso em sua pergunta, mas achei que tentaria realmente apresentar uma solução de código.
Eu geralmente concordo em
SELECT *
ser preguiçoso, mas como você tem um motivo legítimo para usá-lo, é mais cinza do que em preto e branco.O que você deve (na minha opinião) tentar fazer é algo como isso , mas ajustá-lo para garantir que os nomes de colunas e tipos de dados são os mesmos (desde que alguém poderia alterar os tipos de dados e ainda causa problemas no db normalmente não pego com a sua
SELECT *
'segurança internet'.Você pode até criar uma função que permita verificar rapidamente se a versão de auditoria da tabela corresponde à versão de não auditoria:
O
SELECT ... EXCEPT SELECT ...Audit
mostrará quais colunas da tabela não estão na tabela Auditoria. Você pode até alterar a função para retornar o nome de colunas que não são iguais, em vez de apenas mapearem ou não, ou até criar uma exceção.Em seguida, você pode executar isso antes de passar
DEV
para osPRODUCTION
servidores de cada tabela no banco de dados, usando um cursor sobre:fonte
A instrução que indicará o gatilho falhará e o gatilho falhará. Seria uma prática melhor documentar o gatilho e a trilha de auditoria para que você modifique a consulta para adicionar as colunas em vez de especificar o *.
No mínimo, você deve modificar o gatilho para que ele falhe normalmente ao registrar erros em uma tabela e, talvez, coloque um alerta na tabela em que o gatilho está registrando os erros.
Isso também lembra: você pode colocar um gatilho ou alerta quando alguém altera a tabela e adiciona mais colunas ou remove colunas, para notificá-lo a acrescentar o gatilho.
Em termos de desempenho, acredito que * não muda nada, apenas aumenta as chances de falhas no caminho quando as coisas mudam e também pode causar latência da rede quando você extrai mais informações da rede quando necessário. Há um tempo e um lugar para *, mas, como descrito acima, você tem melhores soluções e ferramentas para tentar.
fonte
Se a estrutura original ou a tabela de auditoria mudar, você garante que terá um problema com o seu select *.
Se qualquer um deles mudar, o gatilho terá um erro.
Você poderia fazer:
Mas, como diz CM_Dayton, isso é uma programação lenta e abre as portas para outras inconsistências. Para que esse cenário funcione, você precisa ter certeza absoluta de que está atualizando a estrutura de ambas as tabelas ao mesmo tempo.
fonte