1、HBase存储结构
2、RowKey设计原则
1)rowkey长度原则
2)rowkey散列原则
3)rowkey唯一原则
3、RowKey如何设计
1)生成随机数、hash、散列值
2)字符串反转
4、Phoenix二级索引(讲原理)
对于Hbase,如果想精确定位到某行记录,唯一的办法就是通过rowkey查询。如果不通过rowkey查找数据,就必须逐行比较每一行的值,对于较大的表,全表扫描的代价是不可接受的。
(1)开启索引支持
# 关闭hbase集群 stop-hbase.sh # 在/usr/local/soft/hbase-1.4.6/conf/hbase-site.xml中增加如下配置 <property> <name>hbase.regionserver.wal.codec</name> <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value> </property> <property> <name>hbase.rpc.timeout</name> <value>60000000</value> </property> <property> <name>hbase.client.scanner.timeout.period</name> <value>60000000</value> </property> <property> <name>phoenix.query.timeoutMs</name> <value>60000000</value> </property> # 同步到所有节点 scp hbase-site.xml node1:`pwd` scp hbase-site.xml node2:`pwd` # 修改phoenix目录下的bin目录中的hbase-site.xml <property> <name>hbase.rpc.timeout</name> <value>60000000</value> </property> <property> <name>hbase.client.scanner.timeout.period</name> <value>60000000</value> </property> <property> <name>phoenix.query.timeoutMs</name> <value>60000000</value> </property> # 启动hbase start-hbase.sh # 重新进入phoenix客户端 sqlline.sql master,node1,node2
(2)创建索引
(2.1)全局索引
全局索引适合读多写少的场景。如果使用全局索引,读数据基本不损耗性能,所有的性能损耗都来源于写数据。数据表的添加、删除和修改都会更新相关的索引表(数据删除了,索引表中的数据也会删除;数据增加了,索引表的数据也会增加)
# 创建DIANXIN.sql CREATE TABLE IF NOT EXISTS DIANXIN ( mdn VARCHAR , start_date VARCHAR , end_date VARCHAR , county VARCHAR, x DOUBLE , y DOUBLE, bsid VARCHAR, grid_id VARCHAR, biz_type VARCHAR, event_type VARCHAR , data_source VARCHAR , CONSTRAINT PK PRIMARY KEY (mdn,start_date) ) column_encoded_bytes=0; # 上传数据DIANXIN.csv # 导入数据 psql.py master,node1,node2 DIANXIN.sql DIANXIN.csv # 创建全局索引 CREATE INDEX DIANXIN_INDEX ON DIANXIN ( end_date ); # 查询数据 ( 索引未生效) select * from DIANXIN where end_date = ‘20180503154014‘; # 强制使用索引 (索引生效) hint select /*+ INDEX(DIANXIN DIANXIN_INDEX) */ * from DIANXIN where end_date = ‘20180503154014‘; select /*+ INDEX(DIANXIN DIANXIN_INDEX) */ * from DIANXIN where end_date = ‘20180503154014‘ and start_date = ‘20180503154614‘; # 取索引列,(索引生效) select end_date from DIANXIN where end_date = ‘20180503154014‘; # 创建多列索引 CREATE INDEX DIANXIN_INDEX1 ON DIANXIN ( end_date,COUNTY ); # 多条件查询 (索引生效) select end_date,MDN,COUNTY from DIANXIN where end_date = ‘20180503154014‘ and COUNTY = ‘8340104‘; # 查询所有列 (索引未生效) select * from DIANXIN where end_date = ‘20180503154014‘ and COUNTY = ‘8340104‘; # 查询所有列 (索引生效) select /*+ INDEX(DIANXIN DIANXIN_INDEX1) */ * from DIANXIN where end_date = ‘20180503154014‘ and COUNTY = ‘8340104‘; # 单条件 (索引未生效) select end_date from DIANXIN where COUNTY = ‘8340103‘;(2.2)本地索引本地索引适合写多读少的场景,或者存储空间有限的场景。和全局索引一样,Phoenix也会在查询的时候自动选择是否使用本地索引。本地索引因为索引数据和原数据存储在同一台机器上,避免网络数据传输的开销,所以更适合写多的场景。由于无法提前确定数据在哪个Region上,所以在读数据的时候,需要检查每个Region上的数据从而带来一些性能损耗。
@ 创建本地索引 CREATE LOCAL INDEX DIANXIN_LOCAL_IDEX ON DIANXIN(grid_id); # 索引生效 select grid_id from dianxin where grid_id=‘117285031820040‘; # 索引生效 select * from dianxin where grid_id=‘117285031820040‘;(2.3)覆盖索引
注意:查询是 select 的列和 where 的列都需要在索引中出现。
# 创建覆盖索引 CREATE INDEX DIANXIN_INDEX_COVER ON DIANXIN ( x,y ) INCLUDE ( county ); # 查询所有列 (索引未生效) select * from dianxin where x=117.288 and y =31.822; # 强制使用索引 (索引生效) select /*+ INDEX(DIANXIN DIANXIN_INDEX_COVER) */ * from dianxin where x=117.288 and y =31.822; # 查询索引中的列 (索引生效) select mdn,x,y,county from dianxin where x=117.288 and y =31.822; 查询条件必须放在索引中 select 中的列可以放在INCLUDE (将数据保存在索引中) select /*+ INDEX(DIANXIN DIANXIN_INDEX_COVER) */ x,y,count(*) from dianxin group by x,y;