都來自官網(wǎng),請看官網(wǎng) http://phoenix.apache.org/secondary_indexing.html
下邊分析全局索引和本地索引
Global Indexing 全局索引
Global indexing targets read heavy,low write uses cases. With global indexes, all the performance penalties for indexes occur at write time. We intercept the data table updates on write (DELETE, UPSERT VALUES and UPSERT SELECT), build the index update and then sent any necessary updates to all interested index tables. At read time, Phoenix will select the index table to use that will produce the fastest query time and directly scan it just like any other HBase table. By default, unless hinted, an index will not be used for a query that references a column that isn’t part of the index.
Global indexing適用于多讀少寫的業(yè)務(wù)場景。使用Global indexing的話在寫數(shù)據(jù)的時(shí)候會(huì)消耗大量開銷,因?yàn)樗袑?shù)據(jù)表的更新操作(DELETE, UPSERT VALUES and UPSERT SELECT),會(huì)引起索引表的更新,而索引表是分布在不同的數(shù)據(jù)節(jié)點(diǎn)上的,跨節(jié)點(diǎn)的數(shù)據(jù)傳輸帶來了較大的性能消耗。在讀數(shù)據(jù)的時(shí)候Phoenix會(huì)選擇索引表來降低查詢消耗的時(shí)間。在默認(rèn)情況下如果想查詢的字段不是索引字段的話索引表不會(huì)被使用,也就是說不會(huì)帶來查詢速度的提升。
配置hbase-site.xml
使用Global Indexing的話需要配置hbase-site.xml,在HBase集群的每個(gè)regionserver節(jié)點(diǎn)的hbase-site.xml中加入如下配置并重啟HBase集群。
<property>
<name>hbase.regionserver.wal.codec</name>
<value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
</property>
如果是CDH版本,要通過該cloudera manager配置


測試索引
-- 注意phoenix最好全大寫字母,這里碼字方便,我全小寫了,請注意
-- 創(chuàng)建表
create table company(id varchar primary key, name varchar, address varchar);
--- 查看索引
!indexes company;
-- 創(chuàng)建索引
create index my_index on company(name);
--刪除索引表
drop index my_index on company
-- 查看表就會(huì)發(fā)現(xiàn)多了一張索引表
!tables
SELET * FROM MY_INDEX

-- 插入數(shù)據(jù)
upsert into company(id, name, address) values('001', 'dimensoft', 'nanjing');
-- 查詢數(shù)據(jù)
select name,address from company where name='dimensoft';

-- 查詢索引表MY_INDEX
SELECT * FROM MY_INDEX
或者
scan 'MY_INDEX'


高能預(yù)警
> select name,address from company where name='dimensoft';
這樣的查詢語句是不會(huì)用到索引表的
Global mutable index will not be used unless all of the columns referenced in the query are contained in the index.
name字段雖然是索引字段但是address字段并不是索引字段!也就是說需要查詢出來的字段必須都是索引字段如:
> select name from company where name='dimensoft';
如果希望使用索引表進(jìn)行查詢的話可以使用以下三種方式來解決這個(gè)問題:
- 強(qiáng)制使用索引表
在進(jìn)行查詢的時(shí)候通過sql語句強(qiáng)制使用索引查詢。
> SELECT /*+ INDEX(company my_index) */ name,address FROM company WHERE name = 'dimensoft';
This will cause each data row to be retrieved when the index is traversed to find the missing address column value. This hint should only be used if you know that the index has good selective (i.e. a small number of table rows have a value of ‘dimensoft’ in this example), as otherwise you’ll get better performance by the default behavior of doing a full table scan.
這樣的查詢語句會(huì)導(dǎo)致二次檢索數(shù)據(jù)表,第一次檢索是去索引表中查找符合name為dimensoft的數(shù)據(jù),這時(shí)候發(fā)現(xiàn)address字段并不在索引字段中,會(huì)去company表中第二次掃描,因此只有當(dāng)用戶明確知道符合檢索條件的數(shù)據(jù)較少的時(shí)候才適合使用,否則會(huì)造成全表掃描,對性能影響較大。
- 創(chuàng)建covered index
創(chuàng)建索引的時(shí)候指定一個(gè)covered字段,先刪除my_index索引
> drop index my_index on company;
創(chuàng)建covered index
> create index my_index on company(name) include(address);
This will cause the address column value to be copied into the index and kept in synch as it changes. This will obviously increase the size of the index.
使用這種方式創(chuàng)建的所有會(huì)導(dǎo)致address字段的值被拷貝到索引中,缺點(diǎn)就是會(huì)導(dǎo)致索引表大小有一定的增加。
查詢索引表my_index數(shù)據(jù)。
> select * from my_index;
這里的數(shù)據(jù)是自動(dòng)同步過來的,可以發(fā)現(xiàn)address字段的值也被存儲(chǔ)了。
從HBase的CLI中查看MY_INDEX表數(shù)據(jù)會(huì)發(fā)現(xiàn)比不使用include的時(shí)候多了一行數(shù)值,并且里面包含了address字段的值。
> scan 'MY_INDEX'
這個(gè)時(shí)候就再使用下面的查詢語句就會(huì)使用到索引來進(jìn)行查詢了。
> select name,address from company where name='dimensoft';
- 使用Local Indexing創(chuàng)建索引
與Global Indexing不同,當(dāng)使用Local Indexing的時(shí)候即使查詢的所有字段都不在索引字段中時(shí)也會(huì)用到索引進(jìn)行查詢(這是由Local Indexing自動(dòng)完成的)。這部分內(nèi)容會(huì)放到后一篇文章詳細(xì)介紹。
Local Indexing 本地索引
Local indexing targets write heavy, space constrained use cases. Just like with global indexes, Phoenix will automatically select whether or not to use a local index at query-time. With local indexes, index data and table data co-reside on same server preventing any network overhead during writes. Local indexes can be used even when the query isn’t fully covered (i.e. Phoenix automatically retrieve the columns not in the index through point gets against the data table). Unlike global indexes, all local indexes of a table are stored in a single, separate shared table.At read time when the local index is used, every region must be examined for the data as the exact region location of index data cannot be predetermined.Thus some overhead occurs at read-time.
Local indexing適用于寫操作頻繁的場景。與Global indexing一樣,Phoenix會(huì)自動(dòng)判定在進(jìn)行查詢的時(shí)候是否使用索引。使用Local indexing時(shí),索引數(shù)據(jù)和數(shù)據(jù)表的數(shù)據(jù)是存放在相同的服務(wù)器中的避免了在寫操作的時(shí)候往不同服務(wù)器的索引表中寫索引帶來的額外開銷。使用Local indexing的時(shí)候即使查詢的字段不是索引字段索引表也會(huì)被使用,這會(huì)帶來查詢速度的提升,這點(diǎn)跟Global indexing不同。一個(gè)數(shù)據(jù)表的所有索引數(shù)據(jù)都存儲(chǔ)在一個(gè)單一的獨(dú)立的可共享的表中。在讀取數(shù)據(jù)的時(shí)候,標(biāo)紅的那句話不會(huì)翻譯大意就是在讀數(shù)據(jù)的時(shí)候因?yàn)榇鎯?chǔ)數(shù)據(jù)的region的位置無法預(yù)測導(dǎo)致性能有一定損耗。
配置hbase-site.xml
使用Local Indexing的話需要配置hbase-site.xml,在HBase集群的master節(jié)點(diǎn)的hbase-site.xml中添加如下配置并重啟HBase集群。
Local indexing also requires special configurations
in the master to ensure data table and local index regions co-location.
配置這個(gè)參數(shù)的目的是確保數(shù)據(jù)表與索引表協(xié)同定位。
<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>
高能預(yù)警:如果使用的是Phoenix 4.3+的版本的話
還需要在HBase集群的每個(gè)regionserver節(jié)點(diǎn)的
hbase-site.xml中添加如下配置并重啟HBase集群。
To support local index regions merge on data
regions merge you will need to add the following
parameter to hbase-site.xml in all the region
servers and restart. (It’s applicable for Phoenix 4.3+ versions)
這個(gè)配置是為了支持在數(shù)據(jù)region合并之上進(jìn)行
索引region合并(這句話感覺翻譯的不太準(zhǔn)確)。
<property>
<name>hbase.coprocessor.regionserver.classes</name>
<value>org.apache.hadoop.hbase.regionserver.LocalIndexMerger</value>
</property>
注意: 同理使用CDH版的要通過cloudera manager頁面管理配置
測試二級(jí)索引
進(jìn)入phoenix的CLI的界面創(chuàng)建company表。
> create table company(id varchar primary key, name varchar, address varchar);
查看company表索引
> !indexes company
2.3 創(chuàng)建索引
對company表的name字段創(chuàng)建索引,索引名為my_index。
> create local index my_index on company(name);
查看當(dāng)前所有表會(huì)發(fā)現(xiàn)多一張MY_INDEX索引表,查詢該表數(shù)據(jù)。
通過squirrel來查看company的索引字段。
從HBase的CLI界面查看當(dāng)前所有表。
> list
高能預(yù)警:這里的索引表并不叫MY_INDEX,而是叫_LOCAL_IDX_COMPANY,但是在Phoenix的CLI中進(jìn)行數(shù)據(jù)查詢的時(shí)候仍然是使用MY_INDEX進(jìn)行查詢,應(yīng)該是做了映射。
2.4 插入數(shù)據(jù)
在company表中添加測試數(shù)據(jù)。
> upsert into company(id, name, address) values('001', 'dimensoft', 'nanjing');
2.5 查詢數(shù)據(jù)
查看company表數(shù)據(jù)以及索引表my_index數(shù)據(jù)。
> select * from company;
> select * from my_index;
從HBase的CLI界面查看索引表_LOCAL_IDX_COMPANY。
> scan '_LOCAL_IDX_COMPANY'
3個(gè)索引字段_INDEX_ID、NAME和ID的值被合并為索引表的rowKey,其中_INDEX_ID并沒有值(\x000是十六進(jìn)制表示,轉(zhuǎn)換為字符串是空格)。
函數(shù)索引 Functional Indexes
函數(shù)索引從4.3版本就有,這種索引的內(nèi)容不局限于列,還能在表達(dá)式上建立索引。如果你使用的表達(dá)式正好就是索引的話,數(shù)據(jù)也可以直接從這個(gè)索引獲取,而不需要從數(shù)據(jù)庫獲取。比如說,在一個(gè)表達(dá)式上建立索引,這個(gè)表達(dá)式是UPPER(name) || '_test':
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-family: "Courier New" !important; font-size: 12px !important;">CREATE INDEX index2_f ON hao1 (UPPER(name) || '_test');</pre>
同樣的index2_f表會(huì)被建立,里面存儲(chǔ)了表達(dá)式求值后的結(jié)果,和RowKey的關(guān)系。當(dāng)然也可以添加INCLUDE作為覆蓋索引,做了覆蓋索引,就不需要再去原數(shù)據(jù)表中獲取數(shù)據(jù)。但是數(shù)據(jù)會(huì)多很多。
在索引范圍上,Phoenix的索引可以分為全局索引和本地索引,兩種索引適合的場景不同。
創(chuàng)建異步索引
一般我們可以使用CREATE INDEX來創(chuàng)建一個(gè)索引,這是一種同步的方法。但是有時(shí)候我們創(chuàng)建索引的表非常大,我們需要等很長時(shí)間。Phoenix 4.5以后有一個(gè)異步創(chuàng)建索引的方式,使用關(guān)鍵字ASYNC來創(chuàng)建索引:
CREATE INDEX index1_c ON hao1 (age) INCLUDE(name) ASYNC;
這時(shí)候創(chuàng)建的索引表中不會(huì)有數(shù)據(jù)。你還必須要單獨(dú)的使用命令行工具來執(zhí)行數(shù)據(jù)的創(chuàng)建。當(dāng)語句給執(zhí)行的時(shí)候,后端會(huì)啟動(dòng)一個(gè)map reduce任務(wù),只有等到這個(gè)任務(wù)結(jié)束,數(shù)據(jù)都被生成在索引表中后,這個(gè)索引才能被使用。啟動(dòng)工具的方法:
${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
這個(gè)任務(wù)不會(huì)因?yàn)榭蛻舳私o關(guān)閉而結(jié)束,是在后臺(tái)運(yùn)行。你可以在指定的文件ASYNC_IDX_HFILES中找到最終實(shí)行的結(jié)果。
