本文為您介紹在Hologres中對內部表效能進行調優的最佳實務。
更新統計資料
統計資訊決定是否能夠產生正確的執行計畫。例如,Hologres需要收集資料的採樣統計資訊,包括資料的分布和特徵、表的統計資訊、列的統計資訊、行數、列數、欄位寬度、基數、頻度、最大值、最小值、長索引值、分桶分布特徵等資訊。這些資訊將為最佳化器更新運算元執行預估COST、搜尋空間裁剪、估算最優Join Order、估算記憶體開銷、估算並行度,從而產生更優的執行計畫。關於統計資訊更多的介紹,請參見Using Explain。
統計資訊的收集也存在一定局限,主要是針對非即時、手動觸發或者周期性觸發,不一定反映最準確的資料特徵。您需要先檢查explain的資訊,查看explain中包含的統計資訊是否正確。統計資訊中每個運算元的rows和width表示該運算元的行數和寬度。
查看統計資訊是否正確
通過查看執行計畫:
未及時同步統計資訊導致產生較差的執行計畫,樣本如下:
tmp1表的資料量為1000萬行,tmp表的資料量為1000行。 Hologres預設統計資訊中的行數為1000行,通過執行explainSQL語句,如下展示結果所示,tmp1表的行數與實際的行數不符,該展示結果表明未及時更新統計資料。
Seq Scan on tmp1 (cost=0.00..5.01 rows=1000 width=1)
更新統計資料
tmp1和tmp表Join時,正確的explain資訊展示為資料量大的表tmp1在資料量小的表tmp上方,Hash Join應該採用資料量小的tmp表。因為tmp1表未及時更新統計資料,導致Hologres選擇tmp1表建立Hash表進行Hash Join,效率較低,並且可能造成OOM(Out Of Memory,記憶體溢出)。因此,需要參與Join的兩張表均執行analyze
收集統計資訊,語句如下。
analyze tmp;
analyze tmp1;
執行analyze
命令後,Join的順序正確。資料量大的表tmp1在資料量小的表tmp上方,使用資料量小的表tmp做Hash表,如下圖所示。並且tmp1表展示的行數為1000萬行,表明統計資訊已經更新。
當發現explain返回結果中rows=1000
,說明缺少統計資訊。一般效能不好時,其原因通常是最佳化器缺少統計資訊,需要通過及時更新統計資料,執行analyze <tablename>
,可以簡單快捷最佳化查詢效能。
推薦更新統計資料的情境
推薦在以下情況下運行analyze <tablename>
命令。
匯入資料之後。
大量的INSERT、UPDATE以及DELETE操作之後。
內部表、外部表格均需要ANALYZE。
分區錶針對父表做ANALYZE。
如果遇到以下問題,您需要先執行
analyze <tablename>
,再運行匯入任務,可以系統地最佳化效率。多表JOIN超出記憶體OOM。
通常會產生
Query executor exceeded total memory limitation xxxxx: yyyy bytes used
報錯。匯入效率較低。
在Hologres查詢或匯入資料時,效率較低,啟動並執行任務長時間不結束。
設定適合的Shard數
Shard數代表查詢執行的並行度。Shard個數對查詢效能影響至關重要,Shard數設定少,會導致並行度不足。Shard數設定過多,也會引起查詢啟動開銷大,降低查詢效率,同時引起小檔案過多,佔用記憶體更多的中繼資料管理空間。設定與執行個體規格匹配的Shard數,可以改善查詢效率,降低記憶體開銷。
Hologres為每個執行個體設定了預設的Shard數,Shard數約等於執行個體中用於核心查詢的Core數。這裡的core數,略小於實際購買的Core數(實際購買的Core會被分配給不同的節點,包括查詢節點、接入節點、控制節點和調度節點等)。不同規格執行個體預設的Shard數,請參見執行個體規格概述。當執行個體擴容後,擴容之前舊的DB對應的預設Shard數不會自動修改,需要根據實際情況修改Shard數,擴容後建立DB的Shard數為當前規格的預設數量。預設的Shard數是已經考慮擴容的情境,在資源擴容5倍以上的情境中,建議考慮重新設定Shard數,小於5倍的情境,無需修改也能帶來執行效率的提升。具體操作請參見Table Group設定最佳實務。
如下情境需要修改Shard數:
擴容後,因業務需要,原有業務有規模增長,需要提高原有業務的查詢效率。此時,您需要建立新的Table Group,並為其設定更大的Shard數。原有的表和資料仍然在舊的Table Group中,您需要將資料重新匯入新的Table Group中,完成Resharding的過程。
擴容後,需要上線新業務,但已有業務並不變化。此時,建議您建立新的Table Group,並為其設定適合的Shard數,並不調整原有表的結構。
一個DB內可以建立多個Table Group,但所有Table Group的Shard總數之和不應超過Hologres推薦的預設Shard數,這是對CPU資源的最有效利用。
JOIN情境最佳化
當有兩表或多表JOIN時,為了提高JOIN的效能,有如下幾種最佳化方式。
更新統計資料
如上述查看統計資訊中,參與Join的表如果未及時更新統計資料,可能會導致資料量大的表做了Hash表,從而導致Join效率變低。因此可以通過更新表的統計資訊,提升SQL效能。
analyze <tablename>;
選擇合適的分布列(Distribution Key)
分布列(Distribution Key)用於將資料劃分到多個Shard,劃分均衡可以避免資料扭曲。多個相關的表設計為相同的Distribution Key,可以起到Local Join的加速效果。建立表時,您可以通過如下原則選擇合適的分布列:
Distribution Key設定建議
選擇Join查詢時的串連條件列作為分布列。
選擇Group By頻繁的列作為分布列。
選擇資料分布均勻離散的列作為分布列。
更多關於Distribution Key的原理和使用詳情請參見分布鍵Distribution Key。
設定Distribution Key情境樣本
例如設定Distribution Key,表tmp和tmp1做Join,通過執行explain SQL語句看到執行計畫中有Redistribution Motion,說明資料有重分布,沒有Local Join,導致查詢效率比較低。您需要重建立表並同時設定Join Key為Distribution Key,避免多表串連時資料重分布帶來的額外開銷。重建立表後兩個表的DDL樣本語句如下。
begin; create table tmp(a int, b int, c int); call set_table_property('tmp', 'distribution_key', 'a'); commit; begin; create table tmp1(a int, b int, c int); call set_table_property('tmp1', 'distribution_key', 'b'); commit; -- 設定分布列為Join Key。 select count(1) from tmp join tmp1 on tmp.a = tmp1.b ;
通過重新設定表的Distribution Key,再次執行explain SQL語句,可以看到執行計畫中,紅框內的運算元被最佳化掉了,資料按照相同的Hash Key分佈於Shard中。因為資料分布相同,Motion運算元被最佳化(上圖中紅框內的運算元),表明資料不會重新分配,從而避免了冗餘的網路開銷。
使用Runtime Filter
從V2.0版本開始,Hologres開始支援Runtime Filter,通常應用在多表Join(至少2張表),尤其是大表Join小表的情境中,無需手動設定,最佳化器和執行引擎會在查詢時自動最佳化Join過程的過濾行為,使得掃描更少的資料量,從而降低IO開銷,以此提升Join的查詢效能,詳情請參見Runtime Filter。
最佳化Join Order演算法
當SQL Join關係比較複雜時,或者Join的表多時,最佳化器(QO)消耗在串連關係最優選擇上的時間會更多,調整Join Order策略,在一定情境下會減少Query Optimization的耗時,設定最佳化器Join Order演算法文法如下。
set optimizer_join_order = '<value>';
參數說明
參數
說明
value
最佳化器Join Order演算法,有如下幾種。
exhaustive2(V2.2及以上版本預設值):升級最佳化的動態規划算法。
exhaustive(早期版本預設值):通過動態規划算法進行Join Order轉換,會產生最優的執行計畫,但最佳化器開銷最高。
query:不進行Join Order轉換,按照SQL書寫的串連順序執行,最佳化器開銷最低。
greedy:通過貪心演算法進行Join Order的探索,最佳化器開銷適中。
補充說明
使用預設的exhaustive2演算法可以全域探索最優的執行計畫,但對於很多表的Join(例如表數量大於10),最佳化耗時可能較高。使用query或者greedy演算法可以減少最佳化器耗時,但無法產生最優的執行計畫。
最佳化Broadcast等Motion運算元
目前Hologres包含四種Motion Node,分別對應四種資料重分布情境,如下表所示。
類型 | 描述 |
Redistribute Motion | 資料通過雜湊分布或隨機分布,Shuffle到一個或多個Shard。 |
Broadcast Motion | 複製資料至所有Shard。 僅在Shard數量與廣播的表的數量均較少時,Broadcast Motion的優勢較大。 |
Gather Motion | 摘要資料至一個Shard。 |
Forward Motion | 用於聯邦查詢情境。外部資料源或執行引擎與Hologres執行引擎進行資料轉送。 |
結合explain SQL語句執行結果您可以注意如下事項:
如果Motion運算元耗時較高,則您可以重新設計分布列。
如果統計資訊錯誤,導致產生Gather Motion或Broadcast Motion,則您可以通過
analyze <tablename>
命令將其修改為更高效的Redistribute Motion分布方式。Broadcast Motion只有在Shard數較少,且廣播表的數量較少的情境下有優勢。所以如果是小表Broadcast的情境,建議您將表的Shard數量減少(盡量保持Shard Count與Worker數量成比例關係),從而提高查詢效率。Shard Count詳情請參見Shard Count。
關閉Dictionary Encoding
對於字元類型(包括Text/Char/Varchar)的相關查詢,Dictionary Encoding或Decoding會減少比較字串的耗時,但是會帶來大量的Decode或Encode開銷。
Hologres預設對所有的字元類型列建立Dictionary Encoding,您可以設定dictionary_encoding_columns為空白,或關閉部分列的自動Dictionary Encoding功能。注意,修改Dictionary Encoding設定,會引起資料檔案重新編碼儲存,會在一段時間內消耗一部分CPU和記憶體資源,建議在業務低峰期執行變更。
當Decode運算元的耗時較高時,請關閉Decode。關閉Dictionary Encoding功能可以改善效能。
當表的字元類型欄位較多時,按需選擇,可以不用將所有的字元類型都加入dictionary_encoding_columns。樣本語句如下:
begin;
create table tbl (a int not null, b text not null, c int not null, d int);
call set_table_property('tbl', 'dictionary_encoding_columns', '');
commit;
常見的效能調優手段
可以通過最佳化相應的SQL來提高查詢效率。
採用Fixed Plan
Fixed Plan適用於高吞吐情境,通過簡化的執行路徑,實現數倍效能和吞吐的提升,配置方式和使用方法請參考Fixed Plan加速SQL執行。
PQE運算元改寫
Hologres底層有原生引擎HQE(Hologres Query Engine,向量引擎)和PQE(Postgres Query Engine,分布式Postgres引擎)等多個執行引擎,如果SQL語句中包含HQE不支援的運算元,則系統會將該運算元發送至PQE執行。此時查詢的效能未能足夠最佳化,需要修改相關查詢語句。
通過執行計畫(explain
SQL)查詢,若執行計畫中出現External SQL(Postgres)
則說明這部分的SQL是在PQE中執行的。
具體樣本如下:HQE不支援not in,則會將not in操作轉到外部查詢引擎PQE執行。建議將not in重寫為not exists。最佳化前的SQL語句如下。
explain select * from tmp where a not in (select a from tmp1);
External運算元代表該部分SQL語句是在外部引擎Postgres中執行的。
最佳化後的SQL語句如下,不再使用外部查詢引擎。
explain select * from tmp where not exists (select a from tmp1 where a = tmp.a);
通過改寫函數,將運算元運行在HQE引擎中,以下為函數改寫建議。同時Hologres每個版本都在不斷迭代PQE函數,以將更多函數下推至HQE。如果是HQE已經支援的函數,則可以通過升級版本來解決,詳情請參見函數功能發布記錄。
Hologres原生引擎(HQE)不支援的函數 | 建議改寫的函數 | 範例 | 備忘 |
not in | not exists |
| 不涉及。 |
regexp_split_to_table(string text, pattern text) | unnest(string_to_array) |
| regexp_split_to_table支援Regex。 Hologres V2.0.4版本起HQE支援regexp_split_to_table,需要使用如下命令開啟GUC:set hg_experimental_enable_hqe_table_function = on; |
substring | extract(hour from to_timestamp(c1, 'YYYYMMDD HH24:MI:SS')) |
改寫為:
| Hologres部分V0.10版本及更早版本不支援substring。V1.3版本及以上版本中,HQE已支援substring函數的非Regex入參。 |
regexp_replace | replace |
改寫為:
| replace不支援Regex。 |
at time zone 'utc' | 刪除at time zone 'utc' |
改寫為:
| 不涉及。 |
cast(text as timestamp) | to_timestamp |
改寫為:
| Hologres V2.0版本起HQE支援。 |
timestamp::text | to_char |
改寫為:
| Hologres V2.0版本起HQE支援。 |
避免模糊查詢
模糊查詢(Like操作)不會建立索引。
結果緩衝對查詢的影響
Hologres會預設對相同的查詢或子查詢結果進行緩衝,重複執行會命中緩衝結果。您可以使用如下命令關閉緩衝對效能測試的影響:
set hg_experimental_enable_result_cache = off;
OOM的最佳化手段
當執行個體計算記憶體不足時通常會出現OOM,常見的報錯如下。產生OOM的原因有多種,比如計算複雜、並發量高等,可以根據不同的原因進行針對性最佳化,從而減少OOM。詳情請參見OOM常見問題排查指南。
Total memory used by all existing queries exceeded memory limitation.
memory usage for existing queries=(2031xxxx,184yy)(2021yyyy,85yy)(1021121xxxx,6yy)(2021xxx,18yy)(202xxxx,14yy); Used/Limit: xy1/xy2 quota/sum_quota: zz/100
Order By Limit情境最佳化
在Hologres V1.3之前版本,對Order By Limit情境不支援Merge Sort運算元,產生執行計畫時,在最後輸出時還會做一次排序,導致效能相對較差。從1.3版本開始,引擎通過對Order By Limit情境最佳化,支援Merge Sort運算元,實現多路歸併排序,無需再進行額外的排序,提升了查詢效能。
最佳化樣本如下。
建表DDL
begin;
create table test_use_sort_1
(
uuid text not null,
gpackagename text not null,
recv_timestamp text not null
);
call set_table_property('test_use_sort_1', 'orientation', 'column');
call set_table_property('test_use_sort_1', 'distribution_key', 'uuid');
call set_table_property('test_use_sort_1', 'clustering_key', 'uuid:asc,gpackagename:asc,recv_timestamp:desc');
commit;
--插入資料
insert into test_use_sort_1 select i::text, i::text, '20210814' from generate_series(1, 10000) as s(i);
--更新統計資料
analyze test_use_sort_1;
查詢命令
set hg_experimental_enable_reserve_gather_exchange_order =on
set hg_experimental_enable_reserve_gather_motion_order =on
select uuid from test_use_sort_1 order by uuid limit 5;
執行計畫對比
Hologres V1.3之前版本(V1.1)的執行計畫如下。
Hologres V1.3版本的執行計畫如下。
從執行計畫對比中可以看出,Hologres V1.3版本在最後輸出會少一個排序,直接多路歸併,提升了查詢效能。
Count Distinct最佳化
改寫為APPROX_COUNT_DISTINCT
Count Distinct是精確去重,需要把相同key的記錄shuffle到同一個節點去重,比較耗費資源。Hologres實現了擴充函數APPROX_COUNT_DISTINCT,採用HyperLogLog基數估計的方式進行非精確的COUNT DISTINCT計算,提升查詢效能。誤差率平均可以控制在0.1%-1%以內,可以根據業務情況適當改寫,詳情請參見APPROX_COUNT_DISTINCT。
使用UNIQ函數
Hologres從 V1.3版本開始,支援UNIQ精確去重函數,在GROUP BY KEY的KEY基數較高時,比Count Distinct效能更好,更節省記憶體。當使用Count Distinct出現OOM時,可以使用UNIQ做替換,詳情請參見UNIQ。
設定合適的Distribution Key
當有多個Count Distinct且是key是同一個並且資料離散均勻分布,建議將Count Distinct的key設定成Distribution Key,這樣相同的資料可以分布相同的Shard,避免資料Shuffle。
Count Distinct最佳化
Hologres從V2.1版本開始,針對Count Distinct情境做了非常多的效能最佳化(包括單個Count Distinct、多個Count Distinct、資料扭曲、SQL沒有Group By欄位等情境),無需手動改寫成UNIQ,即可實現更好的效能。如果想要提升Count Distinct效能,建議您將Hologres執行個體升級至V2.1及以上版本。
Group By最佳化
Group By Key會導致資料在計算時按照分組列的Key重新分配資料,如果Group By耗時較高,您可以將Group By的列設定為分布列。
-- 資料如果按照a列的值進行分布,將減少資料運行時重分布,充分利用shard的並行計算能力。
select a, count(1) from t1 group by a;
資料扭曲處理
資料在多個Shard上分布不均勻會導致查詢速度較慢,您可以通過如下語句判斷資料分布是否存在傾斜。詳情請參見查看Worker傾斜關係。
-- hg_shard_id是每個表的內建隱藏列,描述對應行資料所在shard
select hg_shard_id, count(1) from t1 group by hg_shard_id;
如果資料存在顯著傾斜,則需要更改distribution_key,選擇資料分布均勻離散的列作為分布列。
說明更改distribution_key需要重新建立表並匯入資料。
如果資料本身存在傾斜(與distribution_key無關時),建議從業務角度對資料進行最佳化,避免傾斜。
With運算式最佳化(Beta)
Hologres相容PostgreSQL ,支援CTE(Common Table Expression),常用在with遞迴查詢,其實現原理同PostgreSQL,都是基於Inlining展開的,所以當有多次使用CTE時會造成重複計算。在HologresV1.3版本中,可以通過如下GUC參數支援CTE Reuse(複用),這樣CTE只需計算一次而被多次引用,用以節省計算資源,提升查詢效能。若您的Hologres執行個體版本低於 V1.3,請升級執行個體。
set optimizer_cte_inlining=off;
該功能當前還處於Beta階段,預設沒有開啟(預設會將CTE全部Inline展開,重複計算),可手動設定GUC後開啟使用。
CTE Reuse開啟後,依賴Shuffle階段的Spill功能,因為下遊使用者消費CTE的進度是不同步的,所以資料量大的時候會影響效能。
樣本
create table cte_reuse_test_t ( a integer not null, b text, primary key (a) ); insert into cte_reuse_test_t values(1, 'a'),(2, 'b'), (3, 'c'), (4, 'b'), (5, 'c'), (6, ''), (7, null); set optimizer_cte_inlining=off; explain with c as (select b, max(a) as a from cte_reuse_test_t group by b) select a1.a,a2.a,a1.b, a2.b from c a1, c a2 where a1.b = a2.b order by a1.b limit 100;
執行計畫對比
Hologres V1.3之前版本(V1.1)的執行計畫如下。
Hologres V1.3版本的執行計畫如下。
從執行計畫的對比中可以看出Hologres V1.3之前版本會有多個AGG計算(HashAggregate),Hologres V1.3版本只需計算一次就被結果複用,提升了效能。
單階段Agg最佳化為多階段Agg
如果Agg運算元耗時過高,您可以檢查是否沒有做Local Shard層級的預彙總。
通過在單個Shard內先進行本地的Agg操作,可以減少最終彙總操作的資料量,提升效能。具體如下:
三階段彙總:資料先進行檔案層級的彙總計算,再彙總單個Shard內的資料,最後匯總所有Shard的結果。
兩階段彙總:資料先在單個Shard內進行彙總計算,再匯總所有Shard的結果。
您可以強制Hologres進行多階段彙總操作,語句如下。
set optimizer_force_multistage_agg = on;
建表屬性最佳化
選擇儲存類型
Hologres支援行儲存、列儲存和行列共存多種儲存模式,您可以根據業務情境選擇合適的儲存類型,如下表所示。
類型 | 適用情境 | 缺點 |
行儲存 |
| 大範圍的查詢、全表掃描及彙總等操作效能較差。 |
列儲存 | 適用於多列按範圍查詢、單表彙總及多表串連等資料分析情境。 | UPDATE和DELETE操作及無索引情境下的點查詢效能慢於行儲存。 |
行列共存 | 同時具備以上行列兩種使用情境。 | 儲存開銷更高。 |
選擇資料類型
Hologres支援多種資料類型,您可以根據業務情境以及需求選擇合適的資料類型,原則如下:
盡量選用儲存空間小的類型。
優先使用INT類型,而不是BIGINT類型。
優先使用精確確定的DECIMAL/NUMERIC類型,明確數值精度(PRECISION,SCALE),且精度盡量小,減少使用FLOAT/DOUBLE PRECISION等非精確類型,避免統計匯總中的誤差。
GROUP BY的列不建議使用FLOAT/DOUBLE等非精確類型。
優先使用TEXT,適用範圍更廣,當使用
VARCHAR(N)
和CHAR(N)
,N的取值盡量小。日期類型使用TIMESTAMPTZ、DATE,避免使用TEXT。
關聯條件使用一致的資料類型。
進行多表關聯時,不同列盡量使用相同的資料類型。避免Hologres將不同類型的列進行隱式類型轉換,造成額外的開銷。
UNION或GROUP BY等操作避免使用FLOAT/DOUBLE等非精確類型。
UNION或GROUP BY等操作暫不支援DOUBLE PRECISION和FLOAT資料類型,需要使用DECIMAL類型。
選擇主鍵
主鍵(Primary Key)主要用於保證資料的唯一性,適用於主鍵重複的匯入資料情境。您可以在匯入資料時設定option選擇去重方式,如下所示:
ignore:忽略新資料。
update:新資料覆蓋舊資料。
合理的設定主鍵能協助最佳化器在某些情境下產生更好的執行計畫。例如,查詢為group by pk,a,b,c
的情境。
但是在列儲存情境,主鍵的設定對於寫入資料的效能會有較大的影響。通常,不設定主鍵的寫入效能是設定主鍵的3倍。
選擇分區表
Hologres當前僅支援建立一級分區表。合理的設定分區會加速查詢效能,不合理的設定(比如分區過多)會造成小檔案過多,查詢效能顯著下降。
對於按天增量匯入的資料,建議按天建成分區表,資料單獨儲存,只訪問當天資料。
設定分區適用的情境如下:
刪除整個子表的分區,不影響其他分區資料。DROP/TRUNCATE語句的效能高於DELETE語句。
對於分區列在謂詞條件中的查詢,可以直接通過分區列索引到對應分區,並且可以直接查詢子分區,操作更為靈活。
對於周期性即時匯入的資料,適用於建立分區表。例如,每天都會匯入新的資料,可以將日期作為分區列,每天匯入資料至一個子分區。樣本語句如下。
begin;
create table insert_partition(c1 bigint not null, c2 boolean, c3 float not null, c4 text, c5 timestamptz not null) partition by list(c4);
call set_table_property('insert_partition', 'orientation', 'column');
commit;
create table insert_partition_child1 partition of insert_partition for values in('20190707');
create table insert_partition_child2 partition of insert_partition for values in('20190708');
create table insert_partition_child3 partition of insert_partition for values in('20190709');
select * from insert_partition where c4 >= '20190708';
select * from insert_partition_child3;
選擇索引
Hologres支援設定多種索引,不同索引的作用不同。您可以根據業務情境選擇合適的索引,提升查詢效能,因此寫入資料前,請根據業務情境提前設計好表結構。索引類型如下表所示。
類型 | 名稱 | 描述 | 使用建議 | 樣本查詢語句 |
clustering_key | 聚簇列 | 檔案內聚簇索引,資料在檔案內按該索引排序。 對於部分範圍查詢,Hologres可以直接通過聚簇索引的資料有序屬性進行過濾。 | 將範圍查詢或Filter查詢列作為聚簇索引列。索引過濾具備左匹配原則,建議設定不超過2列。 |
|
bitmap_columns | 位元影像列 | 檔案內位元影像索引,資料在檔案內按該索引列建立位元影像。 對於等值查詢,Hologres可以按照數值對每一行的資料做編碼,通過位操作快速索引到對應行,時間複雜度為O(1)。 | 將等值查詢列作為Bitmap列。 |
|
segment_key(也稱為event_time_column) | 分段列 | 檔案索引,資料按Append Only方式寫入檔案,隨後檔案間按該索引鍵合并小檔案。 Segment_key標識了檔案的邊界範圍,您可以通過Segment Key快速索引到目標檔案。 Segment_key是為時間戳記、日期等有序,範圍類資料情境設計的,因此與資料的寫入時間有強相關性。 | 您需要先通過Segment_key進行快速過濾,再通過Bitmap或Cluster索引進行檔案內範圍或等值查詢。具備最左匹配原則,一般只有1列。 建議將第一個非空的時間戳記欄位設定為Segment_key。 |
|
clustering_key和segment_key都需要滿足傳統資料庫(例如MySQL)的最左首碼匹配原則,即按照Index書寫的最左列排序進行索引。如果最左列為有序的情境,則按照左邊第二列進行排序。樣本如下。
call set_table_property('tmp', 'clustering_key', 'a,b,c');
select * from tmp where a > 1 ; --可以使用Cluster索引。
select * from tmp where a > 1 and c > 2 ; --只有a可以使用Cluster索引。
select * from tmp where a > 1 and b > 2 ; --a,b均可以使用Cluster索引。
select * from tmp where a > 1 and b > 2 and c > 3 ; --a,b,c均可以使用Cluster索引。
select * from tmp where b > 1 and c > 2 ; --b,c均不能使用Cluster索引。
Bitmap Index支援多個列的and或or查詢,樣本如下。
call set_table_property('tmp', 'bitmap_columns', 'a,b,c');
select * from tmp where a = 1 and b = 2 ; -- 可以使用Bitmap索引。
select * from tmp where a = 1 or b = 2 ; -- 可以使用Bitmap索引。
bitmap_columns可以在建立表後添加,clustering_key和segment_key則在建立表時已經指定,後續無法再添加。
查看是否使用Index
建立tmp表並指定索引欄位,語句如下。
begin;
create table tmp(a int not null, b int not null, c int not null);
call set_table_property('tmp', 'clustering_key', 'a');
call set_table_property('tmp', 'segment_key', 'b');
call set_table_property('tmp', 'bitmap_columns', 'a,b,c');
commit;
查看是否使用Cluster Index,語句如下。
explain select * from tmp where a > 1;
查看是否使用Bitmap Index,語句如下。
explain select * from tmp where c = 1;
查看是否使用Segment Key,語句如下。
explain select * from tmp where b > 1;