一、Phoenix整合Hbase
1、下载并解压:apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz
2、将apache-phoenix-5.0.0-HBase-2.0-bin目录下的phoenix-5.0.0-HBase-2.0-server.jar复制到hbase的lib目录下
3、修改hbase-site.xml配置文件
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>
<property>
<name>phoenix.query.timeoutMs</name>
<value>10800000</value>
</property>
<property>
<name>hbase.regionserver.lease.period</name>
<value>1200000</value>
</property>
<property>
<name>hbase.rpc.timeout</name>
<value>1200000</value>
</property>
<property>
<name>hbase.client.scanner.caching</name>
<value>1000</value>
</property>
<property>
<name>hbase.client.scanner.timeout.period</name>
<value>1200000</value>
</property>
<property>
<name>index.builder.threads.keepalivetime</name>
<value>1200000</value>
</property>
<property>
<name>index.write.threads.keepalivetime</name>
<value>1200000</value>
</property>
<property>
<name>hbase.htable.threads.keepalivetime</name>
<value>1200000</value>
</property>
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>
-->
<!-- 配置连接超时时间 -->
<property>
<name>phoenix.query.timeoutMs</name>
<value>10800000</value>
</property>
<property>
<name>hbase.regionserver.lease.period</name>
<value>1200000</value>
</property>
<property>
<name>hbase.rpc.timeout</name>
<value>1200000</value>
</property>
<property>
<name>hbase.client.scanner.caching</name>
<value>1000</value>
</property>
<property>
<name>hbase.client.scanner.timeout.period</name>
<value>1200000</value>
</property>
<property>
<name>index.builder.threads.keepalivetime</name>
<value>1200000</value>
</property>
<property>
<name>index.write.threads.keepalivetime</name>
<value>1200000</value>
</property>
<property>
<name>hbase.htable.threads.keepalivetime</name>
<value>1200000</value>
</property>
4、Phoenix的bin目录下启动客户端:sqlline.py hadoop-master:2181,hadoop-slave0:2181,hadoop-slave1:2181
5、Python安装卸载
sudo apt-get install python2.7
sudo apt-get remove python2.7
sudo apt-get remove --auto-remove python2.7
sudo apt-get purge python2.7
or
sudo apt-get purge --auto-remove python2.7
二、索引说明
1、本地索引
本地索引适用于写多、读少、空间有限的场景。与全局索引一样,Phoenix将自动选择是否在查询时使用本地索引。索引数据和原表数据存放在相同的服务器中,防止写入期间出现任何网络开销。即使查询的字段不是索引字段,本地索引也会被使用。与全局索引不同,4.8.0之前版本,表的所有本地索引都存储在单独共享表中;从4.8.0开始,本地索引数据存储在同一个数据表中单独的影子列族中。在使用本地索引进行读取时,因为不能预先确定索引数据确切的region位置,因此必须检查每个region的数据。这会给读取时带来一些额外开销。
#建立本地索引
CREATE LOCAL INDEX IDX_LOCAL_ID ON CARDATA (ID);
#使用本地索引
SELECT * FROM CARDATA WHERE ID= '111111';
2、全局索引
全局索引适用于读多写少的场景,它会建立一张独立的HBase索引表,对原始数据侵入性小。所有对数据表的写操作都会引起索引表的更新(DELETE、UPSERT VALUES和UPSERT SELECT))。索引表分布在不同的数据节点上的,跨节点的数据传输带来了较大的性能消耗。如果查询列不在索引表中,默认索引表将不会被使用,除非使用hint(SELECT /*+ INDEX(table_name,index_name) */ …)。
#建立全局索引
CREATE INDEX IDX_ID ON CARDATA (ID);
#使全局地索引
SELECT ID FROM CARDATA WHERE ID ='111111';
#强制使用全局索引(ROADCODE加索引,COVER未加索引)
SELECT /*+ INDEX(CARDATA, IDX_ROADCODE) */ ROADCODE,COVER FROM CARDATA WHERE ROADCODE ='111111';
强制使用索引方式应该仅在索引列的区分度很强时使用,比如上述例子的ROADCODE列等于111111的很少时才使用Hint方式,否则还不如直接用默认行为即full scan性能更好。
3、覆盖索引
覆盖索引的特点是我们可以把关心的列打包存储在索引表中,一旦在索引表中能够找到索引条目就不需要返回主表,直接拿到查询结果。
#建立覆盖索引
CREATE INDEX IDX_COVER_ID ON CARDATA (ID) include(ROADCODE);
#使用覆盖索引
SELECT ROADCODE FROM CARDATA WHERE ID ='111111';
4、函数索引
函数索引的特点是能根据表达式创建索引,适用于对查询表过滤条件是表达式的表创建索引。
#创建函数索引
CREATE INDEX IDX_FUNC_ ROADCODE ON CARDATA (UPPER(ROADCODE));
#使用函数索引
SELECT * FROM CARDATA WHERE UPPER(ROADCODE)='HOTEL';
5、执行计划与性能查看
EXPLAIN SELECT COUNT(ID) FROM CARDATA WHERE ROADCODE='11270';
CLIENT:表明操作在客户端执行还是服务端执行,客户端尽量返回少的数据。若为 SERVER 表示在服务端执行。
FILTER BY expression:返回和过滤条件匹配的结果。
FULL SCAN OVER tableName:表明全表扫描某张业务表。
RANGE SCAN OVER tableName [ … ]:表明代表范围扫描某张表,括号内代表 rowkey 的开始和结束。
ROUND ROBIN:无 ORDER BY 操作时, ROUND ROBIN 代表最大化客户端的并行化。
x-CHUNK:执行此操作的线程数。
PARALLEL x-WAY:表明合并多少并行的扫描。
EST_BYTES_READ:执行查询时预计扫描的总字节数。
EST_ROWS_READ:执行查询时预计扫描多少行。
EST_INFO_TS:收集查询信息的 epoch time
6、创建异步索引
CREATE INDEX IDX_ASYNC_TEST ON CARDATA (BYTIME) ASYNC
激活异步创建索引命令
hadoop jar ./phoenix-5.0.0-HBase-2.0-client.jar org.apache.phoenix.mapreduce.index.IndexTool --data-table USERINFO --index-table IDX_ASYNC_USERINFO --output-path IDX_INNER_LOG_INTERFACE_DATE
7、增加列
ALTER TABLE CARDATA ADD NEWCOL VARCHAR;
三、查询测试
数据量:5百万条测试数据(5088430)
测试SQL:
SQL1:SELECT COUNT(ID) FROM CARDATA;
SQL2:SELECT COUNT(ID) FROM CARDATA WHERE ROADCODE='11270';
SQL3:SELECT ID,ROADCODE,TIME FROM CARDATA WHERE ROADCODE='11270' LIMIT 100;
SQL4:SELECT * FROM CARDATA WHERE ROADCODE='11270' LIMIT 100;
SQL5:SELECT * FROM (SELECT ROADCODE, COUNT(ROADCODE) AS NUM FROM CARDATA GROUP BY ROADCODE) ORDER BY NUM DESC LIMIT 10;
SQL6:SELECT ROADCODE,COUNT(ROADCODE) AS NUM FROM CARDATA GROUP BY ROADCODE LIMIT 10;
SQL7:SELECT * FROM CARDATA LIMIT 10 OFFSET 10000;
结果
Hbase大数据量查询耗时对比(单位:秒) | |||||||
测试项 | SQL1 | SQL2 | SQL3 | SQL4 | SQL5 | SQL6 | SQL7 |
未加索引 | 35.471 | 48.454 | 30.728 | 30.564 | 53.375 | 52.189 | 13.943 |
加本地索引 | 6.699 | 0.012 | 0.092 | 0.107 | 15.261 | 0.01 | 7.467 |
加全局索引 | 14.677 | 0.029 | 48.303 | 50.211 | 22.134 | 0.009 | 17.211 |
覆盖索引 | 14.314 | 0.013 | 0.007 | 48.125 | 19.736 | 0.044 | 16.892 |
使用全局索引,查询列中包含未加索引的的字段时,查询不会使用索引表。
全局索引查询所有字段解决方案:分两次SQL查询,先根据索引查询到ID,再根据ID去查整条记录