網路應用程式通常會在向使用者呈現資料時,將資料分頁。使用者會收到一頁的結果,當他們前往下一頁時,系統會擷取並顯示下一批結果。本頁說明如何在 Spanner 中執行全文搜尋時,在搜尋結果中加入分頁。
分頁選項
在 Spanner 中實作分頁查詢有兩種方式:以鍵為基礎的分頁 (建議) 和以偏移為基礎的分頁。
以鍵為基礎的分頁是一種方法,可擷取較小且更易管理的搜尋結果,同時確保各項要求的結果一致。系統會使用頁面上最後一個結果的專屬 ID (「鍵」) 做為參照點,擷取下一組結果。
Spanner 通常建議使用以鍵為基礎的分頁。雖然以偏移量為基礎的分頁方式較容易實作,但有兩個重大缺點:
- 查詢費用增加:以偏移量為基礎的分頁會重複擷取及捨棄相同的結果,導致費用增加且效能降低。
- 不一致的結果:在分頁查詢中,每個網頁通常會在不同的讀取時間戳記下載。舉例來說,第一頁可能來自下午 1 點的查詢,而下一頁則來自下午 1 點 10 分的查詢。也就是說,搜尋結果可能會在查詢之間變更,導致不同網頁的結果不一致。
另一方面,以鍵為基礎的分頁則會使用頁面上最後一個結果的專屬 ID (鍵) 擷取下一組結果。這樣一來,即使基礎資料有所變更,也能確保擷取效率和結果一致性。
為了確保網頁結果的穩定性,應用程式可以在相同時間戳記針對不同網頁發出所有查詢。不過,如果查詢超過版本保留期間 (預設為 1 小時),這項作業可能會失敗。舉例來說,如果 version_gc
為一小時,而使用者在下午 1 點擷取第一個結果,並在下午 3 點點選「Next」,就會發生這個失敗。
使用以鍵為基礎的分頁
以鍵為基礎的分頁會記住前一頁的最後一個項目,並將其用作下一頁查詢的起點。為達到這個目的,查詢必須傳回 ORDER BY
子句中指定的欄,並使用 LIMIT
限制列數。
如要讓以鍵為基礎的分頁功能運作,查詢必須依照某種嚴格的總順序排序結果。取得這個值最簡單的方法,就是選擇任一總排序,然後視需要新增平手判斷資料欄。在大多數情況下,總訂單就是搜尋索引排序順序,而資料欄的獨特組合就是基礎資料表的主鍵。
使用 Albums
範例結構定義,第一頁的查詢如下所示:
GoogleSQL
SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 10;
PostgreSQL
SELECT albumid, releasetimestamp
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')
ORDER BY releasetimestamp DESC, albumid
LIMIT 10;
AlbumId
是平手時的判斷依據,因為 ReleaseTimestamp
不是鍵。兩個不同的專輯可能會使用相同的 ReleaseTimestamp
值。
為了繼續執行,應用程式會再次執行相同的查詢,但會使用 WHERE
子句限制上一個網頁的結果。額外條件必須考量鍵方向 (升冪或降冪)、平手時的判斷方式,以及可為空值的資料欄的 NULL 值順序。
在本範例中,AlbumId
是唯一的鍵欄 (以升冪順序),且不得為空值,因此條件如下:
GoogleSQL
SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE (ReleaseTimestamp < @last_page_release_timestamp
OR (ReleaseTimestamp = @last_page_release_timestamp
AND AlbumId > @last_page_album_id))
AND SEARCH(AlbumTitle_Tokens, @p)
ORDER BY ReleaseTimestamp DESC, AlbumId ASC
LIMIT @page_size;
PostgreSQL
本範例使用查詢參數 $1
、$2
、$3
和 $4
,這些參數分別與 last_page_release_timestamp
、last_page_album_id
、query
和 page_size
指定的值繫結。
SELECT albumid, releasetimestamp
FROM albums
WHERE (releasetimestamp < $1
OR (releasetimestamp = $1
AND albumid > $2))
AND spanner.search(albumtitle_tokens, $3)
ORDER BY releasetimestamp DESC, albumid ASC
LIMIT $4;
Spanner 會將這類條件解讀為可尋找。這表示 Spanner 不會讀取您篩除的文件索引。這項最佳化功能讓以鍵為基礎的分頁比以偏移量為基礎的分頁更有效率。
使用偏移式分頁
以偏移為基礎的分頁功能會利用 SQL 查詢的 LIMIT
和 OFFSET
子句模擬頁面。LIMIT
值代表每頁的結果數。OFFSET
值會設為第一頁的零、第二頁的頁面大小,以及第三頁的兩倍頁面大小。
例如,以下查詢會擷取第三個網頁,且網頁大小為 50:
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 50 OFFSET 100;
PostgreSQL
SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')
ORDER BY releasetimestamp DESC, albumid
LIMIT 50 OFFSET 100;
使用須知:
- 強烈建議使用
ORDER BY
子句,確保各頁之間的排序一致。 - 在實際查詢中,請使用查詢參數而非常數指定
LIMIT
和OFFSET
,以便更有效率地快取查詢。詳情請參閱「查詢參數」。
後續步驟
- 瞭解如何排序搜尋結果。
- 瞭解如何執行子字串搜尋。
- 瞭解如何混合全文查詢和非文字查詢。
- 瞭解如何搜尋多個欄。