1. 如何映射一个Phoenix的表到一个Hbase的表?

  你可以通过Create table/create view DDL语句在一个已经存在的hbase表上创建一个Phoenix表或者视图。对于Createtable来说,我们将创建任何元数据(表,列族),这些之前都是不存在的。我们也将对于每行记录添加一个空的key值,以便查询时按照我们的方式(不需要在scan过程中对所有的列进行投影)。

  另外需要注意的是,这些序列化的字节的方式必须匹配在Phoenix中序列化字节的方式。对于Varchar,Char和Unsigned_*类型,我们使用HBase字节的方法。Char字节仅仅为单个字节,Unsigned类型的值大于或等于0。

  如果创建一个HBase的表,如下:

    create 't1', {NAME => 'f1', VERSIONS=> 5}

    你有一个HBase的表,表名为t1,列族为f1。请记住,在HBase里面,你不能模仿这KeyValues 或者行键的结构,你在Phoenix中指定的信息是建立在表和列族之上的。

  因此在Phoenix中,你可以创建一个对应的视图,如下:

    CREATE VIEW "t1" ( pk VARCHAR PRIMARY KEY, "f1".val VARCHAR );

    pk列定义了你的行键的类型为VARCHAR类型,"f1".val列定义了你的HBase表包含KeyValues ,包含一个列族和列修饰符"f1".val,并且他们的值是Varchar类型的。

  如果你创建HBase表时,都使用大写名称,如下:

    create 'T1', {NAME => 'F1', VERSIONS=> 5}

  你可以创建对应的Phoenix视图,可以不需要双引符号:

    CREATE VIEW t1 ( pk VARCHAR PRIMARY KEY,f1.val VARCHAR )

  或者你创建一个新的HBase表,仅仅让Phoenix为你如下的一切事情(根本不需要使用HBase shell):

    CREATE TABLE t1 ( pk VARCHAR PRIMARY KEY,val VARCHAR )

  这里补充一点Family Column:

    如果在Phoenix SQL中创建table时为qualifier指定了family,如下:

      CREATE TABLE "example" (my_pk bigint notnull, m1.col varchar(50), m2.col varchar(50), m3.col varchar(50) constraint pk primary key (my_pk)) ;

  Phoenix primary key 与HBase rowkey 的关系:

  在创建phoenix table时,必须指定一个primary key,但是这个主键我们不一定用到。如果我们想在用Phoenix创建table时,让Phoniex的主键自动地与HBase的rowkey对应起来,则可以用以下方式来创建:

  create table"{空间名:表名}"  ("pk"varchar primary key, "{列1}" varchar, "{列2}" varchar, "{列3}" varchar)  salt_buckets=10;

  这样,Phoniex的主键(名为pk)就自动地与HBase的rowkey对应起来了。

  注:

  (1)自己定义的HBase中的 HTableName,ColumnFamily,以及Column,需要和Phoenix中保持一致。(最好都用大写)

  (2)Phoenix操作HBase,我们有两种方式,创建表和创建视图。

  这两种方式的区别如下:

    创建表的话,可读可写,就可以对HBase进行插入,查询,删除操作。

    创建视图的话,是只读的,一般就只可以进行查询操作

    删除Phoenix中表时,会将HBase对应的表删掉。但是删除Phoenix视图操作,却不会影响HBase原始表的结构。

    因为使用Phoenix,创建表后,会自动和HBase建立关联映射。当你使用Phoenix删除和HBase之间的关系时,就会将HBase中的表也删掉了。所以用视图,会对原始的HBase表影响小一些。

2. 优化Phoenix有哪些提示?

  2.1   使用Salting方式提升读写性能

    Salting能够通过预分区(pre-splitting)数据到多个region中来显著提升读写性能。

    Salting 翻译成中文是加盐的意思,本质是在hbase中,rowkey的byte数组的第一个字节位置设定一个系统生成的byte值,这个byte值是由主键生成rowkey的byte数组做一个哈希算法,计算得来的。Salting之后可以把数据分布到不同的region上,这样有利于phoenix并发的读写操作。

    CREATE TABLE TEST (HOST VARCHAR NOT NULL PRIMARY KEY, DESCRIPTION  VARCHAR) SALT_BUCKETS=16;

  注:

  (1)理性情况下,对于拥有四核CPUs的16个RegionServer的HBase集群来说,选择salt buckets在32-64个以获取较好的性能。Salt bucket的个数必须在1-256之间。

  (2)这里说明一下Salted Tables

    为了避免读写HBase表数据时产生hot-spot问题,我们使用Phoenix来创建表时可以采用salted table。

    salted table可以自动在每一个rowkey前面加上一个字节,这样对于一段连续的rowkeys,它们在表中实际存储时,就被自动地分布到不同的region中去了。当指定要读写该段区间内的数据时,也就避免了读写操作都集中在同一个region上。

    简而言之,如果我们用Phoenix创建了一个saltedtable,那么向该表中写入数据时,原始的rowkey的前面会被自动地加上一个byte(不同的rowkey会被分配不同的byte),使得连续的rowkeys也能被均匀地分布到多个regions。

  创建salted table:

    CREATE TABLE "test:salted" (pk VARCHAR PRIMARY KEY, c1 VARCHAR, c2 VARCHAR, c3 VARCHAR) SALT_BUCKETS=5;

  上述语句创建了一个名为"test:salted"的table(HBase中事先要创建名为test的namespace),SALT_BUCKETS=5 说明该salted table由5个bucket组成(必须在1~256之间)。

  上面在创建table时,没有指定family,只指定了qualifier(c1, c2, c3),因此在HBase shell向表salted写入数据时,column name 要写成'0:[qualifier]'(如'0:c1'),否则HBase会报错。

  另外,创建salted table需要注意两点:

    A.   创建salted table后,应该使用Phoenix SQL来读写数据,而不要混合使用Phoenix SQL和HBase API

    B.   如果通过Phoenix创建了一个salted table,那么只有通过Phoenix SQL插入数据才能使得被插入的原始rowkey前面被自动加上一个byte,通过HBase shell插入数据无法prefix原始的rowkey

  2.2 Pre-split

    Salting能够自动的设置表预分区,但是你得去控制表是如何分区的,所以在建phoenix表时,可以精确的指定要根据什么值来做预分区,比如:

    CREATE TABLE TEST (HOST VARCHAR NOT NULL PRIMARY KEY, DESCRIPTION VARCHAR) SPLIT ON ('CS','EU','NA');

  2.3 使用多列族

    列族包含相关的数据都在独立的文件中,在Phoenix设置多个列族可以提高查询性能。例如:

    CREATE TABLE TEST (MYKEY VARCHAR NOT NULL PRIMARY KEY, A.COL1 VARCHAR,A.COL2 VARCHAR, B.COL3 VARCHAR);

  2.4 使用压缩

    在数据量大的表上使用压缩算法来提高性能。

    例如:

    CREATE TABLE TEST (HOST VARCHAR NOT NULL PRIMARY KEY, DESCRIPTION VARCHAR) COMPRESSION='GZ';

  2.5 创建二级索引

    下面将会介绍。

  2.6 优化HBase集群参数

    请参考HBase官方详细介绍:http://hbase.apache.org/book.html#performance

  2.7 优化Phoenix参数

    请参考官网介绍:http://phoenix.apache.org/tuning.html

3. 如何在表上创建二级索引?

  从Phoenix 2.1版本开始,Phoenix支持可变和不可变(数据插入后不再更新)数据建立二级索引。Phoenix 2.0版本仅支持在不可变数据建立二级索引。

  示例:

  3.1   创建表

    不可变表:create table test (mykey varchar primary key, col1 varchar,col2 varchar) IMMUTABLE_ROWS=true;

    可变表:create table test (mykey varchar primary key, col1 varchar,col2 varchar);

  3.2   在col2创建索引

    create index idx on test (col2);

  3.3   在col1和一个覆盖列col2上创建索引

    create index idx on test (col1) include (col2);

  在test表中upsert数据,Phoenix查询优化器将选择使用合适的索引。你可以使用explain plan进行查看(http://phoenix.apache.org/language/index.html#explain)。当然你也可以使用hint(http://phoenix.apache.org/language/index.html#hint)方式指定一个需要使用的索引。

4. 为什么我的二级索引没有被使用?

  除非所有查询使用的列被索引或者覆盖列,否则二级索引不会被使用。所有列组成数据表的主键将被包含在索引中。

  例子:

  创建表:

    create table usertable (id varchar primary key,firstname varchar, lastname varchar);

    create index idx_name on usertable (firstname);

  这里创建二级索引时报错了如下:

Java.sql.SQLException: ERROR 1029 (42Y88):Mutable secondary indexes must have the hbase.regionserver.wal.codec propertyset to org.apache.Hadoop.hbase.regionserver.wal.IndexedWALEditCodec in thehbase-sites.xml of every region server. tableName=IDX

  根据错误日志,需要在RegionServer每个节点的hbase-site.xml中配置支持可变的二级索引的配置项:

  <property>

    <name>hbase.regionserver.wal.codec</name>

    <value> org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>

  </property>

  <property>

    <name>hbase.region.server.rpc.scheduler.factory.class</name>

    <value>org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory</value>

    <description>Factory to create the Phoenix RPC Scheduler that usesseparate queues for index and metadata updates</description>

  </property>

  <property>

    <name>hbase.rpc.controllerfactory.class</name>

    <value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory</value>

    <description>Factory to create the Phoenix RPCScheduler that uses separate queues for index and metadataupdates</description>

  </property>

  <property>

    <name>hbase.coprocessor.regionserver.classes</name>

    <value>org.apache.hadoop.hbase.regionserver.LocalIndexMerger</value>

  </property>

  在每一个Master的hbase-site.xml中加入如下的属性:

  <property>

    <name>hbase.master.loadbalancer.class</name>

    <value>org.apache.phoenix.hbase.index.balancer.IndexLoadBalancer</value>

  </property>

  <property>

    <name>hbase.coprocessor.master.classes</name>

    <value>org.apache.phoenix.hbase.index.master.IndexMasterObserver</value>

  </property>

  查询:

    select id, firstname, lastname from usertablewhere firstname = 'foo';

  请注意这个查询不会用到索引,因为lastname不是被索引或者覆盖列的部分。我们可以查询执行计划进行验证,比如:

  0:jdbc:phoenix:SZB-L0023780:2181:/hbase114> explain select id, firstname,lastname from usertable where firstname = 'foo';

  +------------------------------------------------------------------------------------------------------------------+

  |                                PLAN                                 |

  +------------------------------------------------------------------------------------------------------------------+

  | CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBINFULL SCAN OVER USERTABLE     |

  |    SERVER FILTER BY FIRSTNAME = 'foo'                                   |

  +------------------------------------------------------------------------------------------------------------------+

  为了修改这个创建索引的问题,要么对lastname创建索引,要么创建覆盖索引,如下:

    drop index idx_name on usertable;

    create index idx_name on usertable (firstname) include(lastname);

  我们再次验证一下

    0: jdbc:phoenix:SZB-L0023780:2181:/hbase114>explain select id, firstname, lastname from usertable where firstname = 'foo';

    +-------------------------------------------------------------------------------------------------------------------------+

    |                                PLAN                                     |

    +-------------------------------------------------------------------------------------------------------------------------+

    | CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBINRANGE SCAN OVER IDX_NAME ['foo']  |

    +------------------------------------------------------------------------------------------------------------------------+

    根据执行计划的结果,可以看出使用了IDX_NAME索引。

5. Phoenix有多快,为什么如此之快?

  全表扫描100M的数据量通过在20s完成(中等大小集群的窄表)。如果查询时增加一些索引列过滤的话,时间会减低到毫秒级别。

  为什么Phoenix全表扫描还那么快?

  (1)Phoenix使用region边界拆分查询,并且客户端使用配置的线程数进行并行查询。

  (2)聚合操作将在服务端的协处理器中完成

6. 为什么我的查询不走Range scan?

  首先看一下创建表的语句:

    CREATE TABLE TEST (pk1 char(1) not null, pk2char(1) not null, pk3 char(1) not null, non_pk varchar CONSTRAINT PK PRIMARY KEY(pk1, pk2, pk3));

  Range Scan意味着仅会扫描表的一部分子集的行记录。如果你使用主键约束中的首个列开头的话,就会使用Range Scan方式。

  比如下面的查询将会使用Full Scan方式:

    select * from test where pk2='x' and pk3='y';

  而下面的查询将会使用Range Scan方式:

    select * from test where pk1='x' and pk2='y';

  DEGENERATE SCAN意味着一个查询不可能返回任何行记录。

  FULL SCAN意味着将扫描表的所有行记录。

  SKIP SCAN意味着要么表的部分子集,要么扫描表的所有记录,然而它将根据过滤条件跳过大量的记录。在一些情况下,当你的leading primary key columns的基数比较低时,它往往比FULL SCAN更有效率。

7. 我应该缓存Phoenix JDBC连接吗?

  No,没有必要缓存Phoenix JDBC连接。

  Phoenix的连接对象不同于绝大部分的JDBC连接,因为其是底层是HBase连接的。如果Phoenix连续被重用,有可能之前使用的用户留下的HBase连接状态并不是良好的,所以最好还是新创建一个Phoenix连接,可以避免潜在的问题。

8. 为什么执行upsert操作时,Phoenix添加一个empty/dummy的KeyValue?

  我们先来看一下示例:

    create table HADOOP (rk Integer primarykey,info.name varchar ,info.score Integer );

    upsert into HADOOP values(1,'Hadoop',90);

  查看HBase的表内容:

    hbase(main):037:0> scan 'HADOOP'

    ROW                 COLUMN+CELL

     \x80\x00\x00\x01   column=INFO:NAME, timestamp=1472634053972,value=Hadoop

    \x80\x00\x00\x01   column=INFO:SCORE, timestamp=1472634053972,value=\x80\x00\x00Z

     \x80\x00\x00\x01   column=INFO:_0, timestamp=1472634053972,value=x

  我们再通过Phoenix插入一行记录:

    upsert into HADOOP values(2,'Spark',95);

  再次查看HBase的表内容:

    hbase(main):037:0> scan 'HADOOP'

    ROW                 COLUMN+CELL

    \x80\x00\x00\x01   column=INFO:NAME, timestamp=1472634053972, value=Hadoop

    \x80\x00\x00\x01   column=INFO:SCORE, timestamp=1472634053972,value=\x80\x00\x00Z

    \x80\x00\x00\x01   column=INFO:_0, timestamp=1472634053972,value=x

     \x80\x00\x00\x02   column=INFO:NAME, timestamp=1472634140841,value=Spark

     \x80\x00\x00\x02   column=INFO:SCORE, timestamp=1472634140841,value=\x80\x00\x00_

     \x80\x00\x00\x02   column=INFO:_0, timestamp=1472634140841,value=x

  可以发现针对每一行,都会增加一列_0

    empty/dummy的KeyValue(列修饰符_0)是需要的,为了确保给定的列能够被所有行访问,这是从提升查询性能方面考虑的。

  据你所知,数据是以KeyValues形式存储在HBase中的,意味着全部的行键存储着每个列值。这也意味着除非至少有一个列存储,否则行键根本不存储数据。

  这部分内容,后续我们有时间从源码层面给大家说明一下。

9. 如何将带有Schema的表移到namespace中?

  前提条件:需要4.8以及以上版本去映射表到namespace。具体相关配置请查看官方文档:http://phoenix.apache.org/tuning.html

  对于基于Kerberos的环境来说,运行的用户需要有admin权限创建namespace。

  表将仅仅映射到名称为schema_name的namespace中,目前不支持迁移已经存在的表到不同的schema或者namespace。

  我们来看一下测试过程:

    [kylin@SZB-L0023780apache-phoenix-4.8.0-HBase-1.1-bin]$ bin/psql.py SZB-L0023780:2181:hbase114 -mmyworld.HADOOP

    Starting upgrading table:myworld.HADOOP...please don't kill it in between!!

    java.lang.IllegalArgumentException:phoenix.schema.isNamespaceMappingEnabled is not enabled!!

     atorg.apache.phoenix.util.UpgradeUtil.upgradeTable(UpgradeUtil.java:1717)

    atorg.apache.phoenix.util.PhoenixRuntime.main(PhoenixRuntime.java:221)

  可以看到需要设置参数允许namespace mapping。

  <property>

    <name>phoenix.schema.isNamespaceMappingEnabled</name>

    <value>true</value>

  </property>

  这里一定要注意:如果设置为true,创建的带有schema的表将映射到一个namespace,这个需要客户端和服务端同时设置。一旦设置为true,就不能回滚了。旧的客户端将无法再正常工作。所以建议大家都查看官方文档,确定后再进行设置。

  示例:将表“table_name”移动到“schema_name”的namespace中。

  bin/psql.py <zookeeper> -m<schema_name>.<table_name>

Apache Phoenix基本操作-2的更多相关文章

  1. Apache Phoenix基本操作-1

    本篇我们将介绍phoenix的一些基本操作. 1. 如何使用Phoenix输出Hello World? 1.1 使用sqlline终端命令 sqlline.py SZB-L0023780:2181:/ ...

  2. [saiku] 使用 Apache Phoenix and HBase 结合 saiku 做大数据查询分析

    saiku不仅可以对传统的RDBMS里面的数据做OLAP分析,还可以对Nosql数据库如Hbase做统计分析. 本文简单介绍下一个使用saiku去查询分析hbase数据的例子. 1.phoenix和h ...

  3. Apache Phoenix JDBC 驱动和Spring JDBCTemplate的集成

    介绍:Phoenix查询引擎会将SQL查询转换为一个或多个HBase scan,并编排运行以生成标准的JDBC结果集. 直接使用HBase API.协同处理器与自己定义过滤器.对于简单查询来说,其性能 ...

  4. phoenix 报错:type org.apache.phoenix.schema.types.PhoenixArray is not supported

    今天用phoenix报如下错误: 主要原因: hbase的表中某字段类型是array,phoenix目前不支持此类型 解决方法: 复制替换phoenix包的cursor文件 # Copyright 2 ...

  5. Mapreduce atop Apache Phoenix (ScanPlan 初探)

    利用Mapreduce/hive查询Phoenix数据时如何划分partition? PhoenixInputFormat的源码一看便知: public List<InputSplit> ...

  6. org.apache.phoenix.exception.PhoenixIOException: SYSTEM:CATALOG

    Error: SYSTEM:CATALOG (state=08000,code=101)org.apache.phoenix.exception.PhoenixIOException: SYSTEM: ...

  7. phoenix连接hbase数据库,创建二级索引报错:Error: org.apache.phoenix.exception.PhoenixIOException: Failed after attempts=36, exceptions: Tue Mar 06 10:32:02 CST 2018, null, java.net.SocketTimeoutException: callTimeou

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...

  8. apache phoenix 安装试用

    备注:   本次安装是在hbase docker 镜像的基础上配置的,主要是为了方便学习,而hbase搭建有觉得   有点费事,用镜像简单.   1. hbase 镜像 docker pull har ...

  9. How to use DBVisualizer to connect to Hbase using Apache Phoenix

    How to use DBVisualizer to connect to Hbase using Apache Phoenix Article DB Visualizer is a popular ...

随机推荐

  1. Win7 sql2005附加数据库失败 错误5120

      错误信息如下: 标题: Microsoft SQL Server Management Studio Express------------------------------ 附加数据库 对于 ...

  2. [Spring MVC]学习笔记--FreeMarker的使用

    还是先贴出该例子存于github上的位置 https://github.com/lemonbar/spring-mvc-freemarker Sping-Framework 的官方文档简单列出了在sp ...

  3. 【RSS】我的RSS使用介绍

    早就想写一个有关RSS的文章,一直没时间,今天刚好被现DL说了一波,那就先整理出一篇教程吧.后续说不定还有分享: 分享相关PPT: 一.我使用的服务: Feedly:https://feedly.co ...

  4. standard pbr(三)-BRDF

    // Default BRDF to use: #if !defined (UNITY_BRDF_PBS) // allow to explicitly override BRDF in custom ...

  5. Cassandra代替Redis?(转)

    原文:Cassandra代替Redis? 最近用Cassandra的又逐渐多了,除了之前的360案例,在月初的QCon Shanghai 2013 篱笆网也介绍了其使用案例.而这篇百万用户时尚分享网站 ...

  6. struts2+Oracle实现管理员查看用户提交的意见功能

    说一下需求:这个功能类似于邮件功能,当用户在站点中提交一些建议及意见后.后台将其存入到Oracle数据库中.然后管理员登录站点,会看到还没有读过以及读过的意见及建议,并能够将未读过的意见及建议标记为已 ...

  7. postman 编码加密汇总

    1.MD5加密 /*加密方式:将 请求头的user-agent内容+请求方式+当前时间+(Base64)请求body中的stacode参数 拼接后得到的字符串进行MD5加密*/ //1.获取reque ...

  8. nodejs get请求

    const http = require('http'); http.get('http://192.168.1.6:8080/getDemo?msg=12', (res) => { const ...

  9. PyQt4 颜色选择,字体选择代码

    # -*- coding: utf-8 -*- """ ------------------------------------------------- File Na ...

  10. MFC实现文字随鼠标移动

    1 实验介绍 此实验是在刚开始接触MFC时做的.它要求实现的功能如下: 文字跟随鼠标动态移动(跟随移动方式自定) 修改图标为自己喜欢的图标 修改窗口标题 修改文档名称 可以用菜单项选定指定的颜色显示文 ...