2013-12-06 5 views
0

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

Ниже приведена действительно урезанная версия того, что я пытаюсь сделать. «Основной запрос» - это дорогостоящий поиск, который является общим для следующих других запросов под ним. «Первый набор результатов» должен возвращать то, что я хочу, как и следовало ожидать, но «второй набор результатов» терпит неудачу, потому что основной запрос выходит за рамки.

-- Primary query 
WITH t(ItemId, Row) AS (
    SELECT ItemId, ROW_NUMBER() OVER(ORDER BY DateCreated DESC) AS Row 
    FROM Items 
) 

-- First result set 
SELECT * 
FROM Items 
INNER JOIN t ON Items.ItemId = t.ItemId 
WHERE t.Row < 10 

-- Second result set 
SELECT * 
FROM Photos 
INNER JOIN ItemPhotos ON Photos.PhotoId = ItemPhotos.PhotoId 
INNER JOIN t ON ItemPhotos.ItemId = t.ItemId 
WHERE t.Row < 10 

Есть ли способ сделать это, чтобы работать второй результирующий набор?

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

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

+0

Зачем нужен массив результатов? Для меня это выглядит так, как будто вы можете просто возглавить 10 пунктов ItemId, упорядоченных по DateCreated, и присоединиться к этому. С индексом по DateCreated и id соединения, который не может быть проблематичным, или я что-то упускаю? – Anton

+1

Даже если синтаксис действительно сработал, это не устранит круглые поездки в базу данных. CTE - это просто синтаксис. – Paparazzi

+0

@ Антон Из того, что я понял, это просто упрощенный пример. – SQB

ответ

3

Нет, нет способа сделать это.

Что вы делаете может делать, использовать временные таблицы, как вы сказали, или использовать материализованное представление.

0

, если вы не хотите использовать временную таблицу вы можете использовать переменную таблицу, как это: (изменено из-за ошибки Благодаря Аарону)

объявлять @mytable (......)

+0

Нет, это совершенно неправильно. [Возможно, вы должны это прочитать] (http://dba.stackexchange.com/questions/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386# 16386). –

+0

Спасибо, да извините, я быстро интерпретировал новую функциональность 2014 года (OLTP). Вот ссылка, сравнивающая таблицу переменных со временной таблицей. Http://stackoverflow.com/questions/11857789/when-should-i-use-a-table-variable-vs-temporary-table-in-sql-server –

+1

Теперь, когда вы знаете, что переменная таблицы ничем не отличается от временной таблицы с точки зрения местоположения хранилища, как вы можете думать, что результат предложения WITH тот же самый для оптимизатора, что и содержимое переменной таблицы? –

0

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

Учитывая t.Row> 1740 И t.Row < = 1760 Я бы #temp через временную таблицу
Мне нравится простота временной таблицы, но не опрашивает оптимизировать хорошо

Это предполагает ItemID является PK

Если вы собираетесь создать #temp, тогда вставьте в него некоторую структуру, чтобы сделать соединения максимально эффективными.

Порядок мимо в вкладыш будет минимизировать (или исключить) фрагментации на ПК

# temp.rn в соединении, а не WHERE дает оптимизатор запросов возможность фильтровать до присоединиться

IF OBJECT_ID(N'tempdb..#temp', N'U') IS NOT NULL DROP TABLE #temp; 
CREATE TABLE #temp (ItemId INT PRIMARY KEY CLUSTERED, rn INT); 

insert into #temp 
SELECT sID, ROW_NUMBER() OVER(ORDER BY addDate DESC) AS Row 
    FROM docSVsys 
where sID < 10000 
ORDER by sID; 

select count(*) from #temp; 

CREATE UNIQUE NONCLUSTERED INDEX [IX] ON #temp ([rn] ASC); 

select docSVtext.value 
    from docSVtext 
    join #temp 
    on docSVtext.sID = #temp.ItemID 
    and #temp.rn >= 100 
    and #temp.rn < 200; 

select docSVdate.value 
    from docSVdate 
    join #temp 
    on docSVdate.sID = #temp.ItemID 
    and #temp.rn >= 100 
    and #temp.rn < 200; 

IF OBJECT_ID(N'tempdb..#temp', N'U') IS NOT NULL DROP TABLE #temp; 

Другой вариант - это # ​​temp2, в который вы вставляете строки для единственного соединения условий.

Смежные вопросы