#sql-server #tsql #stored-procedures #sql-execution-plan #sqlperformance
#sql-сервер #tsql #хранимые процедуры #sql-execution-plan #производительность sql
Вопрос:
Я хочу передать список имен в хранимую процедуру, а затем выполнить объединение по левому краю. Я передал список имен в качестве табличного параметра.
CREATE PROCEDURE [DBO].[INSERTANDGETLATESTNAMES]
(@list [dbo].[NamesCollection] READONLY)
AS
BEGIN
INSERT INTO [dbo].[Employee](NAME)
OUTPUT INSERTED.NAME
SELECT NamesCollection.Name
FROM @list AS NamesCollection
LEFT JOIN [dbo].[Employee] AS emp ON NamesCollection.Name = emp.Name
WHERE emp.Name IS NULL
END
Определяемый пользователем тип таблицы:
CREATE TYPE [dbo].[NamesCollection] AS TABLE
(
[NAME] [varchar](50) NULL
)
GO
SQL Server не ведет статистику по табличным параметрам, повлияет ли это на производительность объединения в приведенном выше случае. Если производительность низкая, могу ли я передать список имен в виде строки, разделенной запятыми, и написать функцию для разделения и возврата таблицы в хранимую процедуру?
CREATE FUNCTION split_string_XML
(@in_string VARCHAR(MAX),
@delimiter VARCHAR(1))
RETURNS @list TABLE(NAMES VARCHAR(50))
AS
BEGIN
DECLARE @sql_xml XML = Cast('<root><U>' Replace(@in_string, @delimiter, '</U><U>') '</U></root>' AS XML)
INSERT INTO @list(NAMES)
SELECT f.x.value('.', 'VARCHAR(50)') AS NAMES
FROM @sql_xml.nodes('/root/U') f(x)
WHERE f.x.value('.', 'VARCHAR(50)') <> ''
RETURN
END
GO
или
CREATE FUNCTION split_string_delimiter
(@in_string VARCHAR(MAX),
@delimiter VARCHAR(1))
RETURNS @list TABLE(NAME VARCHAR(50))
AS
BEGIN
INSERT INTO @list(NAME)
SELECT value AS NAMES
FROM STRING_SPLIT(@in_string, @delimiter);
RETURN
END
GO
Комментарии:
1. Попробуйте и убедитесь — не спрашивайте нас. Лично я бы сделал это правильным способом (используя параметр с табличным значением) и оптимизировал бы производительность только в том случае, если это становится проблемой. Вы можете преждевременно потратить много времени, пытаясь предсказать производительность SQL Server.
2. @DaleK согласен, правильный способ сделать это — использовать параметр, оцениваемый в таблице. Поскольку SQL Server не ведет статистику по табличным параметрам, повлияет ли это на производительность объединения?
3. Как я уже сказал, попробуйте и посмотрите… сколько строк вы передаете?
4. @DaleK <1000 строк за раз.
5. Объявите ограничение первичного ключа для типа таблицы. Даже если у него нет статистики для базового индекса, он предоставляет оптимизатору информацию о мощности, которая может быть полезной.
Ответ №1:
Использовать STRING_SPLIT
лучше, чем использовать XML PATH
для разделения. Если вы можете использовать STRING_SPLIT
, вы можете использовать JSON PATH
.
Используя JSON PATH
, преобразуйте JSON variable
в набор строк и вставьте его #temporary table
, а не @table variable
как в зависимости от версии вашего SQL Server, #temporary tables
выполняется лучше при обработке большого объема данных.
Кроме того, если вы хотите добавить новые поля в JSON variable
, не будет необходимости редактировать table type
. При редактировании table type
затруднено из-за ссылок.
Ответ №2:
ВЫБОР, в котором вы используете табличный параметр, довольно прост. Это просто объединение, и учитывая, что мощность для табличных переменных вычисляется как единица, предполагается, что dbo.Employee.Имя проиндексировано, и типы столбцов совпадают, это объединение будет реализовано с помощью объединения в цикл, которое является самым быстрым вариантом для этого случая.
Просто убедитесь, что dbo.Employee.Имя правильно проиндексировано.