2009-02-26 12 views
16

Chcę znaleźć najwyższą wartość AutoIncremented z pola. (nie jest pobierane po wstawieniu, w którym mogę używać @@SCOPE_IDENTITY itd.) Które z tych dwóch zapytań działałoby szybciej lub zapewnia lepszą wydajność. Id to klucz podstawowy i autoincrement dla Table1. I to jest dla SQL Server 2005.Dla pól autorekrecji: MAX (ID) kontra TOP 1 ID ORDER BY ID DESC

SELECT MAX(Id) FROM Table1 

SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC 

[Edytuj]
Tak w tym przypadku Id jest pole, na którym zdefiniowano indeksu klastrowego.
Jeśli indeksem jest ID DESC, to co ..
A tak, dobrze byłoby wiedzieć, w jaki sposób wydajność wpłynie, jeśli
1. Id jest indeks klastrowany + klucz podstawowy.
2. Id jest indeksem klastrowym, a nie kluczem podstawowym.
3. Identyfikator jest nieklastrowanym indeksem ASC + klucz podstawowy.
4. Identyfikator jest nieklastrowym indeksem ASC, a nie kluczem podstawowym.
5. Id jest indeksem nieklastrowanym DESC + klucz podstawowy.
6. Identyfikator Id jest nieklastrowym indeksem DESC, a nie kluczem podstawowym.
7. Id jest po prostu AutoIncrement

Mam nadzieję, że nie jest to wysokie zamówienie!

+0

Od odpowiedzi tutaj, z indeks nie ma różnicy w wydajności. Jednak znalazłem 'MAX' /' MIN' ma kilka zalet. Po pierwsze, jak wspomniano poniżej, bez indeksu 'MAX' będzie bardziej wydajny, to również staje się znaczące, gdy masz bardziej złożone połączenia w miejscu. Po drugie, jeśli są NULL, to 'SELECT MIN' zwraca wartość, ale' SELECT TOP 1 ... ASC' zwraca 'NULL' – icc97

Odpowiedz

7

Teoretycznie będą używać tych samych planów i działać prawie w tym samym czasie.

W praktyce

SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC 

będzie bardziej prawdopodobnie użyć PRIMARY KEY INDEX.

Również ten jest bardziej rozszerzalny, jeśli zdecydujesz się wybrać inną kolumnę wraz z id.

Rzeczywisty Plan na MAX() mówi:

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

, podczas gdy plan TOP 1 mówi:

SELECT <- TOP <- CLUSTERED INDEX SCAN 

, i. mi. aggregate jest pominięty.

Agregacja właściwie nic tu nie zrobi, ponieważ jest tylko jeden rząd.

PS Jak @Mehrdad Afshari i @John Sansom zauważyć, na polu non-indeksowanej MAX jest nieco szybciej (oczywiście, że nie 20 razy jak mówi optymalizator):

 
-- 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. 
+0

Optymalizator zapytań jest deterministyczny. Dlaczego coś "prawdopodobnie" będzie używać indeksu? –

+0

Decyzje optymalizatora zależą od statystyk tabeli, które zależą od danych tabelarycznych, które są probabilistyczne. Optymalizator MOŻE zdecydować się posortować tabelę zamiast używać i SKANUJ INDEKS razem z GÓRNĄ. – Quassnoi

+0

Spóźniam się na imprezę, ale czy jest jakiś pomysł na wydajność pamięci dwóch planów scenariusza z indeksowanym polem? Jeśli wielokrotnie uruchamiamy to samo zapytanie, to w zależności od tego, który z planów ma wyższy bufor, stracimy. – vk239

3

Wystarczy porównać planów wykonania i zobaczysz (naciśnij Ctrl+M w Management Studio podczas edycji zapytania). Moje dzikie przypuszczenie będzie takie, że te zapytania są równie skuteczne, pod warunkiem, że istnieje indeks (klastrowany) w kolumnie Id.

Jednak w sumie jest to bardzo zły pomysł bardzo zły.

+0

Co to jest bardzo zły pomysł? – Learning

+0

Używanie dodatkowych zapytań w celu pobrania identyfikatora nowo dodanego wiersza jest bardzo złym pomysłem. Spora liczba operacji bazy danych może wystąpić między tymi dwoma żądaniami. –

+0

Och, rzeczywiście. Całkiem prawdziwe. +1 – Learning

2

MAX jest generalnie szybszy.

Oba zapytania użyją indeksu w kolumnie, jeśli istnieje.

Jeżeli nie istnieje indeks kolumny zapytanie TOP 1 użyje operatora Top N Sort do rodzaju ze stołu zamiast strumienia agregacji, co sprawia, że ​​wolniej.

MAX zapewnia również lepszą czytelność.

marginesie: podczas MAX użyje operatora strumień kruszywa w plan wykonania w indeksowanej przypadku nie ma żadnego konkretnego kosztu, jak to tylko przetwarza pojedynczy wiersz (Actual Rows = 1). Możesz porównywać zapytania, uruchamiając je w jednej partii i wyświetlając względny koszt. W przypadku indeksowania oba zapytania będą kosztować 50%. Przetestowałem nieindeksowaną obudowę na stole z około 7000 rzędów, a TOP kosztował 65% w porównaniu do MAX, który kosztuje 35%.

+0

TOP 1 nie posortuje zapytania. W pytaniu wyraźnie zaznaczono, że ID jest KLUCZEM PODSTAWOWYM. – Quassnoi

+0

I myślę, że wyraźnie wspomniałem "jeśli nie ma indeksu w kolumnie". Przeczytaj uważniej. –

+0

Indeks zawsze istnieje na kluczu podstawowym. – Quassnoi

9

Jeśli istnieje indeks klastrowany, nie ma praktycznie żadnej różnicy w wydajności między dwoma zapytaniami.

To dlatego, że oba będą wykonywać skanowanie indeksów klastrowych, które będą ponosić 100% kosztu zapytania.

Wykonanie dwóch zapytań w kolumnie, która nie ma indeksu powoduje, że w obu planach wykonania używane są 3 operatory.

Klauzula Góra używa operatora Sortowania, a funkcja Max używa operatora Stream Aggregate.

Gdy nie ma indeksu, funkcja MAX() zapewnia lepszą wydajność.

Dowód koncepcji można znaleźć pełne solucja scenariusza testowego można znaleźć here

Performance Comparison Top 1 Verses MAX() Funciton

+0

Poindeksował przypadek, operator agregujący strumień będzie miał "Rzeczywiste Rzędy = 1", co w zasadzie nic nie kosztuje. Jeśli nie masz indeksu, plan wykonania dla TOP 1 będzie miał sortowanie "Top N", co spowoduje, że będzie wolniejszy niż "Stream Aggregate", którego używa MAX. –

+0

@Mehrdad: Rzeczywiście tak, wszystkie szczegóły zostaną dodane do mojego bloga. –

+0

@John, użyj stałego linku do tego pytania na swoim blogu http://stackoverflow.com/questions/590079/ –

2

Właśnie testowałem dwa SQL Ci dostarczone przed typowego zestawu danych:

SELECT MAX(Id) FROM Table1 

SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC 

I SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC jest marginalnie szybszy, ponieważ ma jeden ostatni krok w planie wykonania. Oto plany wykonania zapytań każdy wykonuje:

SELECT MAX (id) FROM Table1

Clustered Index skanowania >> Top >> Stream Aggregate >> Wybierz

SELECT TOP 1 Id FROM Tabela 1 ORDER BY Id DESC

Clustered Index skanowania >> Góra >> Wybierz

1

Tak w tym przypadku identyfikatorem jest pole o numerze , w którym zdefiniowałem klastrowany indeks . Jeśli indeksem jest ID DESC, to co ..I tak byłoby miło wiedzieć, w jaki sposób wydajność byłaby dotknięte jeśli

  1. Id jest skupione indeks + klucz podstawowy.
  2. Id jest indeksem klastrowym, a nie kluczem podstawowym.
  3. Id jest kluczem lokalnym nie indeksowanym kodem ASC +.
  4. Id to indeks bez klastrów ASC, a nie klucz podstawowy.
  5. Id to indeks klastrowy DESC + bez klastrów.
  6. Id jest indeksem nieklastrowym DESC, a nie kluczem podstawowym.
  7. Id tylko AutoIncrement

W przypadkach 1 i 2, zarówno wykona skanowanie indeksu klastrowego, która zwraca pojedynczy rekord. Między tymi dwoma zapytaniami nie ma różnicy IO.

W przypadku przypadków 3, 4, 5 i 6 obie wykonają skanowanie indeksu, które zwraca pojedynczy rekord. Między tymi dwoma zapytaniami nie ma różnicy IO.

W przypadku 7, obie przeprowadzą skanowanie tabeli. Nie ma różnicy w kosztach IO.

Podsumowanie: Przypadek 1-6 składa się z wygranej! Jeśli jesteś w przypadku 7, to już straciłeś z punktu widzenia IO.

Możesz zmierzyć IO za pomocą SQL Query analyzer. Uruchom to przed zapytaniem.

SET STATISTICS IO ON 
8

Nikt nie wspomniał IDENT_CURRENT („Tabela1”) - wieje je wszystkie - oczywiście to działa tylko na kolumnach tożsamość, ale był pytanie ...

+2

Wybrane, ale nie * zawsze * stosowane, ponieważ 'IDENT_CURRENT' niekoniecznie znajduje się w zasięgu. Aby być najszybszym i najbezpieczniejszym, transakcja powinna znajdować się w procedurze przechowywanej i użyć 'SCOPE_IDENTITY()' – Matthew