文章目录

  • 一、基本指令
  • 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中运行的一段代码,用于自动处理索引

ESXi 磁盘的分区删除 esxi分区格式_hadoop

2)删除表

ESXi 磁盘的分区删除 esxi分区格式_hbase_02


删除所有在phonex中创建的表,观察HBASE中是否还有

ESXi 磁盘的分区删除 esxi分区格式_java_03


发现hbase中也没有了

3)插入数据

ESXi 磁盘的分区删除 esxi分区格式_java_04

4)查询数据

查询全部

ESXi 磁盘的分区删除 esxi分区格式_hadoop_05


虽然也可以分组,汇总,但是不适合该操作,当数据多的时候,数据非常慢,计算量也很大,可能会导致hbase集群崩溃

ESXi 磁盘的分区删除 esxi分区格式_java_06

5)删除数据

支持where操作,速度快

ESXi 磁盘的分区删除 esxi分区格式_hbase_07

6)退出命令行

!quit

二、映射

  • 默认情况下,直接在hbase中创建的表,通过phoenix是查看不到的
  • 如果需要在phoenix中操作直接在hbase中创建的表,则需要在phoenix中进行表的映射
  • 映射方式有两种:视图映射和表映射。(视图映射,表映射)ou
  • 为表创建映射时,需保证,表是结构化的,不能为非结构化和半结构化的表创建映射

1)视图映射

  • Phoenix创建的视图是只读的,所以只能用来做查询

在hbase中找一个student表,在phonex中为该表创建视图映射,由于原表中已经有了一个STUDENT,在phonex中会自动将表名转为大写,便于区分,这里加上引号创建student映射,但是注意,查询的时候也需要加上引号

首先在HBASE中查看student的列族和列的名字,了解表的结构

ESXi 磁盘的分区删除 esxi分区格式_java_08

创建视图

在phonex中创建视图映射,和创建表一样必须指定主键,这里的主键就是HBASE表中的rowkey,字段名可以任意起,这里为id

create view "student" (
id varchar primary key,
"info"."age" varchar,
"info"."clazz"varchar,
"info"."name"  varchar,
"info"."sex" varchar
);

ESXi 磁盘的分区删除 esxi分区格式_ESXi 磁盘的分区删除_09

查询视图

ESXi 磁盘的分区删除 esxi分区格式_hbase_10

删除视图

drop view “student”;

ESXi 磁盘的分区删除 esxi分区格式_数据_11


HBASE中依然存在,因为视图是只读的

ESXi 磁盘的分区删除 esxi分区格式_ESXi 磁盘的分区删除_12

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;

ESXi 磁盘的分区删除 esxi分区格式_数据_13


方法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;

ESXi 磁盘的分区删除 esxi分区格式_数据_14


hbase中也有该表的信息

ESXi 磁盘的分区删除 esxi分区格式_数据_15

删除表

ESXi 磁盘的分区删除 esxi分区格式_hbase_16


hbase中也被删除,如果被更改,hbase中也被更改

ESXi 磁盘的分区删除 esxi分区格式_数据_17

3)视图映射和表映射的区别

  • 相比于直接创建映射表,视图的查询效率会低,原因是:创建映射表的时候,Phoenix会在表中创建一些空的键值对,这些空键值对的存在可以用来提高查询效率。
  • 视图映射是只读的操作,不会对原表进行修改,表映射和原表关联,对表映射的更改,也会影响hbase中的表

三、二级索引

  • 对于Hbase,如果想精确定位到某行记录,唯一的办法就是通过rowkey查询。如果不通过rowkey查找数据,就必须逐行比较每一行的值,对于较大的表,全表扫描的代价是不可接受的。
  • 索引分为全局索引和本地索引

1)修改配置文件

关闭hbase的集群,修改配置文件
修改配置文件,设置RPC请求的超时时间。默认为60s,由于电脑性能和数据量,需要修改的长一点,RPC时间超过该值,客户端就会主动关闭socket

关闭集群

ESXi 磁盘的分区删除 esxi分区格式_ESXi 磁盘的分区删除_18


修改phonex下的hbase-site.xml

<property>
<name>phoenix.query.timeoutMs</name>
<value>500000</value>
</property>

ESXi 磁盘的分区删除 esxi分区格式_hbase_19

ESXi 磁盘的分区删除 esxi分区格式_ESXi 磁盘的分区删除_20

修改hbase下的hbase-site.xml

如果不是伪分布式,还需将该文件分别发送到子节点的对应目录下

ESXi 磁盘的分区删除 esxi分区格式_hadoop_21

<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>

ESXi 磁盘的分区删除 esxi分区格式_hbase_22

两个文件修改完后,启动集群

ESXi 磁盘的分区删除 esxi分区格式_hadoop_23

2)全局索引

  • 全局索引适合读多写少的场景。
  • 如果使用全局索引,读数据基本不损耗性能,所有的性能损耗都来源于写数据。
  • 数据表的添加、删除和修改都会更新相关的索引表(数据删除了,索引表中的数据也会删除;数据增加了,索引表的数据也会增加)、
  • 注意: 对于全局索引在默认情况下,在查询语句中检索的列如果不在索引表中,Phoenix不会使用索引表将,除非使用hint。
  • hint是一种添加注解的方式

这里个建一个数据量比较大的表,效果明显
创建表,由于手机号并非每条数据的唯一标识,需要用,联合主键,由于建表,再向表插数据,速度慢,将建表语句放入一个sql文件中,使用指令导入数据到表中

创建sql文件

ESXi 磁盘的分区删除 esxi分区格式_数据_24


上传数据

ESXi 磁盘的分区删除 esxi分区格式_ESXi 磁盘的分区删除_25


执行指令,导入数据

ESXi 磁盘的分区删除 esxi分区格式_hbase_26

进入phonex

ESXi 磁盘的分区删除 esxi分区格式_hbase_27


这是一个普通的表,查询测试时间根据mdn查询数据

ESXi 磁盘的分区删除 esxi分区格式_ESXi 磁盘的分区删除_28


根据start_data查询数据

ESXi 磁盘的分区删除 esxi分区格式_数据_29

根据end_data查询数据

ESXi 磁盘的分区删除 esxi分区格式_ESXi 磁盘的分区删除_30

以上的测试也应证了,前缀比较器比其他子串比较器要快行过滤器比列值过滤器速度快
前缀加行过滤器最快

增加索引

根据需求,为要查找的字段增加全局索引,此处以end_data为例

ESXi 磁盘的分区删除 esxi分区格式_hadoop_31


这里会多了一个索引表,hbase中也是

ESXi 磁盘的分区删除 esxi分区格式_java_32


ESXi 磁盘的分区删除 esxi分区格式_hadoop_33


查询数据,会发现没很大区别,这是因为索引没生效,查找的数据含有非索引字段的部分

ESXi 磁盘的分区删除 esxi分区格式_数据_34


只查询索引字段,时间明显减少,可见索引生效

ESXi 磁盘的分区删除 esxi分区格式_java_35


要想查询非索引字段的时候,让索引生效,可以使用加上hint的方法

加上 /*+ INDEX(DIANXIN DIANXIN_INDEX) */ 强制使用索引

ESXi 磁盘的分区删除 esxi分区格式_java_36


ESXi 磁盘的分区删除 esxi分区格式_hbase_37

删除索引

drop index DIANXIN_INDEX on dianxin;

ESXi 磁盘的分区删除 esxi分区格式_hadoop_38

创建多列索引

CREATE INDEX DIANXIN_INDEX1 ON DIANXIN (end_date,start_date);

ESXi 磁盘的分区删除 esxi分区格式_数据_39


查询索引列,索引生效

ESXi 磁盘的分区删除 esxi分区格式_hadoop_40


此处只能where后面只能筛选这个end_date的或者end_date和start_date才会生效,用start_date不生效

ESXi 磁盘的分区删除 esxi分区格式_java_41


ESXi 磁盘的分区删除 esxi分区格式_ESXi 磁盘的分区删除_42


ESXi 磁盘的分区删除 esxi分区格式_数据_43

查询含非索引的列和非key值的列

ESXi 磁盘的分区删除 esxi分区格式_hadoop_44


使索引生效

ESXi 磁盘的分区删除 esxi分区格式_hbase_45

3)本地索引

  • 本地索引适合写多读少的场景,或者存储空间有限的场景。和全局索引一样,Phoenix也会在查询的时候自动选择是否使用本地索引。
  • 本地索引因为索引数据和原数据存储在同一台机器上,避免网络数据传输的开销,所以更适合写多的场景
  • 由于无法提前确定数据在哪个Region上,所以在读数据的时候,需要检查每个Region上的数据从而带来一些性能损耗。
  • 注意:对于本地索引,查询中无论是否指定hint或者是查询的列是否都在索引表中,都会使用索引表。

创建索引

ESXi 磁盘的分区删除 esxi分区格式_java_46


ESXi 磁盘的分区删除 esxi分区格式_java_47


但在HBASE中只有一个索引表,本地索引和数据表在一个表里

ESXi 磁盘的分区删除 esxi分区格式_java_48

观察全局索引和本地索引的表的不同

本地索引=》数据表

ESXi 磁盘的分区删除 esxi分区格式_数据_49


全局索引

ESXi 磁盘的分区删除 esxi分区格式_hadoop_50


测试

查询索引字段

select grid_id from dianxin where grid_id='117285031820040’

索引生效

ESXi 磁盘的分区删除 esxi分区格式_ESXi 磁盘的分区删除_51


查询非索引的字段

select * from dianxin where grid_id='117285031820040’

索引生效

ESXi 磁盘的分区删除 esxi分区格式_java_52

4)覆盖索引

  • 覆盖索引是把原数据存储在索引数据表中,这样在查询时不需要再去HBase的原表获取数据就,直接返回查询结果。
  • 注意:查询是 select 的列和 where 的列都需要在索引中出现。

创建索引

CREATE INDEX DIANXIN_INDEX_COVER ON DIANXIN ( x,y ) INCLUDE ( county );

ESXi 磁盘的分区删除 esxi分区格式_java_53


查询所有列不生效

select * from dianxin where x=117.288 and y =31.822;

ESXi 磁盘的分区删除 esxi分区格式_ESXi 磁盘的分区删除_54


强制让索引生效

select /*+ INDEX(DIANXIN DIANXIN_INDEX_COVER) */ * from dianxin where x=117.288 and y =31.822;

ESXi 磁盘的分区删除 esxi分区格式_数据_55


查询索引中的列,索引生效

select x,y,county from dianxin where x=117.288 and y =31.822;

ESXi 磁盘的分区删除 esxi分区格式_java_56


查询条件必须放在索引中,查询字段作为覆盖

四、java代码使用phonex

在java项目中,加入phonex对应版本的依赖
注意此处必须加入与HBASE版本对应的依赖

<dependency>
            <groupId>org.apache.phoenix</groupId>
            <artifactId>phoenix-core</artifactId>
            <version>4.15.0-HBase-1.4</version>
        </dependency>

ESXi 磁盘的分区删除 esxi分区格式_ESXi 磁盘的分区删除_57

代码演示

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();

    }
}

上面有许多警告信息,但是不影响结果

ESXi 磁盘的分区删除 esxi分区格式_java_58

五、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)。