Hologres支持為實時報表等場景提供分頁能力,本文為您介紹幾種常見的分頁實踐,您可以根據業務需求選擇合適的方案,以達到更佳的查詢性能。
分頁決策樹
分頁SQL命令語法如下。
SELECT ...
FROM ...
ORDER BY key
LIMIT N OFFSET S;
SQL實現原理:對于掃描出來的記錄,按照key排序,取TOP N+S
條記錄(通過部分排序PARTIAL SORT
實現),然后丟棄前S條記錄,返回剩下的N條記錄。
在分頁方案中,核心的考慮因素如下:
N:每頁的記錄條數。一般數值范圍為
10~1000
。S:分頁起始大小。如果S很大(比如第1000頁,一般稱為“深分頁”),則
TOP N+S
的記錄就非常多,因此求TOP的代價就非常大。W:每條記錄的大小。排序時會有大量的記錄
COPY
動作,如果W很大,在排序時要COPY
的內容就會非常大,這會極大的影響查詢性能。
方案1:基本分頁法
適用場景:適用于S不大(S<100*N,淺分頁)且W不大(每條記錄大小W<10KB)的場景。
SQL示例如下。
重要如果未使用
ORDER BY
子句,則輸出結果的順序是未定義的。因此使用LIMIT N OFFSET S
語法進行兩次分頁時,可能會輸出重復結果或者跳過某些記錄的結果。SELECT * FROM table1 ORDER BY key1 LIMIT N OFFSET S;
該SQL語法等價于MySQL的如下語法:
-- 在MySQL中如下兩種SQL都是可使用 SELECT * FROM table1 ORDER BY key1 LIMIT S, N; SELECT * FROM table1 ORDER BY key1 LIMIT N OFFSET S;
方案2:主鍵排序分頁方案
適用場景:適用于表有主鍵(Primary Key)且分頁是按照表的主鍵進行排序的場景。
SQL命令語法如下。
SELECT * FROM table1 ORDER BY pk LIMIT N OFFSET S;
對于深分頁(S較大)或者每條記錄的大小W比較大的場景,如下SQL語法可以節省資源和提高查詢效率:
SELECT * FROM table1 -- ?填入上一頁最后一條記錄的pk WHERE pk > ? ORDER BY pk LIMIT N;
說明此場景中應用側會記住上一頁的位置,下一頁直接從該位置開始讀取。由于在掃描時已經對數據進行過濾,所以排序的數據量會變小,從而提高查詢效率。
方案3:基于臨時表的分頁方案
適用場景:適用于查詢過程中涉及多張表,且需要經過復雜計算后再對結果集進行分頁的場景(如使用
JOIN
連接多張表的查詢結果)。SQL命令語法如下。
SELECT * FROM ( ... 復雜SQL子查詢 ) ORDER BY key1 LIMIT N OFFSET S;
該場景下,由于每次分頁都需要把復雜SQL子查詢重新執行一遍,因此性能會很差。建議先把復雜SQL子查詢的結果寫入一張臨時表中,然后查詢操作基于該臨時表進行,對應的SQL步驟如下:
為了避免每次子查詢都創建一張臨時表,導致臨時表泛濫,可以事先建立一張臨時表。
BEGIN CREATE TABLE query_result_table_tmp( query_id text, key1 text, ... ); CALL set_table_property('query_result_table_tmp', 'distribution_key', 'query_id'); CALL set_table_property('query_result_table_tmp', 'clustering_key', 'query_id,key1'); CALL set_table_property('query_result_table_tmp', 'time_to_live', '24 hour');
對于每個復雜子查詢,將結果寫入臨時表。
INSERT INTO query_result_table_tmp(query_id, key1, ...) -- ?填入query_id SELECT ?, key1, ... FROM ( ... -- 復雜SQL子查詢 );
分頁語句實現如下。
SELECT * FROM query_result_table_tmp ORDER BY key1 LIMIT N OFFSET S;