在 PostgreSQL 中,B-Tree Index 不僅能加快搜尋速度,還能提升 ORDER BY
查詢的效率。在預設情況下,B-Tree 會以升序(ascending) 的順序儲存,並將 NULL 值放在最後(NULLS LAST)。
那麼如果查詢的 ORDER BY
需求剛好符合 Index 的排序方式,資料庫就能直接使用 Index 順序來產生排序結果,少掉額外的排序步驟,加速查詢的速度!
根據官方文件的說明:
In addition to simply finding the rows to be returned by a query, an index may be able to deliver them in a specific sorted order. This allows a query's ORDER BY specification to be honored without a separate sorting step.
預設情況下,B-Tree Index 會將欄位值按照升序(ascending)排序,NULL 值則位於最後。所以對 Index 欄位進行前向掃描(forward scan)時,會自動符合 ORDER BY x ASC NULLS LAST
的要求。
By default, B-tree indexes store their entries in ascending order with nulls last (table TID is treated as a tiebreaker column among otherwise equal entries). This means that a forward scan of an index on column x produces output satisfying ORDER BY x (or more verbosely, ORDER BY x ASC NULLS LAST).
那我們就來做個小測試,驗證上面的敘述是不是真的吧!
ORDER BY
效果這裡一樣用 quizzes 這張表來做實驗,假設我們需要根據 subject
欄位來排序題庫。先將我們前面設定的 Index 刪除:
DROP INDEX IF EXISTS idx_quizzes_school_subject_chapter;
我們單獨把 subject
欄位建立 Index:
CREATE INDEX idx_quizzes_subject ON quizzes (subject);
接下來就來看如果使用 order by subject
來查詢,是否會使用到 Index 加速查詢呢?
EXPLAIN ANALYZE
SELECT * FROM quizzes ORDER BY subject;
這邊可以看到 Index Scan,表示 PostgreSQL 直接利用 Index 來輸出排序後的結果,避免了額外的排序。
反向排序(DESC)
假設我們今天想要查詢的資料是反向排序(desending),這樣也能用到 Index 嗎?
EXPLAIN ANALYZE
SELECT * FROM quizzes ORDER BY subject DESC;
答案是會的!這裡可以看到 Index Scan Backward,代表資料庫直接反向讀取 B-Tree,而不需要額外的排序操作。
The index can also be scanned backward, producing output satisfying ORDER BY x DESC (or more verbosely, ORDER BY x DESC NULLS FIRST, since NULLS FIRST is the default for ORDER BY DESC). An index stored in ascending order with nulls first can satisfy either ORDER BY x ASC NULLS FIRST or ORDER BY x DESC NULLS
ORDER BY + LIMIT:加速 Top-N 查詢
官方文件有特別提到,Index 特別適用於 ORDER BY ... LIMIT n
查詢,因為它可以讓資料庫直接取得前 n 筆資料,而不需要掃描完整 table。
Indexes are more useful when only a few rows need be fetched.
An important special case is ORDER BY in combination with LIMIT n: an explicit sort will have to process all the data to identify the first n rows, but if there is an index matching the ORDER BY, the first n rows can be retrieved directly, without scanning the remainder at all.
所以如果 ORDER BY
條件與 Index 相符,PostgreSQL 可以直接利用 Index 排序,特別是在搭配 LIMIT n 時,因為他只要讀取前 n 筆資料之後就結束,剩餘的資料不需要再讀取,效能提升會更明顯。
ORDER BY
查詢:如果 ORDER BY
條件與 Index 順序一致,PostgreSQL 可以省略掉額外的排序步驟,讓查詢速度更快。ORDER BY
使用 DESC,PostgreSQL 也可以透過反向掃描來產生結果。ORDER BY + LIMIT
:Index 可以讓 PostgreSQL 直接查詢前 n 筆資料,而不需要先對所有資料排序,大幅減少查詢時間。https://www.postgresql.org/docs/current/indexes-ordering.html