Lindorm寬表支援Tabular模型下的二級索引功能,此功能在非主鍵匹配的查詢情境下,可以降低應用的開發複雜性、保證資料的一致性和提高寫入效率。本文介紹Lindorm Tabular模型下二級索引的基本特性和使用樣本。
背景資訊
對於Lindorm Tabular模型,Lindorm寬表有表結構且表對應的列有類型預定義的。Lindorm原生二級索引功能在阿里雲應用多年,經歷了多次雙11的考驗,更加適用於解決海量資料的全域索引。Lindorm與Phoenix在索引情境下的效能對比如下圖所示。
讀寫RT對比
產品
單行寫RT
單行讀RT
批量寫100行RT
Lindorm
1.409
0.492
10.447
開源Phoenix
2.264
2.594
26.224
可以看出,在索引情境下Lindorm進行讀寫操作耗時更少。單行寫RT用時約為開源Phoenix的62%,單行讀RT用時約為開源Phoenix的19%,批量寫100行RT約為開源Phoenix的40%。
寫吞吐對比
產品
BatchPut
Put
Get
Scan
Lindorm
198174
73214
156372
1283451
開源Phoenix
56923
33156
25910
224085
可以看出,在索引情境下Lindorm的BatchPut約為開源Phoenix的3.5倍,Put約為開源Phoenix的2.2倍,Get約為開源Phoenix的6倍,Scan約為開源Phoenix的5.7倍。
特性介紹
Lindorm二級索引支援為單表建多個索引,每個索引在物理上映射為一張資料表,與主表相互獨立,每個索引有不同的儲存策略(如採用不同的壓縮演算法、冷熱分離策略)等屬性。寫主表時,Lindorm會自動更新所有索引表,並確保主表和索引表資料的一致性。讀資料時,您只需針對主表發起查詢,Lindorm會根據WHERE條件和SCHEMA自動選擇合適的索引(包括主表)執行查詢操作(支援HINT來幹預最佳化器行為)。Lindorm二級索引的基本特性如下。
支援單個主表建多個索引。
支援複合式索引(單列和多列)。
支援冗餘索引,全冗餘索引可自動冗餘主表新增的列。
查詢最佳化:根據WHERE語句自動選擇索引,支援HINT來幹預最佳化器的選擇。
Online Schema Change:索引變更不影響主表的正常讀寫,可以隨時新增、刪除、更新索引。
支援資料有效期間(簡稱:TTL):索引表自動繼承主表的TTL設定,主表和索引表資料同時到期。
支援動態列:支援寫入動態列和冗餘動態列。
支援自訂資料版本:自訂時間戳記後自動寫入資料。
使用要求
伺服器:使用Lindorm執行個體。
用戶端:更多資訊,請參見通過Lindorm寬表SQL使用寬表引擎。
Lindorm-Cli用戶端:更多資訊,請參見通過Lindorm-cli串連並使用寬表引擎。
基本概念
強一致性:是指主表和索引表的資料一致性。為了滿足資料一致性的需求,最大程度減少二級索引的額外開銷,提升高吞吐的寫入能力,Lindorm二級索引在強一致性中具有如下約束。
不支援快照隔離性。在資料寫入過程中不保證同時可見,但是返回用戶端寫入成功後主表和索引表資料可見。
在返回用戶端逾時或IO出錯情況下,該資料在主表和索引表中不保證可見,但最終主表和索引表資料會保持一致。
可選的索引組織成本:在主表有一個索引的情況下,寫放大有四次操作(讀主表,刪除索引老資料,寫索引,寫主表),會大大增加維護索引的成本。但不是所有情境都會產生寫放大,比如日誌情境只有資料插入沒有更新操作,此時索引表不存在老資料,只需要做寫索引和寫主表操作。所以Lindorm提出了Mutability的概念。Mutability是指對主表的寫入模式進行分類,並以此組織索引資料,針對不同的需求實現最低的索引組織成本。Mutability分類和描述如下表所示。Mutability屬性需要在建立表或修改表時通過Table_Options參數進行設定,具體操作,請參見CREATE TABLE文法介紹。
Mutability分類
約束
操作成本
操作說明
無索引
無。
1
沒有索引的情況下,直接寫主表,為1次操作。
IMMUTABLE
整行寫入,不可更新或刪除。
2
寫主表,寫索引表。所有情境中成本最低,效能最好。
IMMUTABLE_ROWS
整行寫入,整行刪除,不可更新。
2~3
正常寫入時:寫主表,寫索引表。在刪除情境下需額外讀一次主表。效能僅次於IMMUTABLE。
MUTABLE_LATEST
可更新,可刪除。
4
讀主表,刪索引,寫索引,寫主表。
MUTABLE_ALL
無限制,可使用自訂時間戳記寫入。
4
讀主表,刪索引,寫索引,寫主表。
說明IMMUTABLE和IMMUTABLE_ROWS不涉及資料更新,無寫放大問題,成本最低。適合高吞吐寫的情境,如日誌、監控等。
IMMUTABLE不涉及刪除,所以可充分利用Lindorm的多IDC部署,實現多活的資料訪問。
選擇兩類IMMUTABLE可以有效降低索引情境下的寫時延,提高整體吞吐。實際的業務中,如果不滿足IMMUTABLE情境,可以通過資料冗餘來改造成IMMUTABLE情境。
更新自訂時間戳記的索引:Lindorm支援自訂時間戳記進行寫入,可以在任意時間戳記進行資料更新,由系統來判斷只有時間戳記最大的資料生效。自訂時間戳記特性在控制資料有效期間、亂序、等冪等情境中發揮著重要的作用,在HBase中有廣泛的應用。Lindorm支援列級時間戳記,主表支援自訂時間戳記寫入資料。但在支援二級索引和時間戳記的NoSQL系統中,支援自訂時間戳記索引更新的,就比較罕見了。因為時間戳記亂序寫入很難有效維護索引資料的更新和刪除。Lindorm全域二級索引解決了這個問題,支援列層級自訂時間戳記更新。下面是兩個使用自訂時間戳記的實際業務情境。
匯入與即時並存:在需要同時即時更新和歷史資料匯入的情境下,即時更新可以使用目前時間,而歷史資料匯入可以使用昨天23:59:59這個時間。所以當天未更新過的資料可以通過匯入操作而更新,已更新過的資料也不會被匯入覆蓋。
追訊息:業務系統通過訊息來觸發一系列處理邏輯,在訊息出現積壓時,系統可以跳過積壓的訊息,直接處理當前訊息,並在事後通過追訊息來處理之前積壓的任務。或者,當商務邏輯有問題時,系統也可以跳過一部分訊息來規避問題,在業務修複後重新處理。此時,業務可以通過使用訊息本身的時間來寫入資料,以此來保證追的訊息和正常訊息的準確覆蓋關係。
全冗餘索引:為了避免查詢索引之後再回查主表,通常會在索引表中冗餘一部分主表列,也稱為冗餘索引或覆蓋索引。全冗餘索引是比較常用的冗餘方案。Lindorm支援三種冗餘模式,可以在主表Schema變化以及動態列情境下簡單的實現全冗餘索引。
冗餘指定的列:顯式指定要冗餘主表的哪些列。
冗餘主表Schema中的所有列:當您需要全冗餘索引時,不需要在CREATE INDEX中將主表的每一列都顯式添加進來,而是通過一個常量來描述冗餘所有列,當主表新增列時,全冗餘索引表會自動冗餘這個新增列,無需重建索引。也無需擔心新增列的查詢會導致回查主表了。
冗餘動態列:Lindorm支援固定Schema和鬆散Schema(即動態列)。通過DYNAMIC冗餘模式,索引表能夠自動冗餘主表中的所有動態列,也會冗餘主表Schema中的所有列。
文法參考
二級索引的文法詳細說明,請參見以下文檔:
建立二級索引:CREATE INDEX。
修改二級索引:ALTER INDEX。
查看二級索引:SHOW INDEX。
構建二級索引:BUILD INDEX。
刪除二級索引:DROP INDEX
建立二級索引
建立完Lindorm主表後,可以為主表的相應列建立二級索引。以下是建立二級索引的樣本。
-- 建立主表
CREATE TABLE test (
p1 VARCHAR NOT NULL,
p2 INTEGER NOT NULL,
c1 BIGINT,
c2 DOUBLE,
c3 VARCHAR,
c5 GEOMETRY(POINT),
PRIMARY KEY(p1, p2)
) WITH (CONSISTENCY = 'strong', MUTABILITY='MUTABLE_LATEST');
-- 對c3列建立二級索引,冗餘所有列
CREATE INDEX idx1 ON test(c3 desc) WITH (INDEX_COVERED_TYPE ='COVERED_ALL_COLUMNS_IN_SCHEMA');
-- 基於索引表進行查詢,因為對c3構建索引,當指定c3進行查詢會對應命中索引表
SELECT * FROM test WHERE c3 = 'data';
建立索引有同步建立和非同步建立兩種方式,在存量資料不大的情況下,可以使用同步建立。其他情況下可以使用非同步建立。具體的文法請參見CREATE INDEX。
在已有資料的表中添加新的索引時,CREATE INDEX命令會同時將主錶的歷史資料同步到索引表中,如果主表很大時,CREATE INDEX會非常耗時間(資料同步任務是在服務端執行的,即使刪除Lindorm Shell進程也不會影響資料同步任務)。
查看二級索引
通過Lindorm寬表SQL可以查看建立的二級索引狀態。以下是查看二級索引的樣本。
SHOW INDEX FROM test;
通過樣本可以展示出test主表下建立的索引名和索引類型。
修改二級索引狀態
建立完二級索引後,如果主表有存量資料,需要手動對索引進行一次Rebuild操作,具體文法請參見BUILD INDEX;若主表沒有存量資料,則可以直接使用修改二級索引文法來修改二級索引表狀態。以下是修改二級索引狀態的樣本:
ALTER INDEX IF EXISTS idx1 ON test ACTIVE;
ALTER INDEX idx1 ON test DISABLED;
當二級索引狀態為DISABLED時,直接修改為ACTIVE狀態會導致資料缺失,因此修改前需要進行一次Rebuild操作。
刪除二級索引
通過以下樣本刪除對應主表中的相關二級索引。
DROP INDEX IF EXISTS idx1 ON test;
刪除索引操作需要您有Trash許可權。
查詢最佳化
Lindorm依據RBO(Rule Based Optimization)策略進行二級索引選擇。根據查詢條件匹配索引表的首碼,選擇匹配程度最高的索引表作為本次查詢使用的索引。通過以下樣本可以更好的理解。
-- 主表和索引表如下
CREATE TABLE dt (rowkey varchar, c1 varchar, c2 varchar, c3 varchar, c4 varchar, c5 varchar, PRIMARY KEY(rowkey));
CREATE INDEX idx1 ON dt (c1);
CREATE INDEX idx2 ON dt(c2,c3,c4);
CREATE INDEX idx3 ON dt(c3) INCLUDE(c1,c2,c4);
CREATE INDEX idx4 ON dt(c5 desc) WITH (INDEX_COVERED_TYPE ='COVERED_ALL_COLUMNS_IN_SCHEMA');
-- 查詢最佳化如下
SELECT rowkey FROM dt WHERE c1 = 'a';
SELECT rowkey FROM dt WHERE c2 = 'b' AND c4 = 'd';
SELECT * FROM dt WHERE c2 = 'b' AND c3 >= 'c' AND c3 < 'f';
SELECT * FROM dt WHERE c5 = 'c';
SELECT rowkey FROM dt WHERE c1 = 'a';
表示選擇索引表idx1
。SELECT rowkey FROM dt WHERE c2 = 'b' AND c4 = 'd';
表示選擇索引表idx2
,從中尋找所有滿足c2=b
條件的行,然後逐行按c4=d
進行過濾。雖然c4是索引列之一,但因WHERE
條件中缺少c3
列,無法匹配idx2
的首碼。SELECT * FROM dt WHERE c2 = 'b' AND c3 >= 'c' AND c3 < 'f';
表示選擇索引表idx2,由於是select *,而索引表裡並未包含主表的所有列,因此在查詢索引之後,還要回查一次主表。回查主表時,回查的Rowkey可能散布在主表的各個地方,因此,可能會消耗多次RPC。回查的資料量越大,RT越長。SELECT * FROM dt WHERE c5 = 'c';
表示選擇索引表idx4
,idx4
是全冗餘索引,所以select *
不需要回查主表。
使用限制
不同主表可以有同名索引,如dt表有索引Idx1,foo表也有索引Idx1,但同一主表下不允許有同名索引。
只能為Version為1的表建索引,不支援為多版本的表建索引。
對有TTL的主表建索引,不能單獨為索引表設定TTL,索引表會自動繼承主表的TTL。
索引列最多不超過3個。
索引列和主表主鍵,總長度不能超過30 KB。不建議使用大於100位元組的列作為索引列。
單個主表的索引表個數最多不超過5個,過多索引會造成儲存成本過高,以及寫入耗時過長。
一次查詢最多能命中一個索引,不支援多索引聯集查詢(Index Merge Query)。
建立索引時會將主表的資料同步到索引中,對資料多的表建索引會導致Create_Index命令耗時過長。
二級索引不支援batch increase功能。
命中二級索引的排序與主表不一樣。
僅支援為通過SQL或API寫入的資料構建二級索引,不支援為Bulkload(大量匯入)至Lindorm的資料構建二級索引。
問題答疑(大量匯入)至
對於索引使用上的任何問題,您可以通過DingTalk聯絡雲Lindorm答疑或工單諮詢,具體操作,請參見支援人員。