6.3、 Phoenix 二级索引
6.3.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>
6.3.2 、全局索引(global index)
Global Index 是默认的索引格式,创建全局索引时,会在 HBase 中建立一张新表。也就是说索引数据和数据表是存放在不同的表中的,因此全局索引适用于多读少写的业务场景。
写数据的时候会消耗大量开销,因为索引表也要更新,而索引表是分布在不同的数据节点上的,跨节点的数据传输带来了较大的性能消耗。
在读数据的时候 Phoenix 会选择索引表来降低查询消耗的时间。
创建单个字段的全局索引。
CREATE INDEX my_index ON my_table (my_col); #例如 0: jdbc:phoenix:hadoop102,hadoop103,hadoop104> create index my_index on student1(age);
#删除索引 DROP INDEX my_index ON my_table 0: jdbc:phoenix:hadoop102,hadoop103,hadoop104> drop index my_index on student1;
查看二级索引是否有效,可以使用 explain查看执行计划,有二级索引之后会变成范围扫描
0: jdbc:phoenix:hadoop102,hadoop103,hadoop104> explain select id,name from student1 where age = 10; +---------------------------------------------------------------- ---------+----------------+---------------+---------+ | PLAN | EST_BYTES_READ | EST_ROWS_READ | EST_INF | +---------------------------------------------------------------- ---------+----------------+---------------+---------+ | CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN RANGE SCAN OVER MY_INDEX [10] | null | null | null | | SERVER FILTER BY FIRST KEY ONLY | null | null | null | +---------------------------------------------------------------- ---------+----------------+---------------+---------+ 2 rows selected (0.044 seconds)
如果想查询的字段不是索引字段的话索引表不会被使用,也就是说不会带来查询速度的提升。
0: jdbc:phoenix:hadoop102,hadoop103,hadoop104> explain select id,name,addr from student1 where age = 10; +---------------------------------------------------------------- ---+----------------+---------------+-------------+ | PLAN | EST_BYTES_READ | EST_ROWS_READ | EST_INFO_TS | +---------------------------------------------------------------- ---+----------------+---------------+-------------+ | CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN FULL SCAN OVER STUDENT1 | null | null | null | | SERVER FILTER BY AGE = 10 | null | null | null | +---------------------------------------------------------------- ---+----------------+---------------+-------------+ 2 rows selected (0.024 seconds)
若想解决上述问题,可采用如下方案:
(1)使用包含索引
(2)使用本地索引
6.3.3、 包含索引(covered index)
创建携带其他字段的全局索引(本质还是全局索引)。
语法:CREATE INDEX my_index ON my_table (v1) INCLUDE (v2);
骚戴理解:其中v1是索引列,v2是包含索引列,看下面的例子就懂了!
先删除之前的索引: 0: jdbc:phoenix:hadoop102,hadoop103,hadoop104> drop index my_index on student1; #创建包含索引 0: jdbc:phoenix:hadoop102,hadoop103,hadoop104> create index my_index on student1(age) include (addr);
之后使用执行计划查看效果
0: jdbc:phoenix:hadoop102,hadoop103,hadoop104> explain select id,name,addr from student1 where age = 10; +---------------------------------------------------------------- ---------+----------------+---------------+---------+ | PLAN | EST_BYTES_READ | EST_ROWS_READ | EST_INF | +---------------------------------------------------------------- ---------+----------------+---------------+---------+ | CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN RANGE SCAN OVER MY_INDEX [10] | null | null | null | +---------------------------------------------------------------- ---------+----------------+---------------+---------+ 1 row selected (0.112 seconds)
6.3.4 、本地索引(local index)
Local Index 适用于写操作频繁的场景。
索引数据和数据表的数据是存放在同一张表中(且是同一个 Region),避免了在写操作的时候往不同服务器的索引表中写索引带来的额外开销。
CREATE LOCAL INDEX my_index ON my_table (my_column);//my_column 可以是多个。
本地索引会将所有的信息存在一个影子列族中,虽然读取的时候也是范围扫描,但是没有全局索引快,优点在于不用写多个表了。
#删除之前的索引 0: jdbc:phoenix:hadoop102,hadoop103,hadoop104> drop index my_index on student1; #创建本地索引 0: jdbc:phoenix:hadoop102,hadoop103,hadoop104> CREATE LOCAL INDEX my_index ON student1 (age,addr);
#使用执行计划
0: jdbc:phoenix:hadoop102,hadoop103,hadoop104> explain select id,name,addr from student1 where age = 10; +---------------------------------------------------------------- -----------+----------------+---------------+-------+ | PLAN | EST_BYTES_READ | EST_ROWS_READ | EST_I | +---------------------------------------------------------------- -----------+----------------+---------------+-------+ | CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN RANGE SCAN OVER STUDENT1 [2,10] | null | null | null | | SERVER MERGE [0.ADDR] | null | null | null | | SERVER FILTER BY FIRST KEY ONLY | null | null | null | +---------------------------------------------------------------- -----------+----------------+---------------+-------+ 3 rows selected (0.025 seconds)
第 7 章 与 Hive 的集成
7.1 、使用场景
如果大量的数据已经存放在 HBase 上面,需要对已经存在的数据进行数据分析处理,那
么 Phoenix 并不适合做特别复杂的 SQL 处理,此时可以使用 hive 映射 HBase 的表格,之后
写 HQL 进行分析处理。
7.2 、HBase 与 Hive 集成使用
在 hive-site.xml 中添加 zookeeper 的属性,如下:
<property> <name>hive.zookeeper.quorum</name> <value>hadoop102,hadoop103,hadoop104</value> </property> <property> <name>hive.zookeeper.client.port</name> <value>2181</value> </property>
1)案例一
目标:建立 Hive 表,关联 HBase 表,插入数据到 Hive 表的同时能够影响 HBase 表。
分步实现:
(1)在 Hive 中创建表同时关联 HBase
CREATE TABLE hive_hbase_emp_table( empno int, ename string, job string, mgr int, hiredate string, sal double, comm double, deptno int ) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:co mm,info:deptno") TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");
骚戴理解:STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'表示以HBase存储数据
("hbase.columns.mapping" = ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:co
mm,info:deptno")
和
empno int,ename string,job string,mgr int,hiredate string,sal double,comm double,deptno int
是一一对应的!
提示:完成之后,可以分别进入 Hive 和 HBase 查看,都生成了对应的表。
(2)在 Hive 中创建临时中间表,用于 load 文件中的数据
提示:不能将数据直接 load 进 Hive 所关联 HBase 的那张表中。
CREATE TABLE emp( empno int, ename string, job string, mgr int, hiredate string, sal double, comm double, deptno int ) row format delimited fields terminated by '\t';
(3)向 Hive 中间表中 load 数据
hive> load data local inpath '/opt/software/emp.txt' into table emp;
(4)通过 insert 命令将中间表中的数据导入到 Hive 关联 Hbase 的那张表中
hive> insert into table hive_hbase_emp_table select * from emp;
(5)查看 Hive 以及关联的 HBase 表中是否已经成功的同步插入了数据
hive> select * from hive_hbase_emp_table;
Hbase> scan 'hbase_emp_table'
2)案例二
目标:在 HBase 中已经存储了某一张表 hbase_emp_table,然后在 Hive 中创建一个外部
表来关联 HBase 中的 hbase_emp_table 这张表,使之可以借助 Hive 来分析 HBase 这张表中
的数据。
注:该案例 2 紧跟案例 1 的脚步,所以完成此案例前,请先完成案例 1。
分步实现:
(1)在 Hive 中创建外部表
CREATE EXTERNAL TABLE relevance_hbase_emp( empno int, ename string, job string, mgr int, hiredate string, sal double, comm double, deptno int ) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:co mm,info:deptno") TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");
(2)关联后就可以使用 Hive 函数进行一些分析操作了
hive (default)> select deptno,avg(sal) monery from relevance_hbase_emp group by deptno ;