Phoenix 二級索引
Phoenix 二級索引
HBase中只能通過行鍵(row key)進行索引查詢資料,否則都可能會掃描全表。
Phoenix二級索引可以將索引列或表示式生成備用的行鍵。
Phoenix官網:http://phoenix.apache.org/secondary_indexing.html
索引型別
覆蓋索引(Covered Indexes)
覆蓋索引是將資料打包進索引行中,查詢時無需查詢原表。
SQL示例
CREATE INDEX my_index ON my_table (v1,v2) INCLUDE(v3)
執行計劃
EXPLAIN SELECT v3 FROM my_table WHERE v1 = '' AND v2 = '';
CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN FULL SCAN OVER MY_INDEX
SERVER FILTER BY ( AND )
這裡只查詢了索引表,因為v3列作為v1、v2的附加資料已經包含在索引中。
HBase索引表資料
hbase(main):001:0> scan 'MY_INDEX'
ROW COLUMN+CELL
v1\x00v2 column=0:\x00\x00\x00\x00, timestamp=1604912241250, value=x
v1\x00v2 column=0:\x80\x0B, timestamp=1604912241250, value=v3
可以看出,v3列作為附加列已經寫入了索引表中。
函式索引(Functional Indexes)(僅支援4.3及以上版本)
Phoenix不僅可以將列作為二級索引,而且可以使用函式表示式建立二級索引。
SQL示例
-- 用函式表示式作為索引列建立索引
CREATE INDEX UPPER_NAME_IDX ON EMP (UPPER(FIRST_NAME||' '||LAST_NAME))
執行計劃
EXPLAIN SELECT EMP_ID FROM EMP WHERE UPPER(FIRST_NAME||' '||LAST_NAME)='JOHN DOE'
CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN RANGE SCAN OVER UPPER_NAME_IDX ['JOHN DOE']
SERVER FILTER BY FIRST KEY ONLY
這裡將函式整體視作一列作為索引,查詢時可以直接查詢索引表。
HBase中索引表資料
hbase(main):006:0> scan 'UPPER_NAME_IDX'
ROW COLUMN+CELL
KOBE BYRANT\x001 column=0:\x00\x00\x00\x00, timestamp=1604912053676, value=\x00\x00\x00\x00
可以看出,函式索引就是將函式的結果作為row key寫入了HBase中的索引表。
全域性索引和本地索引
全域性索引(Global Indexes)
全域性索引會擷取更新表(DELETE和UPSERT)操作,然後對HBase中的索引表進行更新;查詢時,選擇要使用的索引表進行查詢。特點是查詢快,寫入慢。
預設情況下,使用索引之外的列作為查詢列(SELECT後的列)或查詢條件(WHERE中的列),將不會使用該索引。
SQL示例
-- 預設情況下使用的就是全域性索引
CREATE INDEX my_index ON my_table (v2, v3);
HBase中索引表資料
hbase(main):004:0> scan 'MY_INDEX'
ROW COLUMN+CELL
v2\x00v3\x00v1 column=0:\x00\x00\x00\x00, timestamp=1604911907530, value=\x00\x00\x00\x00
- 全域性索引就是將所有索引列和原資料row key拼接在一起作為新的row key,寫入HBase中的索引表;
- 對於全域性覆蓋索引,則會新增一列存放INCLUDE中的列,因此寫入比較慢,但是查詢可以直接從索引表中獲取資料,因此查詢快。
本地索引(Local Indexes)
本地索引將索引資料存放在和表資料相同的主機上,從而防止寫入期間的網路開銷。特點是寫入快,查詢慢。
即使查詢列未完全涵蓋,也可以使用本地索引。
SQL示例
建立表
-- 為了方便說明,使用加鹽分割槽分為3個region
CREATE TABLE my_table (v1 VARCHAR NOT NULL PRIMARY KEY, v2 VARCHAR, v3 VARCHAR) SALT_BUCKETS = 3;
建立索引
-- 使用LOCAL關鍵字建立本地索引
CREATE LOCAL INDEX my_index ON my_table (v1, v2);
HBase索引表資料
hbase(main):011:0> scan 'MY_TABLE'
ROW COLUMN+CELL
\x00\x00\x00v1_1\x00v2_1 column=L#0:\x00\x00\x00\x00, timestamp=1604913262299, value=\x00\x00\x00\x00
\x00v1_1 column=0:\x00\x00\x00\x00, timestamp=1604913262299, value=x
\x00v1_1 column=0:\x80\x0B, timestamp=1604913262299, value=v2_1
\x00v1_1 column=0:\x80\x0C, timestamp=1604913262299, value=v3_1
\x01\x00\x00v1_2\x00v2_2 column=L#0:\x00\x00\x00\x00, timestamp=1604913265267, value=\x00\x00\x00\x00
\x01v1_2 column=0:\x00\x00\x00\x00, timestamp=1604913265267, value=x
\x01v1_2 column=0:\x80\x0B, timestamp=1604913265267, value=v2_2
\x01v1_2 column=0:\x80\x0C, timestamp=1604913265267, value=v3_2
\x02\x00\x00v1_3\x00v2_3 column=L#0:\x00\x00\x00\x00, timestamp=1604913268957, value=\x00\x00\x00\x00
\x02v1_3 column=0:\x00\x00\x00\x00, timestamp=1604913268957, value=x
\x02v1_3 column=0:\x80\x0B, timestamp=1604913268957, value=v2_3
\x02v1_3 column=0:\x80\x0C, timestamp=1604913268957, value=v3_3
-
在版本4.8.0之後,本地索引不會單獨在HBase中建立索引表,而是直接將索引資料寫入到原表中;
-
本地索引行的row key為:
\x00\x00v1\x00v2
,含義為:{原資料所在region的start key}\x00{第一個索引列}\x00{第二個索引列}...
。以原資料所在region的start key開頭是為了將索引資料與原資料分在同一個分割槽。這是為了寫入索引時,將索引直接寫入到與原資料相同的分割槽,減少網路開銷,因此寫入快; -
查詢時,首先會在不同region中定位二級索引獲取原資料的row key,然後從本地region中獲取原資料。但是定位二級索引時,必須檢查每個region的資料,因此讀取慢;
-
對於本地覆蓋索引,不會再單獨存入INCLUDE中的列,而是直接根據從二級索引中獲取的原資料row key從原表中查詢,因此相對全域性覆蓋索引寫入快,查詢慢。
構建索引引數
和建立表一樣,建立索引也可以使用一些引數,如下:
CREATE INDEX my_index ON my_table (v2 DESC, v1) INCLUDE (v3)
SALT_BUCKETS=10, DATA_BLOCK_ENCODING='NONE'
注意:
- 本地索引不能加鹽分割槽;
- 如果資料表使用了加鹽分割槽,全域性索引會自動以資料表相同的方式加鹽。
非同步構建索引
Phoenix在建立索引時,會同步將索引資料寫入索引表,但是表如果太大,則可能會耗時過長導致失敗。在Phoenix 4.5之後,支援非同步索引構建。
構建步驟
-
執行構建SQL,此時並未將資料真正寫入索引表,索引表狀態為BUILDING:
`CREATE INDEX async_index ON my_schema.my_table (v) ASYNC`
-
執行MapReduce,真正將資料寫入索引表,完成後索引表狀態為ACTIVE:
${HBASE_HOME}/bin/hbase org.apache.phoenix.mapreduce.index.IndexTool --schema MY_SCHEMA --data-table MY_TABLE --index-table ASYNC_IDX --output-path ASYNC_IDX_HFILES
批量構建
可以使用如下命令對所有狀態為BUILDING的索引進行填充:
${HBASE_HOME}/bin/hbase org.apache.phoenix.mapreduce.index.automation.PhoenixMRJobSubmitter
相關配置
配置項 | 配置說明 |
---|---|
phoenix.index.async.threshold | 允許建立同步索引的索引表大小閾值,單位為bytes,超出該閾值則不能同步建立索引。 |
強制使用索引
假如有一個表建表語句為:CREATE TABLE t1 (v1 VARCHAR NOT NULL PRIMARY KEY, v2 VARCHAR, v3 VARHCAR);
;
現在建立了索引:CREATE INDEX i1 ON t1 (v2)
;
如果此時使用該查詢,並不會使用索引i1:SELECT v2, v3 FROM t1 WHERE v2 = 'foo'
。
這種情況下,有三種方法可以強制其使用索引:
-
覆蓋索引:建立索引時,使用
CREATE INDEX i2 ON t1 (v2) INCLUDE (v3)
進行建立,將資料v3列寫入索引表中。 -
強制使用索引:查詢時候,使用
SELECT /*+ INDEX(t1 i1) */ v2, v3 FROM t1 WHERE v2 = 'foo'
強制該查詢使用索引i1,該查詢的流程為:- 查詢索引表i1,獲取全部v2值為“foo”的行的row key;
- 查詢資料表t1,獲取上一步row key的所有行。
如果表中v2值為“foo”的行比較少,那麼會提升查詢效率。但是如果比較多,效率可能還不如不使用索引,因為需要查詢兩個表。
-
本地索引:建立索引時,使用
CREATE LOCAL INDEX i3 ON t1 (v2)
進行建立,但是查詢效率會略有降低,詳情檢視[本地索引](#‘本地索引(Local Indexes)’)說明。
一致性保證
事務表
如果資料表為事務表,可以在表和索引之間提供最高階別的一致性保證。
缺點:
- 如果是不可變表,事務開銷很小,那麼使用事務表是比較適用的。但是如果是可變表,則需要接受事務和衝突檢測的開銷;
- 具有二級索引的事務表可能會降低寫入效能,因為只有索引表和資料表都可用時才能寫入資料。
不可變表
IMMUTABLE_ROWS=true
可以將表宣告為不可變表(只能追加不能修改),注意,宣告後該資料表依舊是可變的,只有該表的索引表是隻能追加不能修改。全域性不可變索引在客戶端維護,本地不可變索引表在服務端維護。
-- 建立不可變表
CREATE TABLE my_table (k VARCHAR PRIMARY KEY, v VARCHAR) IMMUTABLE_ROWS = true
-- 更新表為可變表
ALTER TABLE my_table SET IMMUTABLE_ROWS = false
注意:如果對資料表進行了修改(也就是使用UPSERT對某行進行了修改而不是追加),那麼索引表中會追加一行而不會對原索引進行修改,也就是說該索引表沒有完全進行同步。
一致性保證:如果不可變索引提交失敗了,由於更新操作是冪等的,所以索引表會一直重試直到追加成功。
可變表
對於非事務性的可變表,資料表更新某一行時:
- 協處理器攔截對HRegion的寫入操作;
- 將索引附加到資料表的WAL中,如果出現故障則返回給客戶端,並且不會保留資料且資料對客戶端不可見;
- 更新資料表和索引,索引更新是並行的,HBase會保證資料和索引表寫入操作的原子性。預設先寫資料表再寫索引表,如果禁用了WAL則相反。
資料寫入WAL前,如果出現故障則返回客戶端,且資料對客戶端不可見;
資料寫入WAL後,即使出現故障,資料表和索引表資料也對客戶端可見,故障情況如下:
- 如果服務端崩潰,則從WAL中進行恢復,並利用更新操作的冪等性確保成功更新索引;
- 如果服務端沒有崩潰,則將索引更新插入到各自的索引表中:
- 如果Phoenix的SYSTEM.CATALOG表無法訪問,則強制終止服務端(終止失敗則呼叫JVM的
System.exit()
進行終止),再重新從WAL中進行恢復,這樣可以確保索引處於已知無效狀態時不會繼續使用; - 如果插入索引表失敗,可以採用以下容錯機制保障資料一致性。
- 如果Phoenix的SYSTEM.CATALOG表無法訪問,則強制終止服務端(終止失敗則呼叫JVM的
容錯機制
禁止表寫入
禁止表寫入是可變索引一致性最高的策略。在發生故障時,Phoenix將記下時間戳,並且不允許對資料表的寫入操作,直到索引一致。配置項如下:
配置 | 說明 |
---|---|
phoenix.index.failure.block.write | 需設定為true,索引插入失敗時,禁止寫入操作 |
phoenix.index.failure.handling.rebuild | 需設定為true(預設值),索引插入失敗時,後臺自動重建可變索引 |
禁用可變索引
禁用可變索引是預設策略。發生故障時,將索引標記為禁用並在後臺進行重建,此時查詢不能使用該索引,直到重建完成。配置項如下:
配置 | 說明 |
---|---|
phoenix.index.failure.handling.rebuild | 需設定為true(預設值),索引插入失敗時,後臺自動重建可變索引 |
phoenix.index.failure.handling.rebuild.interval | 預設值為10000(10秒),服務端檢測是否需要重建索引的頻率 |
phoenix.index.failure.handling.rebuild.overlap.time | 預設值為1,重建時發生故障的時間戳返回的毫秒數 |
禁用可變索引並手動重建
禁用可變索引並手動重建是可變索引一致性最低的策略。發生故障時,將索引標記為禁用,需要手動進行重建才能使用該索引。配置項如下:
配置 | 說明 |
---|---|
phoenix.index.failure.handling.rebuild | 需設定為true(預設值),索引插入失敗時,後臺自動重建可變索引 |
批量匯入工具限制
- 使用BulkLoadTools(CSVBulkLoadTool和JSONBulkLoadTool)匯入資料不能正確更新索引;
- 如果使用BulkLoadTools匯入資料,必須在匯入完成後刪除並重新建立所有索引表;
- 可以使用psql.py工具代替BulkLoadTools,可以完成索引正確更新;
- 可以編寫MapReduce任務解析資料直接寫入Phoenix,可以完成索引正確更新。
相關配置
配置支援二級索引
在每個HBase節點上修改hbase-site.xml:
<!--Phoenix 4.12以上版本使用如下配置支援可變表二級索引-->
<property>
<name>hbase.regionserver.wal.codec</name>
<value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
</property>
升級Phoenix 4.8之前建立的索引
Phoenix升級到4.8及以上版本後,需要刪除hbase-site.xml中關於Phoenix 4.7之前的索引配置(如果有的話):
<property>
<name>hbase.master.loadbalancer.class</name>
<value>org.apache.phoenix.hbase.index.balancer.IndexLoadBalancer</value>
</property>
<property>
<name>hbase.coprocessor.master.classes</name>
<value>org.apache.phoenix.hbase.index.master.IndexMasterObserver</value>
</property>
<property>
<name>hbase.coprocessor.regionserver.classes</name>
<value>org.apache.hadoop.hbase.regionserver.LocalIndexMerger</value>
</property>
配置客戶端:
phoenix.client.localIndexUpgrade:預設為true,表示線上升級,false為離線升級。
離線升級命令:psql [zookeeper地址] -l
索引優化配置
配置項 | 預設值 | 說明 | 備註 |
---|---|---|---|
index.builder.threads.max | 10 | 構建索引更新的執行緒數 | 值越大,訪問HRegion效率越高,但是值太大HRegion會出現瓶頸。 |
index.builder.threads.keepalivetime | 60 | 構建索引更新執行緒過期時間(秒) | 在該值時間後,未使用的執行緒會立即釋放,但是會保留核心執行緒 |
index.writer.threads.max | 10 | 寫入索引表的執行緒數 | 在每個表的基礎上,應大致對應索引表的數量 |
index.writer.threads.keepalivetime | 60 | 寫入索引表執行緒過期時間(秒) | 在該值時間後,未使用的執行緒會立即釋放,但是會保留核心執行緒 |
hbase.htable.threads.max | 2147483647 | 寫入每個索引HTable的執行緒數 | 值越大則支援更多的併發索引更新,增大吞吐量 |
hbase.htable.threads.keepalivetime | 60 | 寫入每個索引HTable執行緒超時時間 | |
index.tablefactory.cache.size | 10 | 快取中索引HTable數量 | 快取HTable可以不用每次都建立HTable,但是會增大記憶體壓力 |
org.apache.phoenix.regionserver.index.priority.min | 1000 | 索引優先順序最低值 | |
org.apache.phoenix.regionserver.index.priority.max | 1050 | 索引優先順序最高值 | 索引優先順序並不代表索引會被更快地處理 |
org.apache.phoenix.regionserver.index.handler.count | 30 | 全域性索引的寫入請求執行緒數 |
索引工具
索引檢查工具(Phoenix 4.12以上版本)
Phoenix提供了IndexScrutinyTool工具驗證索引表對其資料表是否有效(一致),將找到所有無效行寫入檔案或輸出到表PHOENIX_INDEX_SCRUTINY中。
IndexScrutinyTool提供一些計數器:
- VALID_ROW_COUNT
- INVALID_ROW_COUNT
- BAD_COVERED_COL_VAL_COUNT
計數器和其他該任務的後設資料會寫入表PHOENIX_INDEX_SCRUTINY_METADATA中。
使用方法如下:
# HBase命令執行
hbase org.apache.phoenix.mapreduce.index.IndexScrutinyTool -dt my_table -it my_index -o
# Hadoop命令執行
HADOOP_CLASSPATH=$(hbase mapredcp) hadoop jar phoenix-<version>-server.jar org.apache.phoenix.mapreduce.index.IndexScrutinyTool -dt my_table -it my_index -o
引數說明:
引數 | 說明 |
---|---|
-dt,–data-table | 資料表表名(必填項) |
-it,–index-table | 索引表表名(必填項) |
-s,–schema | 資料庫名稱 |
-src,–source | 可選值為DATA_TABLE_SOURCE、INDEX_TABLE_SOURCE,或者兩個都選,預設為都選 |
-o,–output | 是否輸出無效行,預設關閉 |
-of,–output-format | 輸出到表還是檔案,預設為表 |
-om,–output-max | 每個mapper輸出的最大無效行數量,預設為1M |
-op,–output-path | 檔案輸出的HDFS路徑 |
-t,–time | 檢查時間,預設為當前時間-60秒 |
-b,–batch-size | 一次比較的行數 |
相關文章
- Phoenix二級索引索引
- pandas 設定二級索引索引
- 【Mysql】InnoDB 中的聚簇索引、二級索引、聯合索引MySql索引
- phoenix全域性索引和本地索引 概述,使用場景,區別等詳解索引
- AppBoxFuture: 二級索引及索引掃描查詢資料APP索引
- 使用高斯Redis實現二級索引Redis索引
- hbase構建二級索引解決方案索引
- Hbase的二級索引和RowKey的設計索引
- hbase與phoenix整合(使用phoenix操作hbase資料)
- MySQL 二 索引MySql索引
- phoenix安裝
- 索引與null(二):組合索引索引Null
- MySQL e二級索引上的一致性讀MySql索引
- MySQL8.0.27 新特性-提高二級索引的建立效率MySql索引
- MySQL索引(二):建索引的原則MySql索引
- oracle重建索引(二)Oracle索引
- DBeaver連線Phoenix
- CDH+HBase Indexer+Solr為HBase資料建立二級索引IndexSolr索引
- MySql如何使用索引(二)MySql索引
- 關於MySQL InnoDB表的二級索引是否加入主鍵的總結MySql索引
- 資料庫索引層級資料庫索引
- 高效能索引策略二索引
- 大資料技術 - Phoenix大資料
- CF1515F Phoenix and Earthquake
- phoenix API服務釋出API
- Innodb:insert 第一次進行樂觀插入邏輯(二級索引)索引
- GaussDB(for Cassandra)新特性發布:支援Lucene二級索引,讓複雜查詢更智慧索引
- 深入研究B樹索引(二)索引
- MySQL的索引優化分析(二)MySql索引優化
- postgreSQL 索引(二)型別介紹SQL索引型別
- 【TUNE_ORACLE】Oracle索引設計思想(四)三星級索引Oracle索引
- 【TUNE_ORACLE】Oracle索引設計思想(二)索引過濾列概述Oracle索引
- 高效能MySQL實戰(二):索引MySql索引
- [題解]CF1515I Phoenix and Diamonds
- 二級市盈率
- MySQL(二):快速理解MySQL資料庫索引MySql資料庫索引
- 使用phoenix踩的坑與設計思考
- CDH 5.14.2 Phoenix Install (離線版本安裝)