Phoenix二級索引(Secondary Indexing)的使用

摘要
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'
(雖然USERID是索引字段,但KEYWORD不是索引字段,因此不會使用到索引)
 
查詢語句2.
SELECT KEYWORD FROM CSVTABLES WHERE USERID='9bb8b2af925864bb275b840c578df3c3'
(同理,KEYWORD不是索引字段)
 
使用如下三種方式,執行查詢語句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,因爲是緩存在內存中,因此其值越大,其須要的內存越多
相關文章
相關標籤/搜索