Phoenix二級索引(Secondary Indexing)的使用
2017年02月22日 08:35:04 xuguokun1986 閱讀數:499
摘要
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>
-
<property>
-
<name>hbase.region.server.rpc.scheduler.factory.class</name>
-
<value>org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory</value>
-
</property>
-
<property>
-
<name>hbase.rpc.controllerfactory.class</name>
-
<value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory</value>
-
</property>
在用使用全域性索引之前需要在每個HMaster上的hbase-site.xml新增如下屬性:
-
<property>
-
<name>hbase.region.server.rpc.scheduler.factory.class</name>
-
<value>org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory</value>
-
<description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>
-
</property>
-
<property>
-
<name>hbase.rpc.controllerfactory.class</name>
-
<value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory</value>
-
</property>
-
<property>
-
<name>hbase.region.server.rpc.scheduler.factory.class</name>
-
<value>org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory</value> </property>
-
<property> <name>hbase.rpc.controllerfactory.class</name>
-
<value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory</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,由於是快取在記憶體中,所以其值越大,其需要的記憶體越多