赞
踩
二级索引这个特性应该是大部分用户引入Phoenix主要考虑的因素之一。HBase因其历史原因只支持rowkey索引,当使用rowkey来查询数据时可以很快定位到数据位置。现实中,业务查询需求条件往往比较复杂,带有多个查询字段组合,如果用HBase查的话,只能全表扫描进行过滤,效率很低。而Phoenix支持除rowkey外的其它字段的索引创建,即二级索引,查询效率可大幅提升。
二级索引分为全局索引和本地索引。新建索引实际上是创建了另一张 HBase 表,并把索引字段数据存进去,在查询的时候优先查询索引表数据从而避免了全表扫描。
create index USER_USER_NAME_INDEX on USER ("name");
使用 Global Indexing 在写数据的时候开销很大,因为所有对数据表的更新操作(DELETE, UPSERT VALUES and UPSERT SELECT),都会引起索引表的更新,而索引表是分布在不同的数据节点上的,跨节点的数据传输带来了较大的性能消耗。
在读数据的时候 Phoenix 会选择优先查询索引表来降低查询消耗的时间。在默认情况下如果待查询的字段不是索引字段的话,索引表是不会被使用的,也就是说不会带来查询速度上的提升。
create local index USER_USER_NAME_INDEX on USER ("name");
与 Global Indexing 一样,Phoenix 会自动判定在进行查询的时候是否使用索引。使用 Local indexing 时,索引数据和数据表的数据存放在相同的服务器中,这样避免了在写操作的时候往不同服务器的索引表中写索引带来的额外开销。使用 Local indexing 的时候即使查询的字段不是索引字段索引表也会被使用,这会带来查询速度的提升,这点跟 Global indexing 不同。对于 Local Indexing,一个数据表的所有索引数据都存储在一个单一的独立的可共享的表中。
不可变索引的存储方式是 write one,append only。当在 Phoenix 使用 create table 语句时指定 IMMUTABLE_ROWS = true 表示该表上创建的索引将被设置为不可变索引。Phoenix 默认情况下如果在 create table 时不指定 IMMUTABLE_ROWS = true 时,表示该表为 mutable。不可变索引分为 Global immutable index 和 Local immutable index 两种。
Phoenix 默认情况创建的索引都是可变索引,除非在 create table 的时候显式地指定 IMMUTABLE_ROWS = true。可变索引同样分为 Global mutable index 和 Local mutable index 两种。
创建 converted index。如果在某次查询中,查询项或者查询条件中包含有被索引列之外的列(主键除外)。默认情况下,该查询就会触发 full table scan(全表扫描),但是使用 covered index 则可以避免全表扫描。 创建包含某个字段的覆盖索引,创建方式如下:
create index USER_NAME_AGE_INDEX on USER ("name") include("age");
如果创建索引时原表已经有大量数据了,可能会等很长时间,这时可以使用异步创建的方式。
create index USER_NAME_AGE_INDEX on USER ("name") include("age") ASYNC;
再用 hbase 命令触发执行
hbase org.apache.phoenix.mapreduce.index.IndexTool \
--data-table=Product \
--index-table=INDEX_PRODUCT \
--output-path=/user/spark/ASYNC_INDEX_HFILES <-- 必须先在 hdfs 创建这个目录
上述命令运行成功后,IndexTool 的 MR 任务会帮助我们构建好索引数据,同时会把索引表的当前状态置为 ACTIVE,然后就可以使用这个索引表进行数据查询了。
查询的时候提示其使用索引。 在 select 和 column_name 之间加上/+ Index(<表名> <index 名>)/,通过这种方式强制使用索引。 例如:
select /*+ index(user,USER_NAME_AGE_INDEX) */ "name","sex" from user where "user_id"='123';
这样会强制查询索引表,但由于 sex字段其实不在索引表,最后还是会去查询原表,但可能会缩小查询范围。
比如以 time 为查询条件,在原表需要查询所有 id 的部分 time,而先查询索引可以先过滤出满足查询条件的 id,再去原表查询满足条件的 id 的部分 time,如果过滤出来的 id 很少,性能会有显著提升,如果过滤出来的 id 非常多,性能可能就没有明显提升,甚至可能会有下降,因为要查两张表。因此只有当用户明确知道符合检索条件的数据较少的时候才适合使用,否则就又会造成全表扫描,对性能影响较大。
可以通过 explain 命令查看数据库是如何执行查询计划的。
explain select * from User where age > 20
索引不一定能显著提升查询性能,这取决于数据分布和查询条件
如果是以 time 为查询条件,在原表需要查询所有 id 的部分 time,而在索引表是直接查询 time,这样如果满足查询条件的 id 很少,性能会有显著提升,如果满足查询条件的 id 本来就非常多,性能可能就没有明显提升
如果是以 sale 为查询条件,在原表需要查询所有 id 的所有 time,即需要查询原表所有 row key,而在索引表是直接查询 sale,一般来讲性能会有显著提升,除非满足查询条件的 id + time 非常多,即满足条件的原表 row key 非常多,那性能可能就没有明显提升。
索引会导致写性能下降,因为建了多少索引就要写多少张表,同时消耗更多的磁盘空间。所以,索引不是越多越好。
最后,Phoenix 的二级索引在某些场景中还是非常有用的,可一旦使用姿势不当,极大可能会造成全表扫描,严重时线上其他的查询服务也会深受其害。其次牢记,不走 Phoenix 的 API 而更新数据的方式,索引表可能不会随之更新,必要时需要手动维护索引表数据,索引表的数据要严格与主表的数据保持一致,否则,会出现遗漏数据的情况。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。