У меня есть запрос SELECT в представлении, содержащем 500 000 строк. Давайте держать это просто:Неудовлетворительная производительность SQL-запроса с использованием переменной таблицы или пользовательского типа
SELECT * FROM dbo.Document WHERE MemberID = 578310
Запрос выполняется быстро, ~0s
Давайте перепишем его для работы с набором значений, что отражает мои потребности больше:
SELECT * FROM dbo.Document WHERE MemberID IN (578310)
Это же быстро , ~0s
Но теперь набор идентификаторов должен быть переменным; определим его как:
DECLARE @AuthorizedMembers TABLE
(
MemberID BIGINT NOT NULL PRIMARY KEY, --primary key
UNIQUE NONCLUSTERED (MemberID) -- and index, as if it could help...
);
INSERT INTO @AuthorizedMembers SELECT 578310
Набор содержит одно и то же значение, но теперь переменная таблицы. Производительность такого запроса падает до 2s
, а в более сложных - до 25s
и более, а с фиксированным идентификатором - ~0s
.
SELECT *
FROM dbo.Document
WHERE MemberID IN (SELECT MemberID FROM @AuthorizedMembers)
это же плохо, как:
SELECT *
FROM dbo.Document
WHERE EXISTS (SELECT MemberID
FROM @AuthorizedMembers
WHERE [@AuthorizedMembers].MemberID = Document.MemberID)
или же плохо, как это:
SELECT *
FROM dbo.Document
INNER JOIN @AuthorizedMembers AS AM ON AM.MemberID = Document.MemberID
Производительность одинакова для всех выше и всегда намного хуже, чем один с фиксированная стоимость.
Динамический SQL с легкостью справляется, поэтому создание nvarchar, такого как (id1,id2,id3)
, и построение фиксированного запроса с ним сохраняет мое время запроса ~0s
. Но я хотел бы как можно больше избегать использования Dynamic SQL, и если да, то я бы хотел, чтобы он всегда был одной и той же строкой, независимо от значений (используя параметры, которые выше метод не позволяет).
Любые идеи о том, как получить производительность переменной таблицы подобно фиксированному массиву значений или избежать создания другого динамического кода SQL для каждого запуска?
P.S. Я попытался выше с определенным типом пользователя с такими же результатами
Edit: Результаты с временной таблицы, определяемые как:
CREATE TABLE #AuthorizedMembers
(
MemberID BIGINT NOT NULL PRIMARY KEY
);
INSERT INTO #AuthorizedMembers SELECT 578310
улучшили время выполнения до 3-х раз. (13 с -> 4 с). Который все еще значительно выше, чем динамический SQL < 1s.
Попробуйте изменить переменную таблицы во временную таблицу 'CREATE TABLE # AuthorizedMembers' Она может значительно повысить производительность в некоторых ситуациях, в зависимости от объема данных. –
'OPTION (RECOMPILE)' – Devart
как насчет 'INNER JOIN', вместо' LEFT JOIN + IS NOT NULL'? – Kobi