phoenix全局索引和本地索引 概述,使用场景,区别等详解

    科技2024-03-28  73

    索引类型

    phoenix的索引大致分为两类global index和local index,好像和星环有点类似,其实这是hbase二级索引解决方案里面广为人知的两种方案,侧重点不同,使用场景也不一样。

    global index,global是默认的索引格式。官方文档翻译过来的:Global indexing适用于多读少写的业务场景。使用Global indexing的话在写数据的时候会消耗大量开销,因为所有对数据表的更新操作(DELETE, UPSERT VALUES and UPSERT SELECT),会引起索引表的更新,而索引表是分布在不同的数据节点上的,跨节点的数据传输带来了较大的性能消耗。在读数据的时候Phoenix会选择索引表来降低查询消耗的时间。在默认情况下如果想查询的字段不是索引字段的话索引表不会被使用,也就是说不会带来查询速度的提升。Local index,适用于写操作频繁的场景。与Global index一样,Phoenix会自动判定在进行查询的时候是否使用索引。使用Local indexing时,索引数据和数据表的数据是存放在相同的服务器中的避免了在写操作的时候往不同服务器的索引表中写索引带来的额外开销。使用Local indexing的时候即使查询的字段不是索引字段索引表也会被使用,这会带来查询速度的提升,这点跟Global indexing不同。一个数据表的所有索引数据都存储在一个单一的独立的可共享的表中。

    官方文档上写的太书面了,下面用几个例子就能明白这两种索引格式是怎么设计以及怎样运行原理了。

    全局索引 测试 

    //创建盐表,就是预分区表的一种 create table ns1.testsalt (id integer primary key, name varchar, age integer, address varchar) salt_buckets = 6; //添加数据 upsert into ns1.testsalt (id,name,age,address) values(1,'zhangshan',18,'chongqing'); upsert into ns1.testsalt (id,name,age,address) values(2,'lishi',16,'wuhan'); //创建索引 CREATE INDEX testsalt_idx ON ns1.testsalt(name,age); CREATE INDEX testsalt_idx_2 ON ns1.testsalt(name,age) include(address); //删除索引 DROP INDEX testsalt_idx ON ns1.testsalt; //phoenix中查询表和索引表的数据 select * from ns1.testsalt; select * from ns1.testsalt_idx; select * from ns1.testsalt_idx_2; //explain查看sql运行情况 explain select address from ns1.testsalt where age=17; //强制走索引 explain select /*+ INDEX(ns1.testsalt testsalt_idx) */ address from ns1.testsalt where age=17; //hbase中查询表和索引表的数据 scan 'NS1:TESTSALT' scan 'NS1:TESTSALT_IDX' scan 'NS1:TESTSALT_IDX_2'

    全局索引 1.以上可以看出global index的设计方式,会单独写一张索引表,列族为include字段,rowkey的设计方位是:二级索引字段1+"\x00"+二级索引字段2(复合索引)…+"\x00"+原表rowkey 2.查询的时候,会直接定位到索引表,通过rowkey查到位置,然后从索引表中带出数据 3.因为建立索引的时候还要多写一份include字段,读的时候直接从索引表定位并读出信息。所以这种表的应用场景定位是写的慢,读得快

    本地索引 测试

    //创建表 create table ns1.testlocal (id integer primary key, name varchar, age integer, address varchar); //添加数据 upsert into ns1.testlocal (id,name,age,address) values(1,'wangwu',21,'shandong'); upsert into ns1.testlocal (id,name,age,address) values(2,'chenmazi',26,'xinjiang'); //创建索引,注意关键词 local CREATE local INDEX testlocal_idx ON ns1.testlocal(name,age); CREATE local INDEX testlocal_idx_2 ON ns1.testlocal(name,age) include(address); //删除索引 DROP INDEX testlocal_idx ON ns1.testlocal; //phoenix中查询表和索引表的数据 select * from ns1.testlocal; select * from ns1.testlocal_idx; select * from ns1.testlocal_idx_2; //explain查看sql运行的情况 explain select address from ns1.testlocal where age=17; //强制走索引 explain select /*+ INDEX(ns1.testlocal testlocal_idx) */ address from ns1.testlocal where age=17; //hbase中查询表 scan 'NS1:TESTLOCAL'

    本地索引 1.以上可以看出local index的设计方式,索引数据直接写在原表rowkey中,列族不写任何实际信息,local index的rowkey的设计方位是:原数据region的start key+"\x00"+二级索引字段1+"\x00"+二级索引字段2(复合索引)…+"\x00"+原rowkey 第一条信息"原数据region的start key",这样做的目的是保证索引数据和原数据在一个region上,定位到二级索引后根据原rowkey就可以很快在本region上获取到其它信息,减少网络开销和检索成本。 2.查询的时候,会在不同的region里面分别对二级索引字段定位,查到原rowkey后在本region上获取到其它信息 3.因为这种索引设计方式只写索引数据,省了不少空间的占用,根据索引信息拿到原rowkey后再根据rowkey到原数据里面获取其它信息。所以这种表的应用场景定位是写的快,读得慢   

    不管是全局索引 ,还是本地索引,从phoenix查询,索引也是一张表,如下图所示

      全局索引,本地索引不同点 和 比较直白话:全局索引是表,适合重读轻写的场景 ,                本地索引是列族,适合重写轻读的场景

    1.索引数据

    global index单独把索引数据存到一张表里,保证了原始数据的安全,侵入性小local index把数据写到原始数据里面,侵入性强,原表的数据量=原始数据+索引数据,使原始数据更大

    2.性能方面

    global index要多写出来一份数据,写的压力就大一点,但读的速度就非常快local index只用写一份索引数据,节省不少空间,但多了一步通过rowkey查找数据,写的速度非常快读的速度就没有直接取自己的列族数据快

     

    Processed: 0.013, SQL: 9