Я попал в дебаты на работе, и мне нужен совет по поводу возможных ловушек, которые я мог бы пропустить.
Представьте себе сценарий, в котором триггер используется для копирования удаленных записей в таблицу аудита. Триггер использует SELECT *. Все указывают и кричат и говорят нам, как это плохо.
Однако, если в структуру основной таблицы внесены изменения, а таблица аудита пропущена, то триггер выдаст ошибку, сообщающую людям, что таблица аудита также нуждается в модификации.
Ошибка будет обнаружена во время тестирования на наших серверах DEV. Но нам нужно обеспечить соответствие производственного процесса DEV, поэтому мы разрешаем SELECT * в производственных системах (только триггеры).
Итак, мой вопрос: меня подталкивают к удалению SELECT *, но я не уверен, как еще обеспечить автоматическую фиксацию ошибок разработки такого рода, каких-либо идей или это лучшая практика?
Я собрал пример ниже:
--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'
ОБНОВЛЕНИЕ (перефразировать вопрос):
Я администратор базы данных и должен убедиться, что разработчики не предоставляют плохо продуманные сценарии развертывания, внося вклад в нашу документацию по передовому опыту. SELECT * вызывает ошибку в DEV, когда разработчик пропускает таблицу аудита (это защитная сеть), поэтому ошибка обнаруживается на ранней стадии процесса разработки. Но где-то в Конституции SQL - вторая поправка гласит: «Не используйте SELECT *». Так что теперь есть толчок, чтобы избавиться от сети безопасности.
Как бы вы заменили сеть безопасности, или я должен считать это лучшей практикой для триггеров?
ОБНОВЛЕНИЕ 2: (решение)
Спасибо за ваш вклад, я не уверен, что у меня есть четкий ответ, потому что это, кажется, очень серый вопрос. Но вместе вы предоставили темы для обсуждения, которые могут помочь нашим разработчикам продвинуться вперед в определении своей лучшей практики.
Спасибо Daevin
за ваш вклад, ваш ответ обеспечивает основу для некоторых механизмов тестирования, которые могут реализовать наши разработчики. +1
Спасибо CM_Dayton
, ваши предложения, способствующие передовому опыту, могут быть полезны всем, кто разрабатывает триггеры аудита. +1
Большое спасибо ypercube
, вы много размышляли о проблемах, связанных с изменениями в определениях таблиц. +1
В заключении:
Is Select * ok in a tigger?
Да, это серая зона, не слепо следуйте идеологии «Выбрать * - это плохо».
Am I asking for Trouble?
Да, мы делаем больше, чем просто добавляем новые столбцы в таблицы.
источник
SELECT *
чтобы быть ленивым, но, поскольку у вас есть законная причина использовать его, он скорее серый, чем черно-белый. Вы должны попытаться сделать что-то вроде этого , но настроить его таким образом, чтобы не только иметь одинаковое количество столбцов, но и чтобы имена столбцов и типы данных были одинаковыми (поскольку кто-то может изменить типы данных и при этом вызвать проблемы в БД, которые обычно не перехватываются с вашейSELECT *
«сеткой безопасности».SELECT *
в качестве защитной сетки, но она не охватит все случаи. Например, если вы уроните столбец и добавите его снова. Это изменит порядок столбцов и (если все столбцы не относятся к одному и тому же типу) вставки в таблицу аудита завершатся неудачно или приведут к потере данных из-за неявных преобразований типов.Ответы:
Как правило, это считается «ленивым» программированием.
Учитывая то, что вы специально вставляете два значения в вашу
TestAudit
таблицу, я буду осторожен, чтобы ваш выбор также получал ровно два значения. Потому что, если по какой-то причине этаTest
таблица имеет или когда-либо получает третий столбец, этот триггер завершится ошибкой.Не имеет прямого отношения к вашему вопросу, но если вы настраиваете таблицу аудита, я бы также добавил несколько дополнительных столбцов в вашу
TestAudit
таблицу, чтобы ...Так что это приводит к запросу вроде:
Таким образом, вы получаете точные столбцы, которые вам нужны, и вы проверяете, для чего / когда / почему / о ком происходит событие аудита.
источник
Я прокомментировал это по вашему вопросу, но решил, что постараюсь представить решение кода.
Я обычно согласен с
SELECT *
чтобы быть ленивым, но, поскольку у вас есть законная причина использовать его, он скорее серый, чем черно-белый.То, что вы должны (на мой взгляд) попытаться сделать, - это что-то вроде этого , но отрегулируйте его так, чтобы имена столбцов и типы данных были одинаковыми (поскольку кто-то может изменить типы данных и при этом вызвать проблемы в БД, которые обычно не обнаруживаются вашим
SELECT *
безопасностью). сеть'.Вы даже можете создать функцию, которая позволит вам быстро проверить, соответствует ли версия Audit таблицы не-Audit версии:
SELECT ... EXCEPT SELECT ...Audit
Покажет вам , какие столбцы в таблице , а не в таблице аудита. Вы даже можете изменить функцию, чтобы она возвращала имена столбцов, которые не совпадали, а не просто отображали ли они или нет, или даже вызывали исключение.Затем вы можете запустить это, прежде чем переходить
DEV
кPRODUCTION
серверам для каждой таблицы в БД, используя курсор над:источник
Оператор, который вызовет триггер, потерпит неудачу, и триггер потерпит неудачу. Лучше было бы документировать триггер и контрольный журнал, чтобы вы знали, как изменить запрос, добавив столбцы вместо указания *.
По крайней мере, вы должны изменить триггер, чтобы он мог корректно завершиться с ошибкой при регистрации ошибок в таблице и, возможно, поместить предупреждение в таблицу, в которую триггер регистрирует ошибки.
Это также напоминает, что вы можете поставить триггер или предупреждение, когда кто-то изменяет таблицу и добавляет дополнительные столбцы или удаляет столбцы, чтобы уведомить вас о добавлении триггера.
Я считаю, что производительность * ничего не меняет, она только увеличивает вероятность сбоев в будущем, когда что-то меняется, а также может привести к задержке в сети, когда вы перемещаете больше информации по сети, когда вам это нужно. Есть время и место для *, но я чувствую, что, как описано выше, у вас есть лучшие решения и инструменты, которые можно попробовать вместо них.
источник
Если ваша исходная структура или структура таблицы аудита вообще изменится, вы гарантированно столкнетесь с проблемой выбора *.
Если что-то изменится, триггер выдаст ошибку.
Вы могли бы сделать:
Но, как говорит CM_Dayton, это ленивое программирование и открывает двери для других несоответствий. Чтобы этот сценарий работал, вы должны быть абсолютно уверены, что вы обновляете структуру обеих таблиц одновременно.
источник