Lindorm寬表引擎是一款分布式資料引擎,寬表引擎中的資料均按照主鍵進行分布。在執行查詢時,如果表中存在多列主鍵,系統會從最左邊的主鍵開始匹配。如果主鍵設定不當,則可能導致主鍵無法被有效利用,進而產生熱點問題,影響查詢效能。因此,在資料分區和資料查詢中,主鍵的設計至關重要。本文介紹設計主鍵前需要考慮的一些問題以及設計樣本。
問題考慮
主鍵是唯一的嗎?
相同的主鍵在Lindorm中被認為是同一條資料的多個版本,查詢時預設返回最新版本的資料,所以通常主鍵都需要保證唯一,除非用到多版本特性。
最佳設計樣本:主鍵可以是一列,也可以是多列的組合。每個主鍵表示一條記錄。
[userid]
:表示主鍵只有一列,每個使用者只有一條記錄。[userid][orderid]
:表示主鍵為兩列的組合,每個使用者有多條記錄。
基於主鍵可以滿足哪種查詢情境?
主鍵的設計限制了資料的查詢方式,一條SELECT
查詢語句,Lindorm伺服器端會編譯為兩種查詢方式。
根據完整的主鍵查詢(get方式),例如
SELECT * FROM table WHERE userid='abc' AND orderid=123
。說明get方式需要知道所有的主鍵列,即組成主鍵所有欄位的值都是確定的。
根據主鍵的範圍查詢(scan方式),例如
SELECT * FROM table WHERE userid='abc' AND 123<orderid<456
。說明scan方式需要指定第一列主鍵的範圍,否則Lindorm預設會拒絕低效的全表掃描查詢,具體說明,請參見低效查詢語句及說明。
最佳設計樣本:在有限的查詢方式下如何?複雜查詢?以下方法可以幫您實現。
再建立一張表作為索引表。
查詢條件給定非主鍵列範圍,服務端會使用Filter過濾不需要的資料。
使用二級索引。
使用
ORDER BY
方法實現倒序(將新資料排在前面),例如SELECT * FROM table WHERE userid='abc' AND 123<orderid<456 ORDER BY orderid DESC
。說明由於表欄位原始順序的倒序效能比正序效能差,如果大部分資料是倒序情境,可以體現在主鍵設計上,主鍵設計為
[userid][orderid DESC]
。
設計主鍵應該考慮哪些因素?
需要考慮主鍵列值的長度和主鍵列的個數。
主鍵列值的長度:主鍵列值的長度建議盡量短小,建議您採用固定長度的類型,例如長整型。對於非固定長度的類型,主鍵列值的長度控制在2 KB之內,有利於減少儲存成本,提升寫效能。
主鍵列的個數:主鍵列越少,寫入效能越高,同時可以降低儲存成本。建議將主鍵列的數量控制在1~3個。
設計主鍵應該避免哪些情況?
Lindorm是一個分散式資料庫,資料按照主鍵分布。如果存在多列主鍵,則按照資料庫的最左匹配原則分布。為避免產生寫入熱點問題,建議您遵循以下條件:
主鍵的第一列盡量分散,不建議主鍵名使用相同的首碼。
避免使用共同首碼或者自增的資料作為主鍵的第一列或者索引列(例如時間戳記列)。
避免使用有明顯首碼的欄位或者枚舉(比如order_type)作為主鍵的第一列。
如果有類似的情況無法避免,可以利用Hash演算法進行打散。例如:
假設原始主鍵pk是遞增的字串,可以設定新主鍵pk1 = hash(pk).substring(0,4)+pk
,即選取原始主鍵pk經過Hash演算法計算後的結果前4位作為首碼,拼接原始主鍵pk,最終形成新的主鍵pk1。
資料足夠分散,會存在堆積的熱點現象嗎?
散列的目的是將資料分散到不同的分區,不至於產生熱點使某一台伺服器終止,其他伺服器空閑,充分發揮分布式和並發的優勢。
最佳設計樣本:
設計md5散列演算法,主鍵設計為
[md5(userid).subStr(0,4)][userId][orderid]
。設計反轉,主鍵設計為
[reverse(userid)][orderid]
。設計模數,主鍵設計為
[bucket][timestamp][hostname][log-event]; long bucket = timestamp % numBuckets
。增加隨機數,主鍵設計為
[userId][orderid][random(100)]
。
主鍵可以再精簡點嗎?
精簡的主鍵列可以減少資料量,提高資料查詢和資料寫入效率。
最佳設計樣本:
使用Long或Int代替String,例如
'2015122410' => Long(2015122410)
。使用編碼代替名稱,例如
'淘寶'=> 'tb'
。
常見設計樣本
日誌類、時間序列資料。列舉出三個情境設計主鍵。
查詢某台機器某個指標某段時間內的資料,主鍵設計為
[hostname][log-event][timestamp]
。查詢某台機器某個指標最新的幾條資料,主鍵設計為
[hostname][log-event][timestamp DESC]
。查詢的資料存在只有時間一個維度或某一個維度資料量巨大的情況,主鍵設計為
long bucket = timestamp % numBuckets; [bucket][timestamp][hostname][log-event]
。
交易類資料。列舉出四個情境設計主鍵。
查詢某個賣家某段時間內的交易記錄,主鍵設計為
[seller_id][timestamp][order_number]
。查詢某個買家某段時間內的交易記錄,主鍵設計為
[buyer_id][timestamp][order_number]
。根據訂單號查詢,主鍵設計為
[order_number]
。查詢中同時滿足三張表,一張買家維度資料表主鍵設計為
[buyer_id][timestamp][order_number]
。一張賣家維度資料表主鍵設計為[seller_id][timestamp][order_number]
。一張訂單索引表主鍵設計為[order_number]
。