前言
ClickHouse中除了主鍵索引之外還有一種叫做跳數索引(Skipping index)的索引類型,就和這種索引的名稱一樣,跳數索引主要做的事情就是在查詢時将非必要的資料過濾掉,隻查詢有用的資料。
介紹
跳數索引隻能在MergeTree引擎上使用,跳數索引中主要有四個參數:
- 索引名稱。索引名用于在每個分區中建立索引檔案。
- 索引的表達式。索引表達式用于計算存儲在索引中的值集。它可以是列、簡單操作符、函數的子集的組合。
- 類型。索引的類型。
- GRANULARITY。每個索引塊由顆粒(granule)組成。例如,如果主表索引粒度為8192行,GRANULARITY為4,則每個索引“塊”将為32768行。
跳數索引可以在建立表時添加:
sql複制代碼create table ck_test.test_skip_index
(
id UInt32,
org_id String,
user_id Int32,
name String,
l_date Date,
index idx_org_id org_id TYPE set(100) GRANULARITY 2
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(l_date)
PRIMARY KEY(id)
ORDER BY id;
也可以在建完表之後添加:
sql複制代碼ALTER TABLE ck_test.test_skip_index ADD INDEX idx_user_id user_id TYPE set(100) GRANULARITY 2;
跳數索引隻應用于新插入的資料,是以僅僅添加索引不會影響已經有的資料,要使已經有的資料也生效,需要重新執行下面的指令:
sql複制代碼ALTER TABLE ck_test.test_skip_index MATERIALIZE INDEX idx_user_id;
跳數索引中,不僅可以為某個列常見索引,也能為某個表達式建立索引
sql複制代碼ALTER TABLE ck_test.test_skip_index ADD INDEX idx_calculate (id*user_id) TYPE minmax GRANULARITY 2;
這一類索引可以提高特定查詢的性能,就比如剛好要對 id*user_id 作為條件進行查詢:
sql複制代碼select * from ck_test.test_skip_index where id*user_id=10;
索引類型
minmax
Minmax 是最簡單的一種。它存儲特定列(或表達式)的最小值和最大值,在查詢執行過程中,ClickHouse 可以在不掃描列的情況下快速檢查列值是否超出範圍,并跳過不滿足最大最小值的顆粒塊。當列的值随排序順序緩慢變化時,它的效果最好。
set
這種輕量級索引類型接受單個參數max_size,這種索引會将指定顆粒中的所有不同值存儲起來,如果不同值數量超過了max_size,該索引就不生效。
ClickHouse 在使用 where 條件查詢時,如果遇到了 set 類型的跳數索引,則會檢查 where 條件中的值是否在 set 集合中,如果不在就跳過這些顆粒。
set 類型的索引很适合那種有大量重複值的列,比如枚舉列(省市等)。
布隆過濾器
很多人剛開始聽說布隆過濾器應該是在 redis 中,一個資料如果在布隆過濾器中傳回不存在,那麼這個數一定不存在;如果一個數在布隆過濾器中傳回存在,那麼有一定的可能這個資料不存在。布隆過濾器可以很快地過濾掉那些一定不存在的資料。ClickHouse提供了三種布隆過濾器過濾方法。
bloom_filter
sql複制代碼ALTER TABLE ck_test.test_skip_index ADD INDEX idx_user_bf user_id TYPE bloom_filter(0.25) GRANULARITY 2;
基本的bloom_filter接受一個可選參數,該參數表示在0到1之間允許的“假陽性”率(如果未指定,則使用.025)。
tokenbf_v1
sql複制代碼ALTER TABLE ck_test.test_skip_index ADD INDEX idx_name_token_bf name TYPE tokenbf_v1(256, 2, 0) GRANULARITY 2;
相比基本的 bloom_filter 更加專業,需要三個參數,用來優化布隆過濾器
- size_of_bloom_filter_in_bytes – 布隆過濾器大小,位元組為機關。(因為壓縮得好,可以指定比較大的值,如 256 或 512)。
- number_of_hash_functions – 布隆過濾器中使用的哈希函數的個數。
- random_seed – 哈希函數的随機種子。
tokenbf_v1 主要用于字元串的過濾,比如:This is a candidate for a "full text" search将被分割為This | is | a | candidate | for | full | text | search 存儲,是以更适合 LIKE、EQUALS、in 等操作。
ngrambf_v1
sql複制代碼ALTER TABLE ck_test.test_skip_index ADD INDEX idx_name_ngram_bf name TYPE ngrambf_v1(4, 256, 2, 0) GRANULARITY 2;
該索引的功能與tokenbf_v1相同。在Bloom filter設定之前需要一個額外的參數,即要索引的ngram的大小,一個ngram是長度為n的任何字元串。
A short string會被分割為A sho, shor, hort, ort s, or st, r str, stri, trin, ring,這個索引對于文本搜尋也很有用。
資料是怎麼被跳過的?
跳數索引的核心是跳過那些一定不會被命中的資料,進而隻在少量的顆粒中進行查詢,提升查詢速度。
首先增加跳數索引後,會增加兩個實體檔案
skp_idx_{index_name}.idx:具體的索引檔案。
skp_idx_{index_name}.mrk2:存儲顆粒資訊。
借用官網的一張圖:
在上圖中,跳數索引設定 GRANULARITY 為 2,想要查詢 my_value 等于 125 的資料。因為第一個跳數索引塊的兩個顆粒中包含了 125 這個值,是以這個索引塊沒有被跳過。第二個跳數索引塊中的顆粒沒有包含 125 這個值,是以這個索引塊就被跳過了。
針對跳數索引的配置
use_skip_indexes
use_skip_indexes 可以設定為 0 或者 1,預設是 1,如果想要在某一次查詢中不使用跳數索引,則可以在查詢時将該參數設定為 0。
sql複制代碼SELECT * FROM ck_test.test_skip_index SETTINGS use_skip_indexes=0;
force_data_skipping_indices
如果将此設定與一個或多個索引名一起使用,則對于任何沒有使用所列索引的查詢将傳回一個異常,force_data_skipping_indices 後面的索引以英文逗号分隔
sql複制代碼SELECT * FROM ck_test.test_skip_index where name = '123' SETTINGS force_data_skipping_indices = 'idx_name_token_bf';
上面的這段SQL因為走了跳數索引是以不會抛出異常。
sql複制代碼SELECT * FROM ck_test.test_skip_index SETTINGS force_data_skipping_indices = 'idx_name_token_bf';
這段 SQL 沒有配 Where 條件,一定不會走跳數索引,就會抛出一個 INDEX_NOT_USED 異常: