文章目录
- 一、基本指令
- 1)创建表
- 2)删除表
- 3)插入数据
- 4)查询数据
- 5)删除数据
- 6)退出命令行
- 二、映射
- 1)视图映射
- 创建视图
- 查询视图
- 删除视图
- 2)表映射
- 删除表
- 3)视图映射和表映射的区别
- 三、二级索引
- 1)修改配置文件
- 2)全局索引
- 增加索引
- 删除索引
- 创建多列索引
- 3)本地索引
- 创建索引
- 4)覆盖索引
- 创建索引
- 四、java代码使用phonex
- 五、phonex调优
- 配置超时
- 预分区
- 方法一
- 方法二
- rowkey的设计
- in memory
- version
- Hbase适合存储大量的对关系运算要求低的NOSQL数据,受Hbase 设计上的限制不能直接使用原生的PAI执行在关系数据库中普遍使用的条件判断和聚合等操作。
- Apache Phoenix提供一种更面向普通开发人员的操作方式
- Phoenix 基于Hbase给面向业务的开发人员提供了以标准SQL的方式对Hbase进行查询操作,并支持标准SQL中大部分特性:条件运算,分组,分页,等高级查询语法。
一、基本指令
使用phonex
sqlline.py master,node1,node2
- 用了phonex就只能存储结构化的数据,不能存储半结构化和非结构化的数据
1)创建表
建表的时候必须要指定主键,或者会报错
CREATE TABLE IF NOT EXISTS STUDENT1 (
id VARCHAR NOT NULL PRIMARY KEY,
name VARCHAR,
age BIGINT,
gender VARCHAR ,
clazz VARCHAR
);
在HBASE中查看表的结构
在phonex中创建的表比在hbase中的表多了一段代码,这部分叫做协处理器,就是在region中运行的一段代码,用于自动处理索引
2)删除表
删除所有在phonex中创建的表,观察HBASE中是否还有
发现hbase中也没有了
3)插入数据
4)查询数据
查询全部
虽然也可以分组,汇总,但是不适合该操作,当数据多的时候,数据非常慢,计算量也很大,可能会导致hbase集群崩溃
5)删除数据
支持where操作,速度快
6)退出命令行
!quit
二、映射
- 默认情况下,直接在hbase中创建的表,通过phoenix是查看不到的
- 如果需要在phoenix中操作直接在hbase中创建的表,则需要在phoenix中进行表的映射
- 映射方式有两种:视图映射和表映射。(视图映射,表映射)ou
- 为表创建映射时,需保证,表是结构化的,不能为非结构化和半结构化的表创建映射
1)视图映射
- Phoenix创建的视图是只读的,所以只能用来做查询
在hbase中找一个student表,在phonex中为该表创建视图映射,由于原表中已经有了一个STUDENT,在phonex中会自动将表名转为大写,便于区分,这里加上引号创建student映射,但是注意,查询的时候也需要加上引号
首先在HBASE中查看student的列族和列的名字,了解表的结构
创建视图
在phonex中创建视图映射,和创建表一样必须指定主键,这里的主键就是HBASE表中的rowkey,字段名可以任意起,这里为id
create view "student" (
id varchar primary key,
"info"."age" varchar,
"info"."clazz"varchar,
"info"."name" varchar,
"info"."sex" varchar
);
查询视图
删除视图
drop view “student”;
HBASE中依然存在,因为视图是只读的
2)表映射
- 创建映射表的时候,Phoenix会在表中创建一些空的键值对,会生成原表对应字段的映射,故创建表时,需加上column_encoded_bytes=0,否者用原表的字段名在去查询时,对应的映射中查询,会查询不到
- 使用Apache Phoenix创建对HBase的表映射,有两种方法:
- 1) 当HBase中已经存在表时,可以以类似创建视图的方式创建关联表,只需要将create view改为create table即可。
- 2)当HBase中不存在表时,可以直接使用create table指令创建需要的表,并且在创建指令中可以根据需要对HBase表结构进行显示的说明。
方法1
create table "student" (
empid varchar primary key,
"info"."age" varchar,
"info"."clazz"varchar,
"info"."sex" varchar,
"info"."name" varchar
) column_encoded_bytes=0;
方法2
这样系统将会自动在Phoenix和HBase中创建表,并会根据指令内的参数对表结构进行初始化。
使用create table创建的关联表,如果对表进行了修改,源数据也会改变,同时如果关联表被删除,源表也会被删除。但是视图就不会,如果删除视图,源数据不会发生改变。
创建一个HBASE中不存在的表的映射
create table "stu" (
empid varchar primary key,
"info"."age" varchar,
"info"."clazz"varchar,
"info"."sex" varchar,
"info"."name" varchar
) column_encoded_bytes=0;
hbase中也有该表的信息
删除表
hbase中也被删除,如果被更改,hbase中也被更改
3)视图映射和表映射的区别
- 相比于直接创建映射表,视图的查询效率会低,原因是:创建映射表的时候,Phoenix会在表中创建一些空的键值对,这些空键值对的存在可以用来提高查询效率。
- 视图映射是只读的操作,不会对原表进行修改,表映射和原表关联,对表映射的更改,也会影响hbase中的表
三、二级索引
- 对于Hbase,如果想精确定位到某行记录,唯一的办法就是通过rowkey查询。如果不通过rowkey查找数据,就必须逐行比较每一行的值,对于较大的表,全表扫描的代价是不可接受的。
- 索引分为全局索引和本地索引
1)修改配置文件
关闭hbase的集群,修改配置文件
修改配置文件,设置RPC请求的超时时间。默认为60s,由于电脑性能和数据量,需要修改的长一点,RPC时间超过该值,客户端就会主动关闭socket
关闭集群
修改phonex下的hbase-site.xml
<property>
<name>phoenix.query.timeoutMs</name>
<value>500000</value>
</property>
修改hbase下的hbase-site.xml
如果不是伪分布式,还需将该文件分别发送到子节点的对应目录下
<property>
<name>hbase.regionserver.wal.codec</name>
<value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
</property>
<property>
<name>phoenix.query.timeoutMs</name>
<value>500000</value>
</property>
两个文件修改完后,启动集群
2)全局索引
- 全局索引适合读多写少的场景。
- 如果使用全局索引,读数据基本不损耗性能,所有的性能损耗都来源于写数据。
- 数据表的添加、删除和修改都会更新相关的索引表(数据删除了,索引表中的数据也会删除;数据增加了,索引表的数据也会增加)、
- 注意: 对于全局索引在默认情况下,在查询语句中检索的列如果不在索引表中,Phoenix不会使用索引表将,除非使用hint。
- hint是一种添加注解的方式
这里个建一个数据量比较大的表,效果明显
创建表,由于手机号并非每条数据的唯一标识,需要用,联合主键,由于建表,再向表插数据,速度慢,将建表语句放入一个sql文件中,使用指令导入数据到表中
创建sql文件
上传数据
执行指令,导入数据
进入phonex
这是一个普通的表,查询测试时间根据mdn查询数据
根据start_data查询数据
根据end_data查询数据
以上的测试也应证了,前缀比较器比其他子串比较器要快,行过滤器比列值过滤器速度快
前缀加行过滤器最快
增加索引
根据需求,为要查找的字段增加全局索引,此处以end_data为例
这里会多了一个索引表,hbase中也是
查询数据,会发现没很大区别,这是因为索引没生效,查找的数据含有非索引字段的部分
只查询索引字段,时间明显减少,可见索引生效
要想查询非索引字段的时候,让索引生效,可以使用加上hint的方法
加上 /*+ INDEX(DIANXIN DIANXIN_INDEX) */ 强制使用索引
删除索引
drop index DIANXIN_INDEX on dianxin;
创建多列索引
CREATE INDEX DIANXIN_INDEX1 ON DIANXIN (end_date,start_date);
查询索引列,索引生效
此处只能where后面只能筛选这个end_date的或者end_date和start_date才会生效,用start_date不生效
查询含非索引的列和非key值的列
使索引生效
3)本地索引
- 本地索引适合写多读少的场景,或者存储空间有限的场景。和全局索引一样,Phoenix也会在查询的时候自动选择是否使用本地索引。
- 本地索引因为索引数据和原数据存储在同一台机器上,避免网络数据传输的开销,所以更适合写多的场景
- 由于无法提前确定数据在哪个Region上,所以在读数据的时候,需要检查每个Region上的数据从而带来一些性能损耗。
- 注意:对于本地索引,查询中无论是否指定hint或者是查询的列是否都在索引表中,都会使用索引表。
创建索引
但在HBASE中只有一个索引表,本地索引和数据表在一个表里
观察全局索引和本地索引的表的不同
本地索引=》数据表
全局索引
测试
查询索引字段
select grid_id from dianxin where grid_id='117285031820040’
索引生效
查询非索引的字段
select * from dianxin where grid_id='117285031820040’
索引生效
4)覆盖索引
- 覆盖索引是把原数据存储在索引数据表中,这样在查询时不需要再去HBase的原表获取数据就,直接返回查询结果。
- 注意:查询是 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 x,y,county from dianxin where x=117.288 and y =31.822;
查询条件必须放在索引中,查询字段作为覆盖
四、java代码使用phonex
在java项目中,加入phonex对应版本的依赖
注意此处必须加入与HBASE版本对应的依赖
<dependency>
<groupId>org.apache.phoenix</groupId>
<artifactId>phoenix-core</artifactId>
<version>4.15.0-HBase-1.4</version>
</dependency>
代码演示
import java.sql.*;
public class Dianxin_Demo {
public static void main(String[] args) throws SQLException {
//建立连接,连接zookeeper
Connection conn = DriverManager.getConnection("jdbc:phoenix:master:2181");
//建立预处理的sql
PreparedStatement ps = conn.prepareStatement("select * from DIANXIN where mdn=?");
//设置参数的值
ps.setString(1,"47BE1E866CFC071DB19D5E1C056BE28AE24C16E7");
//执行查询操作,获取结果集
ResultSet resultSet = ps.executeQuery();
while ((resultSet.next())){
String mdn = resultSet.getString("mdn");
String start_date = resultSet.getString("start_date");
String end_date = resultSet.getString("end_date");
String county = resultSet.getString("county");
String x = resultSet.getString("x");
String y = resultSet.getString("y");
System.out.println(mdn+"\t"+start_date+"\t"+end_date+"\t"+county+"\t"+x+"\t"+y);
}
conn.close();
}
}
上面有许多警告信息,但是不影响结果
五、phonex调优
配置超时
增加超时时间,phnoex,master和子节点 都要添加
<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>
预分区
方法一
在创建表的时候,根据指定主键要分区的值
CREATE TABLE IF NOT EXISTS STUDENT (
id VARCHAR NOT NULL PRIMARY KEY,
name VARCHAR,
age BIGINT,
gender VARCHAR ,
clazz VARCHAR
)split on('1500100615','1500100721','1500100742') ;
方法二
加盐:在创建表的时候指定salting。
在rowkey前面加上一个随机的前缀
CREATE TABLE IF NOT EXISTS STUDENT (
id VARCHAR NOT NULL PRIMARY KEY,
name VARCHAR,
age BIGINT,
gender VARCHAR ,
clazz VARCHAR
)salt_buckets=4;
优点:不需要知道rowkey的分步情况
缺点:不能在hbase中根据rowkey对数据进行查询和修改
rowkey的设计
- rowkey按字典升序排列,如果想要倒叙排列,可以采用大数减小数的方法
- rowkey尽量不要太长,因为每个列中也存有rowkey的信息,rowkey太长,会导致数据量很大
- rowkey的设计原则
- 长度原则
- 散列原则
- 唯一原则
in memory
- 创建表的时候,可以通过HColumnDescriptor.setInMemory(true)将表放到 RegionServer的缓存中,保证在读取的时候被cache命中。
version
- 创建表的时候,可以通过HColumnDescriptor.setMaxVersions(int maxVersions)设置 表中数据的最大版本,如果只需要保存最新版本的数据,那么可以设置 setMaxVersions(1)。