Практика SQL Server

Табличные параметры SQL Server как пакетный интерфейс

Передавайте типизированные строки с ясными правилами проверки, дубликатов и порядка и учитывайте отсутствие статистик и настройки клиента.

Отдельный вызов базы для каждой позиции заказа тратит сетевые обращения и усложняет обработку отказа. Строка через запятую переносит проблему в разбор и экранирование. Табличный параметр, или TVP, передаёт типизированный набор процедуре за один вызов.

Сначала определите контракт: уникальные продукты, позиции с разрешёнными повторами либо независимые операции. От этого зависят ключ, проверки, сопоставление результата и смысл повторного запроса.

Тип описывает входные данные

Учебный интерфейс принимает положительное количество на продукт и явно показывает неизвестные идентификаторы.

-- Disposable practice database. Send GO-separated batches separately.
CREATE TYPE dbo.RequestLinesDemo AS TABLE (
    ProductId int NOT NULL PRIMARY KEY,
    Quantity int NOT NULL CHECK (Quantity > 0)
);
GO
CREATE TABLE dbo.ProductsTvpDemo(ProductId int PRIMARY KEY, UnitPrice decimal(12,2));
INSERT dbo.ProductsTvpDemo VALUES (1,10.00),(2,15.00);
GO
CREATE PROCEDURE dbo.ValidateLinesDemo @Lines dbo.RequestLinesDemo READONLY
AS
BEGIN
    SET NOCOUNT ON;
    SELECT l.ProductId, l.Quantity, p.UnitPrice,
           CONVERT(bit, CASE WHEN p.ProductId IS NULL THEN 0 ELSE 1 END) AS IsValid
    FROM @Lines AS l
    LEFT JOIN dbo.ProductsTvpDemo AS p ON p.ProductId = l.ProductId
    ORDER BY l.ProductId;
END;
GO

Первичный ключ запрещает повтор ProductId. Если одинаковые товары являются самостоятельными позициями, используйте LineId как ключ. Нельзя объединять настоящие строки заказа только ради удобной обработки множеств.

CHECK требует положительное количество, а NOT NULL запрещает неизвестное значение. Ограничения типа проверяют форму и простые инварианты, но не заменяют проверку текущего каталога, состояния продукта или доступности.

READONLY обязателен для TVP. Процедура читает и соединяет входные строки, но не изменяет параметр как временную таблицу. Для преобразований нужна отдельная рабочая структура с собственной стоимостью.

Пример вызова содержит несуществующий продукт.

DECLARE @Input dbo.RequestLinesDemo;
INSERT @Input VALUES (1,2),(2,3),(99,1);
EXEC dbo.ValidateLinesDemo @Lines = @Input;

Продукты 1 и 2 допустимы, 99 отмечен ошибкой. LEFT JOIN сохраняет неверный вход для отчёта. INNER JOIN скрыл бы его и мог превратить частичный результат в видимость полной успешной проверки.

Согласуем проверку с операцией

Процедура демонстрирует проверку, а не завершённую транзакцию размещения заказа. Решите, отклоняет ли одна ошибка всю заявку или допустимо частичное принятие. Каждому результату нужно соответствие входной позиции и понятный итоговый статус.

Успешная предварительная проверка не замораживает продукт до следующего вызова. Цена, доступность и права могут измениться. Повторно проверяйте необходимые условия внутри настоящей транзакции либо используйте подходящий контракт версии. Предварительный отчёт не является гарантией конкурентной безопасности.

У TVP нет гарантированного порядка. Передавайте отдельную последовательность при необходимости и явно сортируйте выдачу. Новые идентификаторы возвращайте вместе с исходной LineId, а не сопоставляйте по случайному порядку строк.

В .NET задавайте структурированный параметр с правильным schema-qualified именем типа. Вход может предоставлять DataTable или поток строк. Согласуйте типы, precision, scale, длину и допустимость NULL. Совпадение имени параметра не компенсирует неверную структуру.

Измеряем реальные размеры пакетов

SQL Server не поддерживает столбцовые статистики TVP. Пять строк и пятьдесят тысяч могут требовать разных планов. Первичный ключ предоставляет уникальность и структуру доступа, но не гистограмму распределения.

Для больших переменных входов копирование во временную таблицу с индексами и статистиками иногда улучшает соединения. Оно добавляет копирование и нагрузку tempdb, поэтому измеряйте весь вызов. Рекомпиляция способна помочь некоторым случаям оценки количества, но не создаёт отсутствующее распределение.

Ограничьте размер запроса и рассмотрите контролируемые пакеты для огромной загрузки. TVP не обязательно быстрее bulk load при любом объёме. Включайте сериализацию, сеть, компиляцию и выполнение в общее сравнение.

Вызывающей стороне нужны права на процедуру и тип, включая REFERENCES там, где это требуется. Разделяйте развёртывание и обычное использование. Изменение пользовательского табличного типа обычно требует согласованной версии зависимых объектов и совместимости старых клиентов.

Проверьте пустой вход, дубликаты, неверное количество, неизвестные продукты, максимальный размер и повтор после неопределённого ответа. Дополнительно проверьте, что клиент действительно передаёт пустую таблицу, а не пытается заменить её скалярным NULL. Хороший интерфейс сокращает обращения, сохраняя точный смысл каждой строки и всей заявки.

Техническая документация: Microsoft Learn: Table-valued parameters · Microsoft Learn: CREATE TYPE.

Вопрос по статье

Есть вопрос по этой теме?

Расскажите, что вы оцениваете или с какой проблемой столкнулись. Мы ответим с практической рекомендацией.

Inquiries are not enabled in this preview.

Задать вопрос по этой статье