Phoenix与HBase中的表是独立的,两者之间没有必然的关系。
如果要通过Phoenix操作Hbase中的表,则需要在Phoenix的系统表中加入Hbase的相关信息。实际上Phoenix也是通过这种形式来查询Hbase中的表的,这样子看来Phoenix有点像数据表中的Hmaster,cuiyaonan2000@163.com
Phoenix创建表时会自动调用HBase客户端创建相应的表(使用hbase client api),创建八张系统表(这些表也是创建在HBase中的表,只是所属对象是Phoenix):
- SYSTEM.CATALOG(其中SYSTEM.CATALOG表用于存放Phoenix创建表时的元数据,即用于存储记录Hbase中的表,如此才能操作关联Hbase)
- SYSTEM.FUNCTION
- SYSTEM.LOG
- SYSTEM.SEQUENCE
- SYSTEM.STATS
- SYSTEM.CHILD_LINK
- SYSTEM.TASK
并且在SYSTEM.CATALOG系统表中记录Phoenix创建表时的元数据:
- 主键的值对应HBase的RowKey
- 非主键的列对应HBase的Column
- 列族不指定时为0,且列会进行编码
- 如果是通过Phoenix创建的表,那么必须通过Phoenix客户端来对表进行操作,因为通过Phoenix创建的表其非主键的列会进行编码---------------这样我们的代码中就需要维护2个客户端,A:phoenix客户端 B:Hbase客户端
#查看所有的表
!table
#查看指定表的字段信息
!describe 表名
#之前输入的命令
!history
#数据库的配置信息
!dbinfo
# 查看指定表上的索引
!index 表名
#查看其他操作
!help
#退出phoenix shell
!quit
基本语法
- Phoenix中的sql,表名和字段如果不加双引号,则自动转换成大写
- 字符串使用单引号,表名和字段名使用双引号
- 如果没有指定列族,默认使用列族0
- 主键对应hbase的rowkey,联合主键的意思其实也很容易理解
CREATE TABLE IF NOT EXISTS us_population (
state CHAR(2) NOT NULL,
city VARCHAR NOT NULL,
population BIGINT
CONSTRAINT my_pk PRIMARY KEY (state, city)
);
加盐建表
通过在创建表时指定SALE_BUCKETS来实现将表中的数据预分割到多个Region中,有利于提高读取数据的性能。
注:SALT_BUCKETS的值范围在(1 ~ 256)
过程是:
- 将RowKey进行散列,取余数
- 把得到的余数的byte值插入到RowKey的第一个字节中,因为是聚合索引,且该余数又是第一位,所以是有序的。
- 并通过预定义每个Region的Start Key和End Key,将数据分散存储到不同的Region中--------------这里了需要人为去控制region开始和结束
create table test(h
ost varchar not null primary key,
description varchar
)salt_buckets=16;
根据rowkey内容建表预分区
Salting能够自动的设置表预分区,但是你得去控制表是如何分区的, 所以在建phoenix表时,可以精确的指定要根据什么值来做预分区,
CREATE TABLE IF NOT EXISTS us_population (
state CHAR(2) NOT NULL,
city VARCHAR NOT NULL,
population BIGINT
CONSTRAINT my_pk PRIMARY KEY (state, city)
)SPLIT ON('CS','EU','NA');
建表的同时创建列族(列族是一定要有的,要不然hbase就失去了意义)
创建列族其实很简单,只需要 满足格式:列簇.列名 系统就会自动创建列族。cuiyoanan2000@163.com
create table test (
mykey varchar not null primary key,
a.col1 varchar,
a.col2 varchar,
b.col3 varchar
);
建表时指定压缩
可选的压缩方式包括
- GZip
- Snappy
- Lzo
- 等等
create table test (
host varchar not null primary key,
description varchar
) compression='snappy';
删除表
--删除表
drop table tb;删除表
drop table if exists tb;
drop table my_schema.tb;
--删除表的同时产出该表上的索引
drop table my_schema.tb cascade;
创建视图
create view "my_hbase_table"( k varchar primary key, "v" unsigned_long) default_column_family='a';
create view my_view ( new_col smallint ) as select * from my_table where k = 100;
create view my_view_on_view as select * from my_view where new_col > 70;
create view v1 as select * from test where description in ('s1','s2','s3');
删除视图
drop view my_view;
drop view if exists my_schema.my_view;
drop view if exists my_schema.my_view cascade;
插入或更新数据
在Phoenix中是没有Insert语句的,取而代之的是Upsert语句。
另外由于HBase的主键设计,相同rowkey的内容可以直接覆盖,这就变相的更新了数据,所以插入与跟新是一样的
Upsert有两种用法:
- upsert into :用于单挑插入
- upsert select :用于插入其它表的数据
-
如果主键的值重复,那么进行更新操作,否则插入一条新的记录
-
在进行更新时,没有更新的列保持原值,在进行插入时,没有插入的列为null
-
在使用UPSERT时,主键的列不能为空(包括联合主键)------如果是自增主键呢
-- upawer into
upsert into tb values('ak','hhh',222);
upsert into tb(stat,city,num) values('ak','hhh',222);
--upsert select
upsert into tb1 (state,city,population) select state,city,population from tb2 where population < 40000;
upsert into tb1 select state,city,population from tb2 where population > 40000;
upsert into tb1 select * from tb2 where population > 40000;
删除数据
DELETE FROM us_population WHERE state = 'NA';
#清空表
delete from tb;
查询数据
- 在进行查询时,支持:ORDER BY、GROUP BY、LIMIT、JOIN、UNION ALL、GROUP BY、ORDER BY、LIMIT
- 同时Phoenix提供了一系列的函数,其中包括COUNT()、MAX()、MIN()、SUM()等,具体的函数列表可以查看:http://phoenix.apache.org/language/functions.html
- 不管条件中的列是否是联合主键中的,Phoenix一样可以支持。
通过实例感觉phoenix更像是mysql的语法
select * from test limit 1000;
select * from test limit 1000 offset 100;
select full_name from sales_person where ranking >= 5.0 union all select reviewer_name from customer_review where score >= 8.0
创建索引(HBase里面只有rowkey作为一级索引)
Global indexes(全局索引):适用于读多写少场景
通过维护全局索引表,所有的更新和写操作都会引起索引的更新,写入性能受到影响。 在读数据时,Phoenix SQL会基于索引字段,执行快速查询
- CREATE INDEX 索引名称 ON 表名(列名)
把关注的数据字段也附在索引表上,只需要通过索引表就能返回所要查询的数据(列), 所以索引的列必须包含所需查询的列(SELECT的列和WHRER的列)
- CREATE INDEX 索引名称 ON 表名(列名) INCLUDE(列名) -----------------即如果查询结果包含了include后面的字段,则查询效率会更快,应为这就是覆盖索引
在数据写入时,索引数据和表数据都会存储在本地。
在数据读取时, 由于无法预先确定region的位置,所以在读取数据时需要检查每个region(以找到索引数据),会带来一定性能(网络)开销。
不是索引字段索引表也会被使用,索引数据和真实数据存储在同一台机器上
- create local index index3_l_name on hao1 (name);
索引不局限于列,支持任意的表达式来创建索引。
重建索引索引重建是把索引表清空后重新装配数据。
- alter index 索引名 on 表名 rebuild
注意:创建索引跟创建表一样支持 :1加盐分区 2根据值分区 3分区是指不同的region
create index my_idx on sales.opportunity(last_updated_date desc);
create index my_idx on log.event(created_date desc) include (name, payload) salt_buckets=10;
create index if not exists my_comp_idx on server_metrics ( gc_time desc, created_date desc )
data_block_encoding='none',versions=?,max_filesize=2000000 split on (?, ?, ?);
create index my_idx on sales.opportunity(upper(contact_name));
create index test_index on test (host) include (description);
与现有Hbase表关联
首先在hbase中创建表
#首先在hbase创建一个表
hbase(main):017:0> create 'cuiyaonan2000' ,'columnfamily.column'
#插入一条记录
hbase(main):020:0> put 'cuiyaonan2000' ,'row1','columnfamily:column','value1'
#查看该表结构
hbase(main):019:0> describe 'cuiyaonan2000'
#查看该表中的记录
hbase(main):023:0> scan 'cuiyaonan2000'
可以看到cuiyaonan2000表中的主键字段名称为ROW
- 表名必须和HBase表名一致即可
- 字段也应该一样
- hbase之前插入的记录并不能再phoenix中查询出来
- 关联后从phoenix插入的记录,可以在hbase中查询出来
CREATE TABLE "cuiyaonan2000"(
"ROW" varchar PRIMARY key ,
"columnfamily"."column" varchar
);
#注意表名、字段都用双引号,字符串用单引号
upsert into "cuiyaonan2000"("ROW","columnfamily"."column")values('ROW2','from phoen55ix');
插入后在hbase shell中可以看到插入结果----------------注意列族未被phoenix编码,仅有列明被编码。这种操作让hbase认为这是同一列族的不同列cuiyaonan2000@163.com
构建一份“索引”的映射关系,存储在另一张hbase表或者其他DB里面。
-
优点: 基于Coprocessor的方案,从开发设计的角度看, 把很多对二级索引管理的细节都封装在的Coprocessor具体实现类里面, 这些细节对外面读写的人是无感知的,简化了数据访问者的使用。
-
缺点: 但是Coprocessor的方案入侵性比较强, 增加了在Regionserver内部需要运行和维护二级索引关系表的代码逻辑等,对Regionserver的性能会有一定影响。
选择不基于Coprocessor开发,自行在外部构建和维护索引关系也是另外一种方式。
常见的是采用底层基于Apache Lucene的Elasticsearch(下面简称ES)或Apache Solr ,来构建强大的索引能力、搜索能力, 例如支持模糊查询、全文检索、组合查询、排序等