摘要
HBase只提供了一個基於字典排序的主鍵索引,在查詢中你只能通過行鍵查詢或掃描全表來獲取數據,使用Phoenix提供的二級索引,可以避免在查詢數據時全表掃描,提高查過性能,提升查詢效率
測試環境:
數據約370萬
數據格式:(數據來自
搜狗實驗室)

三節點集群(一主兩從,hadoop和HBase屬同一集群)
目錄
- Covered Indexes(覆蓋索引)
- Functional indexes(函數索引)
- Global indexes(全局索引)
- Local indexes(本地索引)
索引類型
Covered Indexes(覆蓋索引)
覆蓋索引:只需要通過索引就能返回所要查詢的數據,所以索引的列必須包含所需查詢的列(SELECT的列和WHRER的列)
不帶索引的查詢:
查詢USERID= 9bb8b2af925864bb275b840c578df3c3的KEYWORD和URL
EXPLAIN(語句的執行邏輯及計划):


(由圖看知先進行了全表掃描再通過過濾器來篩選出目標數據,顯示這種查詢方式效率是很低的)
查詢時間:(平均在38s~41s)


帶索引:
(創建基於USERID的覆蓋索引並綁定KEYWORD列上的數據)
CREATE INDEX COVERINDEX ON CSVTANLES(USERID) INCLUDE(KEYWORD)
當你要通過UERID來查詢KEYWORD時就直接可以從索引上取回數據而無需先得到索引再去數據表中查詢數據
查詢語句:
SECECT KEYWORD FROM CSVTABLES WHERE USERID='9bb8b2af925864bb275b840c578df3c3'
EXPLAIN:


(使用了COVERINDEX索引使用SCAN在索引區間內查詢)
查詢用時(平均在49ms~70ms):


注意:SELECT所帶的字段必須包含在覆蓋索引內
Functional indexes(函數索引)
從Phoeinx4.3以上就支持函數索引,其索引不局限於列,可以合適任意的表達式來創建索引,當在查詢時用到了這些表達式時就直接返回表達式結果
例2:使用UPPER函數創建函數索引使查詢出的USERID和URL里字母都是大寫的
創建函數索引
CREATE INDEX UPPERINDEX ON CSVTABLES (UPPER(USERID || ' ' || URL))
查詢:


Global indexes(全局索引)
全局索引適用於多讀少寫的場景,在寫操作上會給性能帶來極大的開銷,因為所有的更新和寫操作(DELETE,UPSERT VALUES和UPSERT SELECT)都會引起索引的更新,在讀數據時,Phoenix將通過索引表來達到快速查詢的目的。
在用使用全局索引之前需要在每個RegionServer上的hbase-site.xml添加如下屬性:
<property> <name>hbase.regionserver.wal.codec</name> <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value> </property>
在USERID字段上創建索引
CREATE INDEX USERIDINDEX ON CSVTABLES(USERID);
以下查詢會用到索引
SELECT USERID FROM CSVTABLES WHERE USERID='9bb8b2af925864bb275b840c578df3c3';


SELECT USERID,ROWKEY CSVTABLES WHERE USERID='9bb8b2af925864bb275b840c578df3c3';


以下查詢不會用到索引
查詢語句1.
SELECT USERID,KEYWORD FROM CSVTABLES WHERE USERID='9bb8b2af925864bb275b840c578df3c3'
查詢語句2.
(同理,KEYWORD不是索引字段)
SELECT KEYWORD FROM CSVTABLES WHERE USERID='9bb8b2af925864bb275b840c578df3c3'
使用以下三種方式,執行查詢語句2時也將用到索引.
1.創建包含字段KEYWORD的覆蓋索引
CREATE INDEX MYINDEX ON CSVTABLE(USERID) INCLUDE(KEYWORD);
2.強制使用索引
SELECT /*+ INDEX(CSVTABLES,MYINDEX) */ KEYWORD FROM CSVTABLES WHERE USERID='9bb8b2af925864bb275b840c578df3c3';
如果KEYWORD是索引字段,那么就會直接從索引表中查詢
如果KEYWORD不是索引字段,那么將會進行全表掃描,所以當用戶明確知道表中數據較少且符合檢索條件時才適用,此時的性能才是最佳的。
3.使用本地索引
CREATE LOCAL INDEX MYINDEX ON CSVTABLES(KEYWORD);
Local indexes(本地索引)
本地索引適用於寫多讀少,空間有限的場景,和全局索引一樣,Phoneix在查詢時會自動選擇是否使用本地索引,使用本地索引,為避免進行寫操作所帶來的網絡開銷,索引數據和表數據都存放在相同的服務器中,當查詢的字段不完全是索引字段時本地索引也會被使用,與全局索引不同的是,所有的本地索引都單獨存儲在同一張共享表中,由於無法預先確定region的位置,所以在讀取數據時會檢查每個region上的數據因而帶來一定性能開銷。
在使用本地索引需要在Master的hbase-site.xml添加以下屬性
<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>
Phoeinx4.3以上為支持在數據region合並時本地索引region也能進行合並需要在每個region servers中添加以下屬性
<property> <name>hbase.coprocessor.regionserver.classes</name> <value>org.apache.hadoop.hbase.regionserver.LocalIndexMerger</value> </property>
創建本地索引
CREATE LOCAL INDEX MYINDEX ON CSVTABLES(USERID);
查詢
CREATE LOCAL INDEX MYINDEX ON CSVTABLES(USERID);


整個查詢只花了0.19s
刪除索引
CREATE LOCAL INDEX MYINDEX ON CSVTABLES(KEYWORD);
如果表中的一個索引列被刪除,則索引也將被自動刪除,如果刪除的是
覆蓋索引上的列,則此列將從覆蓋索引中被自動刪除。
索引的優化
以下屬性都必須在各節點上的hbase-site.xml中設置為true才能起效,
1.index.builder.threads.max:(默認值:10)
根據主表的更新來確定更新索引表的線程數
2.index.builder.threads.keepalivetime:(默認值:60)
builder線程池中線程的存活時間
3.index.write.threads.max:(默認值:10)
更新索引表時所能使用的線程數(即同時能更新多少張索引表),其數量最好與索引表的數量一致
4.index.write.threads.keepalivetime(默認值:60)
更新索引表的線程所能存活的時間
5.hbase.htable.threads.max(默認值:2147483647)
每張索引表所能使用的線程(即在一張索引表中同時可以有多少線程對其進行寫入更新),增加此值可以提高更新索引的並發量
6.hbase.htable.threads.keepalivetime(默認值:60)
索引表上更新索引的線程的存活時間
7.index.tablefactoy.cache.size(默認值:10)
允許緩存的索引表的數量
增加此值,可以在更新索引表時不用每次都去重復的創建htable,由於是緩存在內存中,所以其值越大,其需要的內存越多