1、索引概念
- 举例
一本新华字典,从里面找一个字
有索引:这本新华字典有拼音检索的目录,可以按照拼音找字
没有索引:没有目录,一页一页翻来找这个字
- 问题
- 假设:rowkey设计:时间_用户id
20200101_001
20200101_002
20200102_002
20200103_003
……
- 走索引的查询
- 需求:
查询002所有的数据
- 全表扫描
- 对所有数据的用户id进行过滤,将用户id=002的数据过滤出来
- SingleColumnValueFilter
性能非常差
- 只要查询的 条件不是rowkey的前缀,就只能走全表扫描
- 解决
- 构建二级索引
一级索引:rowkey
二级索引:通过二级索引找到需要的一级索引
2、二级索引
rowkey userid serverTime username ip url ……
20200101_001 001 20200101
20200101_002 002 20200101
20200102_002 002 20200102
20200103_003 003 20200103
20200104_004 004 20200104
……
- rowkey是唯一索引
- 全表扫描
- 对所有的rowkey的userid这一列进行比较
- 如果是002,就返回
- 不是就过滤
- 索引表:用于存储原表的rowkey的
rowkey source_rk
001_20200101 20200101_001
002_20200101 20200101_002
002_20200102 20200102_002
003_20200103 20200103_003
二级索引检索过程
- 第一步:
先检索索引表,根据用户id,得到所有符合的原表的rowkey
002_20200101 20200101_002
002_20200102 20200102_002
20200101_002 002 20200101
20200102_002 002 20200102
- 功能:
基于一级索引构建二级索引,加快读取数据的速度
- 应用场景:将不能满足rowkey前缀查询的条件作为索引表的rowkey,走两次索引来实现数据查询
解决有些条件不在rowkey中或者不是前缀,依旧希望查询比较快
问题:原表数据如何与索引表保持一致,实现数据同步?
- 如果不同步,查询结果就是不准确的
- 问题举例
- 原表:有004用户的数据
- 索引表:没有这个映射关系
- 通过二级索引查询:没有004的数据
- 解决方案
- 往Hbase中写入数据都是通过程序来处理的
- 方案一:在客户端程序中往原表中插入数据以后,往索引也插入一条
- 可以实现
- 但是性能非常差:客户端本来只要写一条数据,但是提交了两个写入请求
- 一般不用
- 方案二:
使用Hbase的协处理器来实现
类似于UDF或者Mysql触发器
开发一个程序,监听原表,只要用户往原表中写入数据,Hbase就自动往索引表写入一条数据
- 方案三:使用第三方工具实现【主要】
- ==Phoenix:==在底层封装了 大量的Hbase的协处理器,不用你自己开发
你可以用SQL写:create index - 自动帮你创建一张索引表,自动帮你维护数据同步
- ES:ELK中的搜索引擎,可以构建索引
- Solr:也是搜索引擎
总结
Rowkey的设计
业务原则
:必须非常贴合业务设计rowkey唯一原则
:每个rowkey唯一标识一行组合原则
:将查询频率比较高的查询条件封装组合成rowkey
散列原则
:构建随机散列的rowkey,避免有序的rowkey
- region的范围就是有序的,如果rowkey也是有序的写入,就会写入同一个region,导致热点
长度原则
:满足业务需求的情况下,越短越好
- rowkey的存储是冗余的,在底层检索时,需要进行比较
- 列族的设计
- 列标签
预分区
- 先设计rowkey
- 根据rowkey的格式来进行预分区创建表
二级索引
- 什么是二级索引?
- 为什么要构建二级索引?
- 因为
Hbase中rowkey是唯一的索引,并且只能做前缀匹配
- 在查询时,如果查询的条件不是rowkey的前缀,只能全表扫描,性能比较差
可以构建二级索引,经过两次索引来解决查询性能问题