Sql-Server

SQL中TOP和MAX()/MIN()的區別

  • November 20, 2021

以我的經驗SELECT TOP,比SELECT MIN()/MAX()如果您的數據庫中有數千/百萬行如this answer以及我在這裡回答的內容和提問者的回答中看到的要快得多。

我的問題是為什麼,在我的理解中,TOP查看數據SELECT column FROM table時,ORDER BY column它會對結果進行排序,而不是只給你第一行,而MIN()/MAX()函式實際上應該只查看每一行檢查總和行,然後轉到下一行,如果該行是><上一行,則它將結果保存在函式中取決於它是 aMAX()還是 a MIN(),這正是ORDER BY應該做的。

請不要回答,根據您的經驗,這MAX()要好於問題,因為問題是/和TOP之間真的有什麼區別?兩者都查看每一行的數據,並且都可能是log(n)MAX()``MIN()``TOP

回复@JD:

一個簡單的例子是,如果您使用沒有 ORDER BY 子句的 TOP。然後,您將獲得的最高結果可能是不確定的,並且並不總是必須是 MAX() 聚合函式將引用的同一行。

絕對我只是問你什麼時候使用ORDER BY因為它的強大TOP之處在於以特定方式對其進行排序。

關於log(n)我會以不同的方式問它,如果它ORDER BY有一個Ω(n)因為它需要查看的最小數據是n並且可能有一個O() >= n因為它可能正在使用最佳排序算法O(n)

有了它,MIN()它也可能是Ω(n)O(n)因為它總是需要掃描所有數據才能找到答案,而且永遠不會超過n,那麼為什麼它有時會產生巨大的差異呢?

換一種方式:

如果我有一個包含一百萬行的表,其中包含客戶以及他們購買產品所花費的金額,如果我正在使用SELECT TOP 1 amount_column FROM customer_table ORDER BY amount_column DESC並使用SELECT MAX(amount_column) FROM customer_table第一個需求來查看所有數據amount_column並對其進行降序排序,那麼執行時間有什麼區別order 所以它是否已經排序並沒有什麼區別,因為它需要檢查所有行是否大於前一行,然後在完成執行時返回最大數量。

當我使用該MAX()函式執行此操作時,它還需要掃描(在我的理解中)所有行並將第一行保存到結果中,然後轉到下一行並檢查它是否大於結果,如果是,則將其保存到整個表的結果,依此類推,當它完成時,它返回最大數量。

因此,在我的理解中,兩者實際上都在做同樣的事情,或者我對它執行功能的方式的理解是錯誤的,這就是我要問的是否我錯了?為什麼?

問題是它們並不總是相同的,因此它們是具有不同目的的不同運營商。其中一些目的重疊,是的,但它們並不完全是一對一的。

一個簡單的例子是如果你TOP不使用ORDER BY子句。然後,您將獲得的最高結果可能是不確定的,並且不一定總是MAX()聚合函式將引用的同一行。

正如mustaccio 在評論中指出的那樣,執行計劃將具體告訴您兩個查詢之間的哪些操作不同,一個是 using TOP,另一個是 using MAX()。如果沒有特定的查詢,就沒有一個關於兩者如何相似或不同的單一答案,因為它可能因每個特定案例而異。

最後,假設兩個運算符的時間大 O 函式始終為O(log(n))也是不正確的,並且取決於數據的結構方式以及應用這些運算符的數據點。在按升序索引的Table1列中,查詢可能按O(log(n))的順序(儘管我不確定它是否甚至可能是O(1),因為該子句與索引排序匹配)但是 a可能是**O(n)**的數量級,因為 column 上沒有覆蓋索引,並且可能需要掃描整個表。(A, B, C)``A``SELECT TOP 1 A FROM Table1 ORDER BY A``ORDER BY``SELECT MAX(B) FROM Table1``B

關於您的更新,聚合函式MIN()也不MAX()需要總是掃描所有數據。我的第一個範例只是為了展示 Big O 搜尋時間複雜度在一個特定案例之間MAX()TOP一個特定案例中的差異。但是使用相同的表範例,具有相同的列和索引A僅覆蓋列升序,那麼查詢SELECT MAX(A) FROM Table1也應該產生**O(log(n))**的時間複雜度。

儘管甚至只關注使用該子句的查詢,但vs和ORDER BY之間的異同仍然會因一個案例而異,這直接取決於正在執行的查詢,以及查詢引擎為該查詢生成的執行計劃。如果您有想要討論的特定查詢和執行計劃,請隨時將其添加到您的問題中,我們可以對其進行適當的分析。TOP``MAX()``MIN()

對於您的最新更新,我相信您被絆倒的地方是資料結構的概念。您一直假設在這兩種情況下都需要分析每一行數據,並且僅在未索引的表(堆資料結構)中或查詢沒有覆蓋索引時才如此。因此,在您的範例中,對於兩個運算符,如果沒有覆蓋. amount_column但是,如果它上面有一個索引,降序,這將尊重您的語句“ …如果它已經排序”,那麼數據將儲存在B-Tree資料結構中,這將允許您的查詢在索引上查找並顯著減少執行時間降至**O(log(n))**因為它不再需要比較每一行。它需要比較的行子集遠小於整個表本身。

是的,在您的具體範例中,理論上兩個查詢都應該看到相同的搜尋時間複雜度,但實際上這又取決於您的數據的結構(在這種情況下是索引)。此外,還有其他因素可能導致兩個單獨的查詢計劃,實際上兩個查詢之間的執行時確實不同,並且只能在比較兩個實際執行計劃時討論其原因。理論上不可能進行討論,因為它可能因多種原因而有所不同,具體取決於執行計劃本身的具體內容。

引用自:https://dba.stackexchange.com/questions/302479