Ответ 1
Эта тема обсуждалась раньше. Основная причина низкой производительности JOIN состоит в том, что параметр с табличным значением (TVP) является табличной переменной. Переменные таблицы не хранят статистику и, по-видимому, оптимизатору запросов содержат только 1 строку. Следовательно, они просто в состоянии сделать что-то вроде INSERT INTO Table (column_list) SELECT column_list FROM @TVP;
но не ПРИСОЕДИНЯЙТЕСЬ.
Есть несколько вещей, чтобы попытаться обойти это:
-
Дамп все в локальную временную таблицу (вы уже делаете это). Техническим недостатком здесь является то, что вы дублируете данные, передаваемые в TVP в базе данных
tempdb
(где и TVP, и временная таблица хранят свои данные). -
Может быть, попробуйте определить пользовательский тип таблицы, чтобы иметь кластерный первичный ключ. Вы можете сделать это встроенным в поле
[Id]
:[ID] INT NOT NULL PRIMARY KEY
Не уверен, насколько это помогает производительности, но стоит попробовать.
-
Вы можете попробовать добавить
OPTION (RECOMPILE)
к запросу. Это способ получить Оптимизатор запросов, чтобы увидеть, сколько строк в табличной переменной, чтобы иметь правильные оценки.SELECT column_list FROM SOMETABLE INNER JOIN @Ids [OurTableType] ON [OurTableType].Id = SOMETABLE.Id OPTION (RECOMPILE);
Недостатком является то, что у вас есть
RECOMPILE
который занимает дополнительное время каждый раз, когда вызывается этот процесс. Но это может быть общая чистая прибыль. -
Начиная с SQL Server 2014, вы можете воспользоваться OLTP в памяти и указать
WITH (MEMORY_OPTIMIZED = ON)
для пользовательского типа таблицы. Пожалуйста, смотрите Сценарий: переменная таблицы может быть MEMORY_OPTIMIZED = ON для подробностей. Я слышал, что это определенно помогает. К сожалению, в SQL Server 2014 и SQL Server 2016 RTM эта функция доступна только в 64-разрядной версии Enterprise Edition. Но, начиная с SQL Server 2016 с пакетом обновления 1 (SP1), эта функция была доступна для всех выпусков (возможное исключение - SQL Server Express LocalDB). -
SQL Server 2019 представляет " отложенную компиляцию табличных переменных ":
При отложенной компиляции табличных переменных компиляция оператора, который ссылается на табличную переменную, откладывается до первого фактического выполнения оператора. Это отложенное поведение при компиляции идентично поведению временных таблиц. Это изменение приводит к использованию фактического количества элементов вместо исходного однострочного предположения.
Пожалуйста, смотрите связанную документацию для деталей.
PS. Не делайте SELECT *
. Всегда указывайте список столбцов. Если не делать что-то вроде IF EXIST(SELECT * FROM)...