Для полей автоинкремента: MAX (ID) и TOP 1 ID ORDER BY ID DESC - PullRequest
16 голосов
/ 26 февраля 2009

Я хочу найти самое высокое значение AutoIncremented из поля. (он не извлекается после вставки, где я могу использовать @@SCOPE_IDENTITY и т. д.) Какой из этих двух запросов будет работать быстрее или даст лучшую производительность. Id - это первичный ключ и autoincrement поле для Table1. И это для Sql Server 2005.

SELECT MAX(Id) FROM Table1

SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC

[Изменить]
Да, в этом случае Id - это поле, в котором я определил кластеризованный индекс.
Если индекс ID DESC, то что ..
И да, было бы неплохо узнать, как это повлияет на производительность, если
1. Идентификатор - это кластерный индекс + первичный ключ.
2. Идентификатор - это кластерный индекс, а не первичный ключ.
3. Идентификатор - это не кластерный индекс ASC + первичный ключ.
4. Идентификатор - это не кластерный индекс ASC, а не первичный ключ.
5. Идентификатор является некластеризованным индексом DESC + первичный ключ.
6. Идентификатор является некластеризованным индексом DESC, а не первичным ключом.
7. Идентификатор просто AutoIncrement

Надеюсь, это не высокий заказ!

Ответы [ 7 ]

9 голосов
/ 26 февраля 2009

При наличии кластеризованного индекса практически нет разницы в производительности между двумя запросами.

Это потому, что оба будут выполнять сканирование кластерного индекса, которое будет нести 100% стоимости запроса.

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

В предложении Top используется оператор Sort, а в функции Max - оператор Stream Aggregate.

Если индекс отсутствует, функция MAX () обеспечивает лучшую производительность.

Можно найти подтверждение концепции и полное описание тестового сценария здесь

Сравнение производительности Лучшие 1 стихи MAX () Funciton

9 голосов
/ 12 августа 2009

Никто не упомянул IDENT_CURRENT ('Table1') - уносит их всех - конечно, это работает только на столбцах идентификации, но это было вопросом ...

7 голосов
/ 26 февраля 2009

Теоретически они будут использовать одни и те же планы и работать почти в одно и то же время.

На практике

SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC

более вероятно будет использовать PRIMARY KEY INDEX.

Кроме того, этот вариант более расширяем, если вы решите выбрать другой столбец вместе с id.

Фактический план MAX() гласит:

SELECT <- AGGREGATE <- TOP <- CLUSTERED INDEX SCAN

, в то время как план для TOP 1 говорит:

SELECT <- TOP <- CLUSTERED INDEX SCAN

, т.е. е. aggregate опущено.

Агрегат на самом деле здесь ничего не сделает, так как есть только одна строка.

P. S. Как отмечалось @Mehrdad Afshari и @John Sansom, в неиндексированном поле MAX немного быстрее (конечно, не в 20 раз, как говорит оптимизатор):

-- 18,874,368 rows

SET LANGUAGE ENGLISH
SET STATISTICS TIME ON
SET STATISTICS IO ON
PRINT 'MAX'
SELECT MAX(id) FROM master
PRINT 'TOP 1'
SELECT TOP 1 id FROM master ORDER BY id DESC
PRINT 'MAX'
SELECT MAX(id) FROM master
PRINT 'TOP 1'
SELECT TOP 1 id FROM master ORDER BY id DESC
PRINT 'MAX'
SELECT MAX(id) FROM master
PRINT 'TOP 1'
SELECT TOP 1 id FROM master ORDER BY id DESC
PRINT 'MAX'
SELECT MAX(id) FROM master
PRINT 'TOP 1'
SELECT TOP 1 id FROM master ORDER BY id DESC
PRINT 'MAX'
SELECT MAX(id) FROM master
PRINT 'TOP 1'
SELECT TOP 1 id FROM master ORDER BY id DESC

Changed language setting to us_english.

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.
MAX

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 20 ms.

(строк обработано: 1)
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 447, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
   CPU time = 5452 ms,  elapsed time = 2766 ms.
TOP 1

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.

(строк обработано: 1)
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 2, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
   CPU time = 6813 ms,  elapsed time = 3449 ms.
MAX

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.

(строк обработано: 1)
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 44, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
   CPU time = 5359 ms,  elapsed time = 2714 ms.
TOP 1

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.

(строк обработано: 1)
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
   CPU time = 6766 ms,  elapsed time = 3379 ms.
MAX

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.

(строк обработано: 1)
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
   CPU time = 5406 ms,  elapsed time = 2726 ms.
TOP 1

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.

(строк обработано: 1)
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
   CPU time = 6780 ms,  elapsed time = 3415 ms.
MAX

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.

(строк обработано: 1)
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 85, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
   CPU time = 5392 ms,  elapsed time = 2709 ms.
TOP 1

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.

(строк обработано: 1)
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 10, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
   CPU time = 6766 ms,  elapsed time = 3387 ms.
MAX

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.

(строк обработано: 1)
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
   CPU time = 5374 ms,  elapsed time = 2708 ms.
TOP 1

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.

(строк обработано: 1)
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
   CPU time = 6797 ms,  elapsed time = 3494 ms.
3 голосов
/ 26 февраля 2009

Просто сравните планы выполнения, и вы увидите (нажмите Ctrl+M в Management Studio при редактировании запроса). Я предпочитаю предположить, что эти запросы одинаково эффективны при условии наличия (кластеризованного) индекса в столбце Id.

Однако в целом это очень плохая идея.

2 голосов
/ 26 февраля 2009

Я только что проверил два предоставленных вами оператора SQL на типичном наборе данных:

SELECT MAX(Id) FROM Table1

SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC

И SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC незначительно быстрее, потому что у него есть последний шаг в плане выполнения. Вот планы выполнения, которые выполняет каждый запрос:

ВЫБЕРИТЕ МАКС. (Id) ИЗ таблицы1

Сканирование кластерного индекса >> Вверх >> Объединение потоков >> Выбрать

ВЫБРАТЬ ТОП-1 Id ИЗ ТАБЛИЦЫ 1 ЗАКАЗАТЬ ПО ИДЕК DESC

Сканирование кластерного индекса >> Вверх >> Выбрать

2 голосов
/ 26 февраля 2009

MAX обычно быстрее.

Оба запроса будут использовать индекс столбца, если он существует.

Если для столбца не существует индекса, запрос TOP 1 будет использовать оператор Top N Sort для сортировки таблицы вместо агрегации потоков , что замедляет его.

MAX также обеспечивает лучшую читаемость.

Дополнительное примечание : хотя MAX будет использовать оператор агрегирования потока в плане выполнения в индексированном случае, он не будет иметь никаких особых затрат, поскольку он просто обрабатывает одну строку (Actual Rows = 1 ). Вы можете сравнить запросы, запустив их в одном пакете и увидеть относительную стоимость. В индексированном случае оба запроса будут стоить 50%. Я проверил неиндексированный случай на таблице с 7000 строками, и TOP будет стоить 65% по сравнению с MAX, который стоит 35%.

1 голос
/ 26 февраля 2009

Да, в этом случае Id - это поле на который я определил кластеризованным индекс. Если индекс ID IDC, то что .. И да, было бы хорошо знать, как будет производительность влияет, если

  1. Идентификатор - это кластерный индекс + первичный ключ.
  2. Идентификатор является кластеризованным индексом, а не первичным ключом.
  3. Идентификатор - это не кластерный индекс ASC + первичный ключ.
  4. Идентификатор представляет собой некластерный индекс ASC, а не первичный ключ.
  5. Идентификатор - это не кластерный индекс DESC + первичный ключ.
  6. Идентификатор - это некластерный индекс DESC, а не первичный ключ.
  7. Идентификатор - это просто Автоинкремент

Для случаев 1 и 2 оба будут выполнять сканирование кластерного индекса, которое возвращает одну запись. Между этими двумя запросами нет разницы в IO.

Для случаев 3, 4, 5 и 6 оба будут выполнять сканирование индекса, которое возвращает одну запись. Между этими двумя запросами нет разницы в IO.

В случае 7 оба будут выполнять сканирование таблицы. Разница в стоимости ввода-вывода отсутствует.

Резюме: Дело 1-6 сделано из победы! Если вы находитесь в случае 7, то вы уже проиграли с точки зрения ввода-вывода.

Вы можете измерить IO с помощью анализатора запросов SQL. Запустите это перед вашим запросом.

SET STATISTICS IO ON
...