全部產品
Search
文件中心

Hologres:最佳化查詢效能

更新時間:Jun 30, 2024

本文為您介紹在Hologres中對內部表效能進行調優的最佳實務。

更新統計資料

統計資訊決定是否能夠產生正確的執行計畫。例如,Hologres需要收集資料的採樣統計資訊,包括資料的分布和特徵、表的統計資訊、列的統計資訊、行數、列數、欄位寬度、基數、頻度、最大值、最小值、長索引值、分桶分布特徵等資訊。這些資訊將為最佳化器更新運算元執行預估COST、搜尋空間裁剪、估算最優Join Order、估算記憶體開銷、估算並行度,從而產生更優的執行計畫。關於統計資訊更多的介紹,請參見Using Explain

統計資訊的收集也存在一定局限,主要是針對非即時、手動觸發或者周期性觸發,不一定反映最準確的資料特徵。您需要先檢查explain的資訊,查看explain中包含的統計資訊是否正確。統計資訊中每個運算元的rowswidth表示該運算元的行數和寬度。

查看統計資訊是否正確

通過查看執行計畫:

未及時同步統計資訊導致產生較差的執行計畫,樣本如下:

tmp1表的資料量為1000萬行,tmp表的資料量為1000行。 Hologres預設統計資訊中的行數為1000行,通過執行explainSQL語句,如下展示結果所示,tmp1表的行數與實際的行數不符,該展示結果表明未及時更新統計資料。

Seq Scan on tmp1 (cost=0.00..5.01 rows=1000 width=1)

樣本

更新統計資料

tmp1tmp表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,避免多表串連時資料重分布帶來的額外開銷。motion重建立表後兩個表的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運算元被最佳化(上圖中紅框內的運算元),表明資料不會重新分配,從而避免了冗餘的網路開銷。設定DK

使用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中執行的。post

最佳化後的SQL語句如下,不再使用外部查詢引擎。

explain select * from tmp where not exists (select a from tmp1 where a = tmp.a);

最佳化後的SQL

通過改寫函數,將運算元運行在HQE引擎中,以下為函數改寫建議。同時Hologres每個版本都在不斷迭代PQE函數,以將更多函數下推至HQE。如果是HQE已經支援的函數,則可以通過升級版本來解決,詳情請參見函數功能發布記錄

Hologres原生引擎(HQE)不支援的函數

建議改寫的函數

範例

備忘

not in

not exists

select * from tmp where not exists (select a from tmp1 where a = tmp.a);

不涉及。

regexp_split_to_table(string text, pattern text)

unnest(string_to_array)

select name,unnest(string_to_array(age,',')) from demo;

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'))

select cast(substring(c1, 13, 2) as int) AS hour from t2;

改寫為:

select extract(hour from to_timestamp(c1, 'YYYYMMDD HH24:MI:SS')) from t2;

Hologres部分V0.10版本及更早版本不支援substring。V1.3版本及以上版本中,HQE已支援substring函數的非Regex入參。

regexp_replace

replace

select regexp_replace(c1::text,'-','0') from t2;

改寫為:

select replace(c1::text,'-','') from t2;

replace不支援Regex。

at time zone 'utc'

刪除at time zone 'utc'

select date_trunc('day',to_timestamp(c1, 'YYYYMMDD HH24:MI:SS')  at time zone 'utc') from t2

改寫為:

select date_trunc('day',to_timestamp(c1, 'YYYYMMDD HH24:MI:SS') ) from t2;

不涉及。

cast(text as timestamp)

to_timestamp

select cast(c1 as timestamp) from t2;

改寫為:

select to_timestamp(c1, 'yyyyMMdd hh24:mi:ss') from t2;

Hologres V2.0版本起HQE支援。

timestamp::text

to_char

select c1::text from t2;

改寫為:

select to_char(c1, 'yyyyMMdd hh24:mi:ss') from t2;

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)的執行計畫如下。執行計畫1.1

    • Hologres V1.3版本的執行計畫如下。執行計畫1.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)的執行計畫如下。執行計畫_11with

    • Hologres V1.3版本的執行計畫如下。執行計畫_13with

    從執行計畫的對比中可以看出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支援行儲存、列儲存和行列共存多種儲存模式,您可以根據業務情境選擇合適的儲存類型,如下表所示。

類型

適用情境

缺點

行儲存

  • 按主鍵進行高QPS的點查詢情境。

  • 一次能讀取所有列,並且對UPDATE、DELETE及INSERT操作的效能較好。

大範圍的查詢、全表掃描及彙總等操作效能較差。

列儲存

適用於多列按範圍查詢、單表彙總及多表串連等資料分析情境。

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列。

select sum(a) from tb1 where a > 100 and a < 200;

bitmap_columns

位元影像列

檔案內位元影像索引,資料在檔案內按該索引列建立位元影像。

對於等值查詢,Hologres可以按照數值對每一行的資料做編碼,通過位操作快速索引到對應行,時間複雜度為O(1)。

將等值查詢列作為Bitmap列。

select * from tb1 where a =100;

segment_key(也稱為event_time_column)

分段列

檔案索引,資料按Append Only方式寫入檔案,隨後檔案間按該索引鍵合并小檔案。

Segment_key標識了檔案的邊界範圍,您可以通過Segment Key快速索引到目標檔案。

Segment_key是為時間戳記、日期等有序,範圍類資料情境設計的,因此與資料的寫入時間有強相關性。

您需要先通過Segment_key進行快速過濾,再通過Bitmap或Cluster索引進行檔案內範圍或等值查詢。具備最左匹配原則,一般只有1列。

建議將第一個非空的時間戳記欄位設定為Segment_key。

select sum(a) from tb1 where ts > '2020-01-01' and a < '2020-03-02';

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;

    cluster

  • 查看是否使用Bitmap Index,語句如下。

    explain select * from tmp where c = 1;

    bitmap

  • 查看是否使用Segment Key,語句如下。

    explain select * from tmp where b > 1;

    segment