1

Я хочу найти классику Наибольшая N на группу. У меня есть два способа решить эту проблемуНаибольшая N на группу в SQL Server

  1. Dense_rank Over() методу
  2. Min Over() метод

Оба работают безупречно. Теперь я хочу найти, какой из них лучше и почему.

Образец данных:

CREATE TABLE #test 
    (
     id INT, 
     NAME VARCHAR(50), 
     dates DATETIME 
    ) 

;WITH cte 
     AS (SELECT TOP (100000) n = ((Row_number()OVER (ORDER BY a.number) - 1)/3) + 1 
      FROM [master]..spt_values a 
       CROSS JOIN [master]..spt_values b) 
INSERT INTO #test 
SELECT n, 
     Getdate() + n 
FROM cte 

DENSE_RANK Over() Метод:

;WITH cte 
    AS (SELECT Dense_rank()OVER(partition BY NAME ORDER BY dates) AS rn,* 
     FROM #test) 
SELECT id, 
     NAME, 
     dates 
FROM cte 
WHERE rn = 1; 

Min Over() Метод:

WITH cte 
    AS (SELECT Min(dates)OVER(partition BY NAME) AS max_date,* 
     FROM #test) 
SELECT id, 
     NAME, 
     dates 
FROM cte 
WHERE max_date = dates 

Чтобы сравнить производительность, я проверил план выполнения, который сказал, что стоимость обоих запросов составляет 50%. Но план выполнения Max Over выглядит немного сложным. Поэтому любое руководство здесь будет полезно. У меня нет хорошего понимания в плане исполнения.

Выполнение плана: (6 записей)

enter image description here

План выполнения: (100000 записей)

Для 100000 записывает план выполнения говорит

Dense_rank Over() Query cost : 46% 
Min Over() Query cost  : 54% 

enter image description here

ответ

4

Вот некоторые замечания, которые слишком много времени для комментариев:

  • Во-первых, немного когнитивный диссонанс, потому что вы расчета min(), но просят о max(). (Эти два должны быть эквивалентны с точки зрения производительности.)
  • Вам действительно нужно протестировать большее количество данных. Оценка планов выполнения на небольшие суммы вводит в заблуждение.
  • Два метода не являются точно то же самое. Если у вас есть NULL значений в dates, тогда результаты могут быть разными (max() over . . . не может возвращать строки, где dense_rank() всегда будет возвращать хотя бы одну строку).
  • Следовательно, планы выполнения должны быть разными.
  • Я бы ожидал, что два будут по существу одинаковыми с точки зрения производительности.
  • Оба метода должны использовать индекс на #test(name, dates), если оптимизатор считает это желательным.

Итак, если вы хотите получить реальный ответ на этот вопрос, сгенерируйте кучу данных (скажем, не менее 100 000 строк) и посмотрите планы выполнения этих данных.

+0

его опечатка обновлен до 'MIN Over'. Будет обновлен план выполнения после добавления 100 000 строк в таблицу –

+0

Обновлен план выполнения для 100 000 записей. Я вижу некоторую разницу в стоимости запроса –

4

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

set statistics io on и set statistics time on (только не забудьте выключить их.)

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

Я запустил их со статистикой, которую я упомянул, и Dense_Rank явно делает меньше работы и более чем на 100 мс быстрее.

DENSE_RANK:

CPU time = 156 ms, elapsed time = 211 ms. 
Table 'test'. Scan count 13, logical reads 359 

Min:

CPU time = 389 ms, elapsed time = 317 ms 
Table 'test'. Scan count 13, logical reads 359 
Table 'Worktable'. Scan count 25, logical reads 203028 

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

  • Нет связанных вопросов^_^