Fork me on GitHub

phoenix中添加二级索引

 Phoenix创建Hbase二级索引

官方文档

1. 配置Hbase支持Phoenix创建二级索引

  1.  添加如下配置到Hbase的Hregionserver节点的hbase-site.xml 

<!-- phoenix regionserver 配置参数 -->
<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>
<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>
<description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>
</property>
View Code

  2.  添加如下配置到Hbase中Hmaster节点的hbase-site.xml中

<!-- phoenix master 配置参数 -->
<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>
View Code

可以在hbase-site.xml里配置以下调优参数 

index.builder.threads.max
o 为主表更新操作建立索引的最大线程数
o Default: 10

index.builder.threads.keepalivetime
o 上面线程的超时时间
o Default: 60

index.writer.threads.max
o 将索引写到索引表的最大线程数
o Default: 10

index.writer.threads.keepalivetime
o 上面线程的超时时间
o Default: 60

hbase.htable.threads.max
o 同时最多有这么多线程往索引表写入数据
o Default: 2,147,483,647

hbase.htable.threads.keepalivetime
o 上面线程的超时时间
o Default: 60

index.tablefactory.cache.size
o 缓存10个往索引表写数据的线程
o Default: 10
View Code

 

 

3. 常见问题汇总:

  1)注意:网上配置文档里有这一条,但在实际测试中(测试环境hbase-1.3.1,网上0.98.6),加入该条的regionserver会在hbase启动时失败,对应节点上没有HregionServer进程,去掉该配置后正常启动,且能正常创建local index。

<property>
<name>hbase.coprocessor.regionserver.classes</name>
<value>org.apache.hadoop.hbase.regionserver.LocalIndexMerger</value>
</property>

  2hbase-site.xml的zookeeeper的配置信息不能加2181,否则在创建local index的时候会报以下异常:

    

正常配置:

<property>
        <name>hbase.zookeeper.quorum</name>
        <value>hadoop101,hadoop102,hadoop103</value>
</property>

2. 创建索引

  phoenix的索引分类

1)全局索引 global index是默认的索引格式。

适用于多读少写的业务场景。写数据的时候会消耗大量开销,因为索引表也要更新,而索引表是分布在不同的数据节点上的,跨节点的数据传输带来了较大的性能消耗。

在读数据的时候Phoenix会选择索引表来降低查询消耗的时间。如果想查询的字段不是索引字段的话索引表不会被使用,也就是说不会带来查询速度的提升。

全局索引必须是查询语句中所有列都包含在全局索引中,它才会生效。
CREATE INDEX MY_INDEX ON STUDENT("info"."dt");

 查询语句:

select "dt" from STUDENT where "dt" >= '2018-08-08'; #可以使用到索引表MY_INDEX
select "name","age","dt" from STUDENT where "dt" >= '2018-08-08'; #这样子就不会用到索引表MY_INDEX,因为name和age不在索引表中;

  所以使用全局索引,必须要所有的列都包含在索引中。那么怎样才能使用上索引呢?有三种方法:

①. 创建索引的时候使用覆盖索引。 

CREATE INDEX MY_INDEX ON STUDENT("info"."dt") INCLUDE("info"."name", "info"."age"); //INCLUED之前的索引,只能建立一个才会走range scan索引,不然就是full scan

这种索引会把name加到索引表里面,同时name也会随着原数据表中的变化而变化。这种方式很明显的缺点是索引表的大小较大,然后就是全局索引不适合写特别多的情况。

  Covered Index覆盖索引的二级索引。这种索引在获取数据的过程中,内部不需要再去HBase上获取任何数据,你查询需要返回的列的数据都会被存储在索引中。要想达到这种效果,你的select 的列,where 的列都需要在索引中出现。

注意关键字INCLUDE(注意跟异步索引的区别),就是包含需要返回数据结果的列。这种索引方式的最大好处就是速度快,而我们也知道,索引就是空间换时间,所以缺点也很明显,存储空间耗费较多。Phoenix的索引其实就是建了一张HBase的表。你可以通过HBase Shell的list命令看到。

 

 

 ②. 使用类似于Oracle的Hint,强制索引。

select /*+ INDEX(STUDENT MY_INDEX)*/ "name","age" from STUDENT where "dt" >= '2018-08-08';

 查询引擎会使用MY_INDEX这个索引,由于它会发现索引表中没有name,age数据,所以每一行它都会去原数据表中获取name,age的值。这个强制索引只有在你认为索引有比较好的选择性的时候才是好的选择,也就是说dt大于2018-08-08的行数不多。不然的话,使用Phoenix默认的全表扫描的性能也许会更好。

 ③. 创建本地索引

CREATE LOCAL INDEX MY_INDEX ON STUDENT("info"."dt");

本地索引和全局索引不同的是,查询语句中,即使所有的列都不在索引定义中,它也会使用索引,这是本地索引的默认行为。Phoenix知道原数据和索引数据在同一个RegionServer上,能保证索引查找是本地的。

global index的设计方式,会单独写一张索引表,列族为include字段,rowkey的设计方位是:
二级索引字段1+"\x00"+二级索引字段2(复合索引)…+"\x00"+原表rowkey
2.查询的时候,会直接定位到索引表,通过rowkey查到位置,然后从索引表中带出数据
3.因为建立索引的时候还要多写一份include字段,读的时候直接从索引表定位并读出信息。所以这种表的应用场景定位是写的慢,读得快

2)本地索引 Local index适用于写操作频繁的场景。

本地索引适合那些写多读少,或者存储空间有限的场景。和全局索引一样,Phoenix也会在查询的时候自动选择是否使用本地索引。本地索引之所以是本地,只要是因为

索引数据和真实数据存储在同一台机器上,这样做主要是为了避免网络数据传输的开销。如果你的查询条件没有完全覆盖索引列,本地索引还是可以生效。因为无法提前确定数据在哪个Region上,所以在读数据的时候,还需要检查每个Region上的数据而带来一些性能损耗。

如下示例,创建了本地索引

CREATE LOCAL INDEX my_index ON my_table (my_index)

local index的设计方式,索引数据直接写在原表rowkey中,列族不写任何实际信息,local index的rowkey的设计方位是:
原数据region的start key+"\x00"+二级索引字段1+"\x00"+二级索引字段2(复合索引)…+"\x00"+原rowkey
第一条信息"原数据region的start key",这样做的目的是保证索引数据和原数据在一个region上,定位到二级索引后根据原rowkey就可以很快在本region上获取到其它信息,减少网络开销和检索成本。
2.查询的时候,会在不同的region里面分别对二级索引字段定位,查到原rowkey后在本region上获取到其它信息
3.因为这种索引设计方式只写索引数据,省了不少空间的占用,根据索引信息拿到原rowkey后再根据rowkey到原数据里面获取其它信息。所以这种表的应用场景定位是写的快,读得慢

local index和global index比较

1.索引数据

global index单独把索引数据存到一张表里,保证了原始数据的安全,侵入性小
local index把数据写到原始数据里面,侵入性强,原表的数据量=原始数据+索引数据,使原始数据更大
2.性能方面

global index要多写出来一份数据,写的压力就大一点,但读的速度就非常快
local index只用写一份索引数据,节省不少空间,但多了一步通过rowkey查找数据,写的速度非常快,读的速度就没有直接取自己的列族数据快。

3)异步创建索引

一般我们可以使用CREATE INDEX来创建一个索引,这是一种同步的方法。但是有时候我们创建索引的表非常大,我们需要等很长时间。Phoenix 4.5以后有一个异步创建索引的方式,使用关键字ASYNC来创建索引:

create index MY_INDEX on FRUITS("info"."name") include ("info"."color") async;

这时候创建的索引表中不会有数据。你还必须要单独的使用命令行工具来执行数据的创建。当语句给执行的时候,后端会启动一个map reduce任务,只有等到这个任务结束,数据都被生成在索引表中后,这个索引才能被使用。启动工具的方法:

${HBASE_HOME}/bin/hbase org.apache.phoenix.mapreduce.index.IndexTool \
> --data-table FRUITS --index-table MY_INDEX \
> --output-path ASYNC_IDX_HFILES
注:  --schema MY_SCHEMA,不加这个就是默认的schema
注: 上边尽量不要用小写,即使""双引号里边写的是小写它也不识别;

2019-10-10 15:04:01,579 INFO  [main] index.IndexTool: Loading HFiles from ASYNC_IDX_HFILES/MY_INDEX
2019-10-10 15:04:01,723 WARN  [main] mapreduce.LoadIncrementalHFiles: Skipping non-directory hdfs://hadoop101:9000/user/kris/ASYNC_IDXEX/_SUCCESS
2019-10-10 15:04:01,909 INFO  [LoadIncrementalHFiles-0] hfile.CacheConfig: Created cacheConfig: CacheConfig:disabled
2019-10-10 15:04:01,985 INFO  [LoadIncrementalHFiles-0] mapreduce.LoadIncrementalHFiles: Trying to load hfile=hdfs://hadoop101:9000/usIDX_HFILES/MY_INDEX/info/6b69a7babd4e4c629b6bee988cf15c5d first=water\x001005 last=watermelon\x001006
2019-10-10 15:04:02,136 INFO  [main] index.IndexToolUtil:  Updated the status of the index MY_INDEX to ACTIVE 

这个任务不会因为客户端给关闭而结束,是在后台运行。你可以在指定的文件ASYNC_IDX_HFILES中找到最终实行的结果。

在Hbase中查看:

  

   测试:

综上三种提升效率查询方式:

1) CREATE INDEX my_index ON my_table (v1) INCLUDE (v2)
2) SELECT /*+ INDEX(my_table my_index) */ v2 FROM my_table WHERE v1 = 'foo'
3) CREATE LOCAL INDEX my_index ON my_table (v1)

 如何删除索引

use "test"再删索引 drop index "my_index" on "student"不行,必须前边加schema,默认的不需要加

DROP INDEX "my_index" ON "test"."student"

用phoenix只是用hbase自身实现了hbase自己的二级索引,用hbase自己rowkey查询的特点来设计索引数据的rowkey,性能方面完全要靠一次检索索引数据的数据量大小了。

 

Phoenix基本优化方法

索引性能调优

posted @ 2019-10-10 22:38  kris12  阅读(1651)  评论(0编辑  收藏  举报
levels of contents