[Phoenix] 五、二级索引

[Phoenix] 五、二级索引

大家好,又见面了,我是全栈君。

一、概要

目前HBASE只有基于字典序的主键索引,对于非主键过滤条件的查询都会变成扫全表操作,为了解决这个问题Phoenix引入了二级索引功能。然而此二级索引又有别于传统关系型数据库的二级索引,本文将详细描述了Phoenix中二级索引功能、用法和原理。


二、二级索引

示例表如下(为了能够容易通过HBASE SHELL对照表内容,我们对属性值COLUMN_ENCODED_BYTES设置为0,不对column family进行编码):

CREATE TABLE  TEST (
   ID VARCHAR NOT NULL  PRIMARY KEY,
   COL1 VARCHAR,
   COL2 VARCHAR
  ) COLUMN_ENCODED_BYTES=0;
upsert into TEST values('1', '2', '3');

1. 全局索引

全局索引更多的应用在读较多的场景。它对应一张独立的HBASE表。对于全局索引,在查询中检索的列如果不在索引表中,默认的索引表将不会被使用,除非使用hint。

创建全局索引:

CREATE INDEX IDX_COL1 ON TEST(COL1)

通过HBASE SHELL观察生成的索引表IDX_COL1。我们发现全局索引表的RowKey存储了索引列的值和原表RowKey的值,这样编码更有利于提高查询的性能。

hbase(main):001:0> scan 'IDX_COL1'
ROW                        COLUMN+CELL
 2\x001                    column=0:_0, timestamp=1520935113031, value=x
1 row(s) in 0.1650 seconds

实际上全局索引的RowKey将会按照如下格式进行编码。
Screen_Shot_2018_03_13_at_18_04_32

  • SALT BYTE: 全局索引表和普通phoenix表一样,可以在创建索引时指定SALT_BUCKETS或者split key。此byte正是存储着salt。
  • TENANT_ID: 当前数据对应的多租户ID。
  • INDEX VALUE: 索引数据。
  • PK VALUE: 原表的RowKey。

2. 本地索引

因为本地索引和原数据是存储在同一个表中的,所以更适合写多的场景。对于本地索引,查询中无论是否指定hint或者是查询的列是否都在索引表中,都会使用索引表。

创建本地索引:

create local index LOCAL_IDX_COL1 ON TEST(COL1);

通过HBASE SHELL观察表’TEST’, 我们可以看到表中多了一行column为L#0:_0的索引数据。

hbase(main):001:0> scan 'TEST'
ROW                        COLUMN+CELL
 \x00\x002\x001            column=L#0:_0, timestamp=1520935997600, value=_0
 1                         column=0:COL1, timestamp=1520935997600, value=2
 1                         column=0:COL2, timestamp=1520935997600, value=3
 1                         column=0:_0, timestamp=1520935997600, value=x
2 row(s) in 0.1680 seconds

本地索引的RowKey将会按照如下格式进行编码:
Screen_Shot_2018_03_13_at_20_16_24

  • REGION START KEY : 当前row所在region的start key。加上这个start key的好处是,可以让索引数据和原数据尽量在同一个region, 减小IO,提升性能。
  • INDEX ID : 每个ID对应不同的索引表。
  • TENANT ID :当前数据对应的多租户ID。
  • INDEX VALUE: 索引数据。
  • PK VALUE: 原表的RowKey。

3. 覆盖索引

覆盖索引的特点是把原数据存储在索引数据表中,这样在查询到索引数据时就不需要再次返回到原表查询,可以直接拿到查询结果。

创建覆盖索引:

create  index IDX_COL1_COVER_COL2 on TEST(COL1) include(COL2);

通过HBASE SHELL 查询表IDX_COL1_COVER_COL2, 我们发现include的列的值被写入到了value中。

hbase(main):003:0> scan 'IDX_COL1_COVER_COL2'
ROW                   COLUMN+CELL
 2\x001               column=0:0:COL2, timestamp=1520943893821, value=3
 2\x001               column=0:_0, timestamp=1520943893821, value=x
1 row(s) in 0.0180 seconds

对于类似select col2 from TEST where COL1='2'的查询,查询一次索引表就能获得结果。其查询计划如下:

+--------------------------------------------------------------------------------------+-----------------+----------------+---+
|                                         PLAN                                         | EST_BYTES_READ  | EST_ROWS_READ  | E |
+--------------------------------------------------------------------------------------+-----------------+----------------+---+
| CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN RANGE SCAN OVER IDX_COL1_COVER_COL2 ['2']  | null            | null           | n |
+--------------------------------------------------------------------------------------+-----------------+----------------+---+

4. 函数索引

函数索引的特点是能根据表达式创建索引,适用于对查询表,过滤条件是表达式的表创建索引。例如:

//创建函数索引
CREATE INDEX CONCATE_IDX ON TEST (UPPER(COL1||COL2))

//查询函数索引
SELECT * FROM TEST WHERE UPPER(COL1||COL2)='23'

三、什么是Phoenix的二级索引?

Phoenix的二级索引我们基本上已经介绍过了,我们回过头来继续看Phoenix二级索引的官方定义:Secondary indexes are an orthogonal way to access data from its primary access path。通过以下例子我们再理解下这个定义。

  1. 对表TESTCOL1创建全局索引
CREATE INDEX IDX_COL1 ON TEST(COL1);
  1. 查询所有字段。
select * from TEST where COL1='2';

以上查询的查询计划如下:

+----------------------------------------------------------------+-----------------+----------------+--------------+
|                              PLAN                              | EST_BYTES_READ  | EST_ROWS_READ  | EST_INFO_TS  |
+----------------------------------------------------------------+-----------------+----------------+--------------+
| CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN FULL SCAN OVER TEST  | null            | null           | null         |
|     SERVER FILTER BY COL1 = '2'                                | null            | null           | null         |
+----------------------------------------------------------------+-----------------+----------------+--------------+
  1. 查询id字段:
select id from TEST where  COL1='2';

查询计划如下

+---------------------------------------------------------------------------+-----------------+----------------+--------------+
|                                   PLAN                                    | EST_BYTES_READ  | EST_ROWS_READ  | EST_INFO_TS  |
+---------------------------------------------------------------------------+-----------------+----------------+--------------+
| CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN RANGE SCAN OVER IDX_COL1 ['2']  | null            | null           | null         |
|     SERVER FILTER BY FIRST KEY ONLY                                       | null            | null           | null         |
+---------------------------------------------------------------------------+-----------------+----------------+--------------+

两个查询都没有通过hint强制指定索引表,查询计划显示,查询所有字段时发生了需要极力避免的扫全表操作(一般数据量在几十万级别的扫全表很容易造成集群不稳定),而查询id时利用索引表走了点查。从现象来看,当查询中出现的字段都在索引表中时(可以是索引字段或者数据表主键,也可以是覆盖索引字段),会自动走索引表,否则查询会退化为全表扫描。

在我们实际应用中一个数据表会有多个索引表,为了能让我们的查询使用合理的索引表,目前都需要通过Hint去指定。


四、索引Building

Phoenix的二级索引创建有同步和异步两种方式。

  1. 在执行CREATE INDEX IDX_COL1 ON TEST(COL1)时会进行索引数据的同步。此方法适用于数据量较小的情况。
  2. 异步build索引需要借助MR,创建异步索引语法和同步索引相差一个关键字:ASYNC
//创建异步索引
CREATE INDEX ASYNC_IDX ON DB.TEST (COL1) ASYNC
//build 索引数据
${HBASE_HOME}/bin/hbase org.apache.phoenix.mapreduce.index.IndexTool --schema DB --data-table TEST --index-table ASYNC_IDX  --output-path ASYNC_IDX_HFILES

五、索引问题汇总

1. 创建同步索引超时怎么办?

在客户端配置文件hbase-site.xml中,把超时参数设置大一些,足够build索引数据的时间。

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

2. 索引表最多可以创建多少个?

建议不超过10个

3. 为什么索引表多了,单条写入会变慢?

索引表越多写放大越严重。写放大情况可以参考下图。

Screen_Shot_2018_03_13_at_21_36_26

References

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/107652.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 数组转化为list

    数组转化为list1、Arrays.asList(strArray)方式将数组转换List后,不能对List增删,只能查改,否则抛异常。此时是java.util.Arrays.ArrayList这里面有java.util.Arrays里面的内部类,里面没有重写增删方法,就会调用父类的AbstractList,可以看到父类的增删方法,就会报错,即使调用iterator也会报错。publicvoi…

    2022年6月29日
    27
  • 数据库课程设计(饭店点餐系统)

    数据库课程设计(饭店点餐系统)1.需求分析2.概念结构设计2.1数据需求2.1.1下订单阶段需要的数据:2.1.2点菜阶段需要的数据:2.1.3结账阶段需要的数据:2.1.4员工管理需要的数据:2.1.5顾客管理需要的数据:2.1.6消费记录管理需要的数据有:2.2事务需求2.2.1数据录入2.2.2数据更新/删除2.2.3数据查询2.3数据项2.2抽象出系统的实体2.3设计E-R图2.3.1菜谱(Menus)E-R图2.3.2顾客(Tomer)E…

    2022年5月12日
    79
  • 主机号「建议收藏」

    主机号「建议收藏」用于识别该网络中的主机。IP地址分为五类,A类保留给政府机构,B类分配给中等规模的公司,C类分配给任何需要的人,D类用于组播,E类用于实验,各类可容纳的地址数目不同。A、B、C三类IP地址的特征:

    2022年8月4日
    3
  • 计算机信息计量单位kgm,工程单位换算表.pdf

    计算机信息计量单位kgm,工程单位换算表.pdf工程单位换算表流量计|论文|工程单位换算表流量计:蒸汽流量计|污水流量计|明渠式流量计|电磁流量计|靶式流量计|涡街|涡轮|流量积算仪产品信息样本下载调查问卷论坛留言关于我们产品价格招聘买马技术资料…

    2022年5月14日
    75
  • 新手编程入门先学什么?

    新手编程入门先学什么?编程入门先学什么?关于编程的基本语言,想学习的朋友或多或少都会知道一些。C、C++、Python和Java一样,它们是通用编程语言,而JavaScript和PHP算是web环境的专用编程语言。但事实上,有许多种编程语言。如果想入门编程,学习的编程语言也有很多。编程入门先学什么?随着计算机的普及,越来越多的朋友开始走上自学编程的道路。那么,作为初学者,学习编程要如何入门?编程入门先学什么?一、先了解什么是编程如果你想学习一门新知识,你应该首先了解这门知识。通过内容可以做些什么?我们可以用什么样

    2022年6月15日
    29
  • Java入门第100课——Calendar的getInstance方法

    不知不觉到第100课了,码字真的累,写完后还要反复检查是否有笔误,以免对大家造成困扰。后面还有好多课时,真的是从零基础开始,一直到框架。不知能不能坚持写完,关注的人越多更的越快。最近更的比较快是因为有存货,存货还能撑50课的样子。一天不吃不喝最多也就写10个课时。有点啰嗦了,有什么想法给我留言吧。问题Calendar类是一个抽象类,它为特定瞬间与一组诸如YE…

    2022年4月14日
    108

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号