2014-10-16 3 views
3

Я занимаюсь подкачкой с SQL Server, и я бы хотел избежать дублирования, посчитав общее количество результатов как часть моего частичного набора результатов, а не получая этот набор результатов, а затем выполнив отдельный запрос, чтобы получить счетчик впоследствии. Однако проблема заключается в увеличении времени выполнения. Например, если я проверю с SET STATISTICS TIME ON, это:Использование COUNT() внутри CTE дороже, чем вне CTE?

WITH PagedResults AS (
    SELECT 
     ROW_NUMBER() OVER (ORDER BY AggregateId ASC) AS RowNumber, 
     COUNT(PK_MatrixItemId) OVER() AS TotalRowCount, 
     * 
    FROM [MyTable] myTbl WITH(NOLOCK) 
) 
SELECT * FROM PagedResults 
WHERE RowNumber BETWEEN 3 AND 4810 

... или это (чей план выполнения идентичен):

SELECT * FROM (
    SELECT TOP (4813) 
     ROW_NUMBER() OVER (ORDER BY AggregateId ASC) AS RowNumber, 
     COUNT(PK_MatrixItemId) OVER() AS TotalRowCount, 
     * 
    FROM [MyTable] myTbl WITH(NOLOCK) 
) PagedResults 
WHERE PagedResults.RowNumber BETWEEN 3 AND 4810 

... кажется, в среднем времени процессора (все запросы суммируется) от 1,5 до 2 раз больше, чем это:

SELECT * FROM (
    SELECT TOP (4813) 
     ROW_NUMBER() OVER (ORDER BY AggregateId ASC) AS RowNumber, 
     * 
    FROM [MyTable] myTbl WITH(NOLOCK) 
) PagedResults 
WHERE PagedResults.RowNumber BETWEEN 3 AND 4810 

SELECT COUNT(*) FROM [MyTable] myTbl WITH(NOLOCK) 

Очевидно, что я бы предпочел использовать бывший, чем последний, потому что последний избыточно повторяет положение FROM (и вес ould повторить любые WHERE предложения, если бы у меня были какие-либо), но время его выполнения намного лучше, я действительно должен его использовать. Есть ли способ, которым я могу полностью сократить время исполнения первого?

+0

Что вы получили от плана исполнения? должно быть полезно понять ваши варианты и дать некоторый намек на объяснение. – Paolo

+0

Это довольно сложно сказать, потому что планы выполнения отличаются друг от друга, но, насколько я вижу, план выполнения первого содержит этап «Вложенные петли», который соединяет колонку count с остальными, что имеет значительные накладные расходы. – Jez

ответ

1

CTE встроены в план запроса. Они выполняют точно так же, как и производные таблицы.

Производные таблицы не соответствуют физическим операциям. Они не «материализуют» результирующий набор в временную таблицу. (Я считаю, что MySQL делает это, но MySQL - это самая примитивная мейнстримовая СУБД.)

Использование OVER() действительно проявляется в плане запроса в качестве буферизации в таблицу темп. Не совсем понятно, почему это было бы быстрее, чем просто перечитывать базовую таблицу. Буферизация довольно медленная, потому что записи более интенсифицированы по ЦП, чем чтение в SQL Server. Мы можем просто прочитать дважды из оригинальной таблицы. Вероятно, поэтому последний вариант быстрее.

Если вы хотите избежать повторения частей запроса, используйте функцию view или table-value. Конечно, это не отличные варианты для одноразовых запросов. Вы также можете генерировать SQL в прикладном уровне и повторно использовать строки. ORM также делают это намного проще.

+0

Это может быть не так быстро, но почему это медленнее? – Jez

+0

Из-за буферизации. – usr

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