Как реализовать триггеры на вставку для подсчета звонков
Что проверяют
Знаете ли вы, как триггер ведёт себя на реальной нагрузке, а не на вставке одной строки. Главная ловушка: в SQL Server триггер срабатывает один раз на инструкцию, а не на каждую строку. Следом обычно спрашивают, не лучше ли считать звонки вообще без триггера.
Как отвечать
Опишите решение для SQL Server, раз стек C#:
- псевдотаблица
inserted: вAFTER INSERTв ней лежат все вставленные строки. Счётчик увеличивается наSELECT COUNT(*) FROM inserted, а не на единицу, иначе пакетная вставка 500 звонков добавит один; - разрез по абоненту: обычно считают не общее число, а по
CallerIDили по дню. Тогда триггер делаетUPDATE ... FROMс группировкой поinsertedиINSERTдля новых ключей, либо одинMERGE; SET NOCOUNT ONв начале тела, чтобы лишние сообщения о затронутых строках не путали клиента;- блокировки: одна строка-счётчик становится горячей точкой, все параллельные вставки встают в очередь за её блокировкой. Выручает счётчик по ключу или разбитый на несколько строк.
Со стороны C# назовите две вещи. EF Core с седьмой версии на SQL Server сохраняет изменения через OUTPUT, а он несовместим с триггерами на таблице, поэтому таблицу нужно пометить: ToTable(t => t.HasTrigger("trg_CallsInsert")). А SqlBulkCopy по умолчанию триггеры не запускает, нужен флаг SqlBulkCopyOptions.FireTriggers.
Закончите альтернативами: индексированное представление с COUNT_BIG(*), которое СУБД поддерживает сама, подсчёт при чтении по индексу или агрегация в фоне через очередь.
Где спотыкаются
Пишут SET TotalCalls = TotalCalls + 1 и считают, что триггер вызывается на каждую строку. Так работает PostgreSQL с FOR EACH ROW, но не SQL Server.
Кладут в триггер тяжёлую логику: обновление нескольких таблиц, запись журнала, сложные проверки. Всё это выполняется внутри транзакции вставки и замедляет каждую запись.
Не упоминают, что триггер невидим из кода приложения. Разработчик читает репозиторий на C#, не находит, откуда меняется счётчик, и тратит день на поиск. Поэтому триггер стоит хотя бы описать в миграции и в документации сервиса.