搞大數據開發的都知道,想要在海量數據里快速查數據,就像在星圖里找一顆特定的星星,賊費勁。不過別慌,數據庫索引就是咱們的 “定位神器”,能讓查詢效率直接起飛!就拿 Apache Doris 這個超火的分析型數據庫來說,它支持好幾種索引,每種都有自己的 “獨門絕技”,能在不同查詢場景下大顯身手。今天就帶大家好好研究下 Apache Doris 的索引,看看它到底是怎么做到這么牛的!
一、索引的分類與原理
(一)點查索引:精準狙擊數據點
前綴索引:排序鍵上的 “捷徑”
Apache Doris 的數據存儲采用類似 SSTable 的有序結構,按照指定列排序存儲。在建表時,如 Aggregate、Unique 和 Duplicate 三種數據模型,會依據各自建表語句中的 Aggregate Key、Unique Key 和 Duplicate Key 指定列進行排序。這些排序鍵就像是書架上排列整齊的書籍類別標簽,而前綴索引則是在這些排序鍵基礎上建立的稀疏索引。
想象一下,每 1024 行數據組成一個邏輯數據塊,就像一個書架分區。每個分區在前綴索引表中有一個索引項,這個索引項就像是分區的 “小目錄”,其內容為該分區中第一行數據排序列組成的前綴,當查詢涉及這些排序列時,系統可以通過這個小巧的 “目錄” 快速定位到相關的數據塊,就如同通過書架分區目錄快速找到所需書籍類別,大大減少了搜索范圍,從而加速查詢。
注意??Doris的前綴索引長度不超過 36 字節。
例如,當表的排序列為 user_id(8 Bytes)、age(4 Bytes)、message(VARCHAR (100))等,前綴索引可能為 user_id + age + message 的前 20 字節(若總長度未超 36 字節)。當查詢條件為SELECT * FROM table WHERE user_id = 1829239 and age = 20;
時,前綴索引能夠快速定位到包含符合條件數據的邏輯數據塊,查詢效率遠高于SELECT * FROM table WHERE age = 20;
,因為后者無法有效利用前綴索引。
倒排索引:信息檢索的 “關鍵詞定位器”
從 2.0.0 版本起,Doris 引入了倒排索引這一強大工具,它在信息檢索領域有著舉足輕重的地位。在 Doris 的世界里,表的一行如同一份文檔,一列則是文檔中的一個字段。倒排索引就像是一個高效的 “關鍵詞定位器”,將文本分解成一個個詞,構建詞到文檔編號(即表中的行)的索引。
例如,對于一個包含用戶評論的表,對評論列創建倒排索引后,當我們要查詢包含特定關鍵詞(如 “OLAP”)的評論時,倒排索引可以快速定位到包含該關鍵詞的行。它不僅能加速字符串類型的全文檢索,支持多種關鍵詞匹配方式,如同時匹配多個關鍵字(MATCH_ALL)、匹配任意一個關鍵字(MATCH_ANY)、短語查詢(MATCH_PHRASE)等,還能加速普通等值、范圍查詢,替代了之前的 BITMAP 索引功能。在存儲上,倒排索引使用獨立文件,與數據文件一一對應但物理分離,這使得創建和刪除索引無需重寫數據文件,大大降低了處理開銷。
注意??,存在精度問題的浮點數類型(FLOAT 和 DOUBLE)以及部分復雜數據類型(如 MAP、STRUCT 等部分類型)暫不支持倒排索引。
(二)跳數索引:智能跳過 “無關數據塊”
ZoneMap 索引:數據塊的 “統計偵探”
ZoneMap 索引如同一位默默工作的 “統計偵探”,自動維護每一列的統計信息。對于每一個數據文件(Segment)和數據塊(Page),它都會記錄下最大值、最小值以及是否有 NULL 值。當進行等值查詢、范圍查詢或 IS NULL 查詢時,它可以根據這些統計信息迅速判斷該數據文件或數據塊是否可能包含滿足條件的數據。如果判斷不包含,就像偵探排除一個無關線索一樣,直接跳過該文件或數據塊不讀取,從而減少 I/O 操作,加速查詢。
例如,在一個包含用戶年齡的表中,當查詢年齡在某個范圍內的數據時,ZoneMap 索引可以通過數據塊的年齡最大值和最小值,快速排除那些明顯不滿足條件的數據塊,提高查詢效率。
BloomFilter 索引:基于概率的 “快速篩子”
BloomFilter 索引是基于 BloomFilter 算法的一種跳數索引,它就像是一個高效的 “快速篩子”。BloomFilter 是一種空間效率高的概率型數據結構,由一個超長的二進制位數組和一系列哈希函數組成。在 Doris 中,BloomFilter 索引以數據塊(page)為單位構建。寫入數據時,數據塊中的每個值經過哈希存入對應 BloomFilter;查詢時,根據等值條件的值判斷 BloomFilter 是否包含該值,若不包含則跳過對應數據塊。
例如,在一個包含大量用戶 ID 的表中,對用戶 ID 列創建 BloomFilter 索引后,當查詢特定用戶 ID 時,如果 BloomFilter 判斷該用戶 ID 不在某個數據塊對應的 BloomFilter 中,就可以直接跳過該數據塊,無需讀取,大大減少了 I/O。
注意??:它只對 IN 和 = 的等值查詢有效,且不支持 Tinyint、Float、Double 類型列,對低基數字段加速效果有限。
NGram BloomFilter 索引:文本 LIKE 查詢的 “助力器”
NGram BloomFilter 索引專門為文本 LIKE 查詢而生,是文本查詢的 “助力器”。它與 BloomFilter 索引類似,但存入 BloomFilter 的不是原始文本值,而是對文本進行 NGram 分詞后的每個詞。對于 LIKE 查詢,將 LIKE 的 pattern 也進行 NGram 分詞,判斷每個詞是否在 BloomFilter 中,若某個詞不在,則對應的數據塊不滿足 LIKE 條件,可跳過該數據塊。
例如,在一個存儲產品描述的表中,對描述列創建 NGram BloomFilter 索引后,當查詢包含特定短語(如 “super awesome”)的產品描述時,它可以快速篩選出可能包含該短語的數據塊,加速查詢。但它只支持字符串列,且要求 LIKE pattern 中的連續字符個數大于等于索引定義的 NGram 中的 N。
二、索引特點詳細對比
不同類型的索引各有千秋,也存在一定局限,讓我們通過表格直觀對比一下:
類型 | 索引 | 優點 | 局限 |
---|---|---|---|
點查索引 | 前綴索引 | 內置索引,性能最好 | 一個表只有一組前綴索引 |
點查索引 | 倒排索引 | 支持分詞和關鍵詞匹配,任意列可建索引,多條件組合,持續增加函數加速 | 索引存儲空間較大,與原始數據相當 |
跳數索引 | ZoneMap 索引 | 內置索引,索引存儲空間小 | 支持的查詢類型少,只支持等于、范圍 |
跳數索引 | BloomFilter 索引 | 比 ZoneMap 更精細,索引空間中等 | 支持的查詢類型少,只支持等于 |
跳數索引 | NGram BloomFilter 索引 | 支持 LIKE 加速,索引空間中等 | 支持的查詢類型少,只支持 LIKE 加速 |
三、索引加速的運算符和函數列表
了解索引對不同運算符和函數的支持,有助于我們在查詢中更好地利用索引加速:
運算符 / 函數 | 前綴索引 | 倒排索引 | ZoneMap 索引 | BloomFilter 索引 | NGram BloomFilter 索引 |
---|---|---|---|---|---|
= | YES | YES | YES | YES | NO |
!= | YES | YES | NO | NO | NO |
IN | YES | YES | YES | YES | NO |
NOT IN | YES | YES | NO | NO | NO |
>, >=, <, <=, BETWEEN | YES | YES | YES | NO | NO |
IS NULL | YES | YES | YES | NO | NO |
IS NOT NULL | YES | YES | NO | NO | NO |
LIKE | NO | NO | NO | NO | YES |
MATCH, MATCH_* | NO | YES | NO | NO | NO |
array_contains | NO | YES | NO | NO | NO |
array_overlaps | NO | YES | NO | NO | NO |
is_ip_address_in_range | NO | YES | NO | NO | NO |
四、索引使用指南
(一)前綴索引選擇建議
選擇最頻繁過濾字段:因為一個表只有一組前綴索引,所以要將查詢中最常用于 WHERE 過濾條件的字段作為 Key。例如,在一個用戶行為分析表中,如果經常根據用戶 ID 進行查詢,那么將用戶 ID 作為前綴索引的 Key 列是明智之舉。
字段順序很關鍵:越常用的字段越放在前面,因為前綴索引只對 WHERE 條件中字段在 Key 的前綴中才有效。比如,查詢條件經常是WHERE user_id = 123 AND age = 25
,那么建表時將 user_id 放在前面作為排序列,能更好地利用前綴索引加速查詢。
(二)其他索引選擇建議
非 Key 字段過濾:對非 Key 字段如有過濾加速需求,首選建倒排索引,因其適用面廣,可多條件組合。例如,在一個包含用戶評論和評分的表中,若需要根據評論內容和評分范圍同時進行查詢過濾,倒排索引可以很好地滿足需求。
字符串 LIKE 匹配:如果有字符串 LIKE 匹配需求,可再加一個 NGram BloomFilter 索引。比如在產品描述搜索場景中,使用 NGram BloomFilter 索引能有效加速 LIKE 查詢。
索引存儲空間敏感:當對索引存儲空間很敏感時,可將倒排索引換成 BloomFilter 索引。例如,在一個存儲海量低基數用戶屬性數據的表中,BloomFilter 索引在滿足等值查詢加速需求的同時,能減少存儲空間占用。
(三)性能優化與分析
如果性能不及預期,可通過 QueryProfile 分析索引過濾掉的數據量和消耗的時間,具體參考各個索引的詳細文檔。例如,通過查看 RowsKeyRangeFiltered(前綴索引過濾掉的行數)、RowsInvertedIndexFiltered(倒排索引過濾掉的行數)等指標,評估索引的過濾效果,進而優化索引設計。
五、索引的管理與使用
(一)前綴索引
管理:前綴索引無需專門語法定義,建表時自動取表的 Key 的前 36 字節作為前綴索引。
使用:用于加速 WHERE 條件中的等值和范圍查詢,能加速時自動生效,無特殊語法。例如,SELECT * FROM table WHERE user_id = 123 AND age > 20;
這樣的查詢,若 user_id 和 age 是排序列,前綴索引可自動發揮作用。
(二)倒排索引
管理
建表時定義:在建表語句中,在 COLUMN 定義之后進行索引定義,如CREATE TABLE table_name (column_name1 TYPE1, column_name2 TYPE2, INDEX idx_name1(column_name1) USING INVERTED [PROPERTIES(...)] [COMMENT 'your comment']);
,需指定索引列名、索引類型(USING INVERTED),還可設置分詞器等額外屬性。
已有表增加:支持CREATE INDEX
和ALTER TABLE ADD INDEX
兩種語法,新增索引定義后,新寫入數據會生成倒排索引,存量數據需使用BUILD INDEX
觸發構建。例如,CREATE INDEX idx_name ON table_name(column_name) USING INVERTED;
和BUILD INDEX index_name ON table_name;
。
已有表刪除:使用DROP INDEX idx_name ON table_name;
或ALTER TABLE table_name DROP INDEX idx_name;
刪除倒排索引。
使用
全文檢索關鍵詞匹配:通過MATCH_ANY
、MATCH_ALL
等完成,如SELECT * FROM table_name WHERE column_name MATCH_ANY 'keyword1 ...';
。
全文檢索短語匹配:通過MATCH_PHRASE
完成,如SELECT * FROM table_name WHERE content MATCH_PHRASE 'keyword1 keyword2';
,需注意設置support_phrase
屬性。
普通等值、范圍、IN、NOT IN 查詢:正常 SQL 語句即可,如SELECT * FROM table_name WHERE id = 123;
。可通過 Query Profile 中的 RowsInvertedIndexFiltered、InvertedIndexFilterTime 等指標分析倒排索引的加速效果。
(三)BloomFilter 索引
管理
建表時創建:通過表的 PROPERTIES “bloom_filter_columns” 指定哪些字段建 BloomFilter 索引,如PROPERTIES ("bloom_filter_columns" = "column_name1,column_name2");
。
已有表增加、刪除:通過 ALTER TABLE 修改表的 bloom_filter_columns 屬性完成,如ALTER TABLE table_name SET ("bloom_filter_columns" = "column_name1,column_name2,column_name3");
增加索引,ALTER TABLE table_name SET ("bloom_filter_columns" = "column_name2,column_name3");
刪除索引。
使用:用于加速 WHERE 條件中的等值查詢,自動生效,無特殊語法。可通過 Query Profile 中的 RowsBloomFilterFiltered、BlockConditionsFilteredBloomFilterTime 等指標分析加速效果。
(四)NGram BloomFilter 索引
管理
創建:在建表語句中 COLUMN 定義之后定義索引,如INDEX
idx_column_name (
column_name) USING NGRAM_BF PROPERTIES("gram_size"="3", "bf_size"="1024") COMMENT 'username ngram_bf index'
,需指定索引列名、索引類型(USING NGRAM_BF)及分詞相關屬性。
查看:使用SHOW CREATE TABLE table_name;
或SHOW INDEX FROM idx_name;
查看索引。
刪除:使用ALTER TABLE table_ngrambf DROP INDEX idx_ngrambf;
刪除索引。
修改:使用CREATE INDEX
或ALTER TABLE ADD INDEX
語法修改索引定義。
使用:用于加速 LIKE 查詢,如SELECT count() FROM table1 WHERE message LIKE '%error%';
。可通過 Query Profile 中的 RowsBloomFilterFiltered、BlockConditionsFilteredBloomFilterTime 等指標分析加速效果。
六、總結
總之,Apache Doris 索引體系豐富強大,多種索引各有優勢。前綴索引依排序結構定位數據,倒排索引助力全文檢索,ZoneMap 索引借統計信息跳過無關數據塊,BloomFilter 索引和 NGram BloomFilter 索引分別加速等值和文本 LIKE 查詢。只要深入了解其原理、場景及使用方法,就能按需精準選擇,讓 Doris 在數據查詢中性能全開,無論是海量數據點查還是復雜文本檢索,都能輕松拿捏,實在搞不定,看看profile,索引生效了沒,別做了和沒做一樣,就尬住了 。