Кэширование подзапроса с Sql Server 2008 - PullRequest
0 голосов
/ 24 июня 2010

Я создаю хранимую процедуру с Sql Server 2008, которая возвращает 2 набора результатов.Первый запрос возвращает набор результатов, который я хотел бы использовать повторно, как во втором запросе в качестве подзапроса (см. Пример ниже).Однако, поскольку первый запрос и подзапрос по сути возвращают одни и те же данные, мне было интересно, есть ли какой-нибудь механизм кэширования, который я могу использовать.Возможно ли это сделать?Я пытаюсь оптимизировать производительность.

SELECT * 
FROM   Employees
WHERE  BossId = 1

SELECT * 
FROM   CostCenters
WHERE  EmployeeId IN (
    SELECT EmployeeId 
    FROM   Employees
    WHERE  BossId = 1
)

PS Пример - упрощенная проблема.

Ответы [ 5 ]

2 голосов
/ 24 июня 2010

Вы можете кэшировать CTE, повторно используя план запроса. Это требует введения Eager Spool между результирующим набором, созданным функцией. Quassnoi использует его в этой статье , но я не могу найти лучшего примера в настоящее время. Вот еще одно хорошее чтение на Eager Spool .

1 голос
/ 24 июня 2010

Кэширование данных первого запроса, вероятно, НЕ приведет к повышению производительности.Когда SQL Server получает запрос, он разбивает его на простые шаги, выбирает правильные индексы и операторы и извлекает данные, используя эти индексы.Сохраняя данные первого запроса в табличной переменной или во временной таблице, вы не позволяете SQL Server использовать какие-либо индексы в таблице Employees.

Если вы переписываете свой запрос в его эквивалент с помощью JOIN, легче увидеть, что происходит

SELECT c.* 
FROM   CostCenters c INNER JOIN Employees e on c.EmployeeId=e.EmployeeId
WHERE e.BossId=1

Когда SQL Server увидит этот запрос, он проверит статистику таблиц.Если BossId является высокоселективным индексированным столбцом, он может сначала попытаться отфильтровать это.В противном случае он будет использовать любые индексы в столбцах EmployeeId для ограничения строк из обеих таблиц до минимума, а затем BossId, чтобы найти правильные строки и вернуть их.

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

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

1 голос
/ 24 июня 2010

Табличные переменные - ваш лучший вариант.Вы также можете улучшить производительность, используя оператор exists для подзапроса, а не in:

-- obviously the columns should match your Employees table
declare @results table (
    employeeId int,
    column1 varchar,
    column2 int
)

insert into @results
select * from Employees
where BossId = 1

-- using exists/not exists performs much better than in
select * from CostCenters
where exists ( select 0
               from @results as r
               where CostCenters.employeeId = r.employeeId )
1 голос
/ 24 июня 2010

Насколько я знаю, для этого вам понадобится либо временная таблица, либо переменная таблицы. сравнение двух здесь.

В приведенном ниже примере выражение OUTPUT используется для заполнения переменной таблицы и выбора из нее одним оператором.

declare @MatchingResults table
(
EmployeeId int primary key --Other Columns
)

INSERT INTO @MatchingResults
OUTPUT INSERTED.*
SELECT EmployeeId  --Other Columns
FROM   Employees
WHERE  BossId = 1


SELECT * 
FROM   CostCenters
WHERE  EmployeeId IN (
    SELECT EmployeeId 
    @MatchingResults))
0 голосов
/ 24 июня 2010

Лучшее решение, которое я могу придумать, - это использовать CTE

http://msdn.microsoft.com/en-us/library/ms190766.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...