phoenix 索引實踐


准備工作

    創建測試表

   

CREATE TABLE my_table (
        rowkey VARCHAR NOT NULL PRIMARY KEY,
        v1 VARCHAR,
         v2 VARCHAR,
         v3 VARCHAR
     );

    UPSERT INTO my_table values('1','value1','value2','value3');
    UPSERT INTO my_table values('2','value1','value2','value3');
    UPSERT INTO my_table values('3','value1','value2','value3');
    UPSERT INTO my_table values('4','value1','value2','value3');
    UPSERT INTO my_table values('5','value1','value2','value3');

    開啟索引支持

    HBase --> 配置 --> 高級 --> 搜索 hbase-site.xml。
    在服務端添加下面配置:

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


    在這里插入圖片描述

創建索引

    全局索引

    全局索引適合讀多寫少的場景。如果使用全局索引,讀數據基本不損耗性能,所有的性能損耗都來源於寫數據。數據表的添加、刪除和修改都會更新相關的索引表(數據刪除了,索引表中的數據也會刪除;數據增加了,索引表的數據也會增加)。

    注意:

    對於全局索引在默認情況下,在查詢語句中檢索的列如果不在索引表中,Phoenix不會使用索引表將,除非使用hint。

    創建全局索引

    CREATE INDEX my_index ON my_table ( v3 );



    查看效果

  

 0: jdbc:phoenix:> select v3 from my_table where v3 = '13000010030';
    +--------------+
    |      V3      |
    +--------------+
    | 13000010030  |
    +--------------+
    1 row selected (2.155 seconds)
    0: jdbc:phoenix:> select * from my_table where v3 = '13000010030';
    +-------------------+------+--------+--------------+
    |      ROWKEY       |  V1  |   V2   |      V3      |
    +-------------------+------+--------+--------------+
    | 77a9ede22e169683  | aaa| bbb| 13000010030  |
    +-------------------+------+--------+--------------+
    1 row selected (2.337 seconds)
    0: jdbc:phoenix:> CREATE INDEX my_index ON my_table ( v3 );
    1,076,190 rows affected (33.875 seconds)
    0: jdbc:phoenix:> select * from my_table where v3 = '13000010030';
    +-------------------+------+--------+--------------+
    |      ROWKEY       |  V1  |   V2   |      V3      |
    +-------------------+------+--------+--------------+
    | 77a9ede22e169683  | aaa| bbb| 13000010030  |
    +-------------------+------+--------+--------------+
    1 row selected (3.296 seconds)
    0: jdbc:phoenix:> select v3 from my_table where v3 = '13000010030';
    +--------------+
    |      V3      |
    +--------------+
    | 13000010030  |
    +--------------+
    1 row selected (0.02 seconds)


    本地索引

    本地索引適合寫多讀少的場景,或者存儲空間有限的場景。和全局索引一樣,Phoenix也會在查詢的時候自動選擇是否使用本地索引。本地索引因為索引數據和原數據存儲在同一台機器上,避免網絡數據傳輸的開銷,所以更適合寫多的場景。由於無法提前確定數據在哪個Region上,所以在讀數據的時候,需要檢查每個Region上的數據從而帶來一些性能損耗。

    注意:

    對於本地索引,查詢中無論是否指定hint或者是查詢的列是否都在索引表中,都會使用索引表。

    創建本地索引

    CREATE LOCAL INDEX LOCAL_IDEX ON my_table(v3);

    查看效果

   

0: jdbc:phoenix:> select * from my_table where v3 = '13000010030';
    +-------------------+------+--------+--------------+
    |      ROWKEY       |  V1  |   V2   |      V3      |
    +-------------------+------+--------+--------------+
    | 77a9ede22e169683  | aaa| bbb| 13000010030  |
    +-------------------+------+--------+--------------+
    1 row selected (3.545 seconds)
    0: jdbc:phoenix:> select v3 from my_table where v3 = '13000010030';
    +--------------+
    |      V3      |
    +--------------+
    | 13000010030  |
    +--------------+
    1 row selected (2.946 seconds)
    0: jdbc:phoenix:> CREATE LOCAL INDEX LOCAL_IDEX ON my_table(v3);
    1,076,190 rows affected (24.67 seconds)
    0: jdbc:phoenix:> select * from my_table where v3 = '13000010030';
    +-------------------+------+--------+--------------+
    |      ROWKEY       |  V1  |   V2   |      V3      |
    +-------------------+------+--------+--------------+
    | 77a9ede22e169683  | aaa| bbb| 13000010030  |
    +-------------------+------+--------+--------------+
    1 row selected (0.055 seconds)
    0: jdbc:phoenix:> select v3 from my_table where v3 = '13000010030';
    +--------------+
    |      V3      |
    +--------------+
    | 13000010030  |
    +--------------+
    1 row selected (0.013 seconds)

    覆蓋索引

    覆蓋索引是把原數據存儲在索引數據表中,這樣在查詢時不需要再去HBase的原表獲取數據就,直接返回查詢結果。

    注意:

    查詢是 select 的列和 where 的列都需要在索引中出現。

    創建覆蓋索引

    CREATE INDEX my_index ON my_table ( v2,v3 ) INCLUDE ( v1 );


    添加索引后提升到毫秒級

   

0: jdbc:phoenix:> select * from my_table where v3 = '13308117837' and v2 = '北京順義';
    +-------------------+-----+-------+--------------+
    |      ROWKEY       | V1  |  V2   |      V3      |
    +-------------------+-----+-------+--------------+
    | 3f65283ed7553909  | wenyuan  | ccc| 13308117837  |
    +-------------------+-----+-------+--------------+
    1 row selected (2.42 seconds)
    0: jdbc:phoenix:> CREATE INDEX my_index ON my_table (v2,v3) INCLUDE ( v1 );
    1,076,190 rows affected (47.432 seconds)
    0: jdbc:phoenix:> select * from my_table where v3 = '13308117837' and v2 = '北京順義';
    +-------------------+-----+-------+--------------+
    |      ROWKEY       | V1  |  V2   |      V3      |
    +-------------------+-----+-------+--------------+
    | 3f65283ed7553909  | wenyuan| ccc| 13308117837  |
    +-------------------+-----+-------+--------------+
    1 row selected (0.031 seconds)



    函數索引

    從Phoenix4.3版本就有函數索引,特點是索引的內容不局限於列,能根據表達式創建索引。適用於對查詢表時過濾條件是表達式。如果你使用的表達式正好就是索引的話,數據也可以直接從這個索引獲取,而不需要從數據庫獲取。

    創建索引

    CREATE INDEX my_index ON my_table(substr(v3,1,9)) INCLUDE ( v1 );

    查看效果

   

0: jdbc:phoenix:> select v1,substr(v3,1,9) from my_table where substr(v3,1,9) = '130000109';
    +-----+-------------------+
    | V1  | SUBSTR(V3, 1, 9)  |
    +-----+-------------------+
    | wenyuan| 130000109         |
    +-----+-------------------+
    1 row selected (3.656 seconds)
    0: jdbc:phoenix:> select v1,v3 from my_table where substr(v3,1,9) = '130000109';
    +-----+--------------+
    | V1  |      V3      |
    +-----+--------------+
    | wenyuan| 13000010979  |
    +-----+--------------+
    1 row selected (3.969 seconds)
    0: jdbc:phoenix:> CREATE INDEX my_index ON my_table(substr(v3,1,9)) INCLUDE ( v1 );
    1,076,190 rows affected (45.833 seconds)

    0: jdbc:phoenix:> select v1,v3 from my_table where substr(v3,1,9) = '130000109';
    +-----+--------------+
    | V1  |      V3      |
    +-----+--------------+
    | wenyuan| 13000010979  |
    +-----+--------------+
    1 row selected (3.44 seconds)
    0: jdbc:phoenix:> select v1,v3,substr(v3,1,9) from my_table where substr(v3,1,9) = '130000109';
    +-----+--------------+-------------------+
    | V1  |      V3      | SUBSTR(V3, 1, 9)  |
    +-----+--------------+-------------------+
    | wenyuan| 13000010979  | 130000109         |
    +-----+--------------+-------------------+
    1 row selected (3.327 seconds)
    0: jdbc:phoenix:> select v1,substr(v3,1,9) from my_table where substr(v3,1,9) = '130000109';
    +-----+--------------------+
    | V1  | " SUBSTR(V3,1,9)"  |
    +-----+--------------------+
    | wenyuan  | 130000109          |
    +-----+--------------------+
    1 row selected (0.013 seconds)
    0: jdbc:phoenix:> select v1 from my_table where substr(v3,1,9) = '130000109';
    +-----+
    | V1  |
    +-----+
    | wenyuan|
    +-----+
    1 row selected (0.011 seconds)



索引Building

    同步索引

    CREATE INDEX ASYNC_IDX ON SCHEMA_NAME.TABLE_NAME(BASICINFO."s1",BASICINFO."s2") ;


    創建同步索引超時怎么辦?

    在客戶端配置文件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>


    異步索引

    異步Build索引需要借助MapReduce,創建異步索引語法和同步索引相差一個關鍵字:ASYNC。

        創建異步索引

        CREATE INDEX ASYNC_IDX ON SCHEMA_NAME.TABLE_NAME ( BASICINFO."s1", BASICINFO."s2" ) ASYNC;
    

        運行MapReduce

        執行MapReduce

        hbase org.apache.phoenix.mapreduce.index.IndexTool \
        --schema SCHEMA_NAME\
        --data-table TABLE_NAME\
        --index-table ASYNC_IDX \
        --output-path ASYNC_IDX_HFILES

       日志:

Java HotSpot(TM) 64-Bit Server VM warning: Using incremental CMS is deprecated and will likely be removed in a future release
        SLF4J: Class path contains multiple SLF4J bindings.
        SLF4J: Found binding in [jar:file:/opt/cloudera/parcels/CDH-5.12.1-1.cdh5.12.1.p0.3/jars/phoenix-4.14.0-cdh5.12.2-client.jar!/org/slf4j/impl/StaticLoggerBinder.class]
        SLF4J: Found binding in [jar:file:/opt/cloudera/parcels/CDH-5.12.1-1.cdh5.12.1.p0.3/jars/slf4j-log4j12-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
        SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
        SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
        19/05/22 15:38:41 INFO log.QueryLoggerDisruptor: Starting  QueryLoggerDisruptor for with ringbufferSize=8192, waitStrategy=BlockingWaitStrategy, exceptionHandler=org.apache.phoenix.log.QueryLoggerDefaultExceptionHandler@dd0c991...
        19/05/22 15:38:41 INFO query.ConnectionQueryServicesImpl: An instance of ConnectionQueryServices was created.

        ...

        19/05/22 15:41:19 INFO index.IndexTool: Loading HFiles from INDEX_PERSONAS_TAG_HFILES/MY_SCHEMA.INDEX_PERSONAS_TAG
        19/05/22 15:41:19 WARN mapreduce.LoadIncrementalHFiles: Skipping non-directory hdfs://bigdata-dev-41:8020/user/root/INDEX_PERSONAS_TAG_HFILES/MY_SCHEMA.INDEX_PERSONAS_TAG/_SUCCESS
        19/05/22 15:41:19 INFO hfile.CacheConfig: CacheConfig:disabled
        19/05/22 15:41:19 INFO mapreduce.LoadIncrementalHFiles: Trying to load hfile=hdfs://bigdata-dev-41:8020/user/root/INDEX_PERSONAS_TAG_HFILES/MY_SCHEMA.INDEX_PERSONAS_TAG/0/e1f766365b4f4c7cb6cfc6e0d18328b8 first=0\x0010\x00\xE4\xB8\x9A\xE4\xB8\xBB\x000\x000\x0010\x000\x00\xE6\xAD\xA3\xE5\xB8\xB8\xE4\xB8\x9A\xE4\xB8\xBB\x001001.99\x000\x001\x003\x00\xE8\x80\x81\xE5\xAE\xA2\xE6\x88\xB7\x00\xE6\x9C\xAA\xE7\x9F\xA5\x0042471415705946377 last=2\x009\x00\xE7\xA7\x9F\xE5\xAE\xA2\x002\x002\x009\x002\x00\xE9\x95\xBF\xE6\x9C\x9F\xE4\xB8\x8D\xE4\xBA\xA4\xE7\x89\xA9\xE4\xB8\x9A\xE7\xAE\xA1\xE7\x90\x86\xE8\xB4\xB9\x00988.56\x000\x001\x004\x00\xE6\x9C\xAA\xE7\x9F\xA5\x00\xE5\x9C\x9F\xE8\xB1\xAA\x0044ff3613003558171
        19/05/22 15:41:20 INFO index.IndexToolUtil:  Updated the status of the index INDEX_PERSONAS_TAG to ACTIVE

 


    

        遇到問題

        Error: Could not find or load main class org.apache.phoenix.mapreduce.index.IndexTool

        解決辦法

        將 phoenix-4.14.0-cdh5.12.2-client.jar 包復制到 hbase 的 lib 目錄下

        [root@node00 ~]# cd /opt/cloudera/parcels/
        [root@node00 parcels]# cd APACHE_PHOENIX/lib/phoenix
        [root@node00 phoenix]# cp phoenix-4.14.0-cdh5.12.2-client.jar /opt/cloudera/parcels/CDH/jars/
        [root@node00 phoenix]# cd /opt/cloudera/parcels/CDH/lib/hbase/lib/
        [root@node00 lib]# ln -s ../../../jars/phoenix-4.14.0-cdh5.12.2-client.jar phoenix-4.14.0-cdh5.12.2-client.jar

索引用法總結

Phoenix 的二級索引主要有兩種,即全局索引和本地索引。
全局索引適合讀多寫少的場景,如果使用全局索引,讀數據基本不損耗性能,所有的性能損耗都來源於寫數據。
本地索引適合寫多讀少的場景,或者存儲空間有限的場景。

索引定義完之后,一般來說,Phoenix自己會判定使用哪個索引更加有效。
但是,全局索引必須是查詢語句中所有列都包含在全局索引中,它才會生效。

索引為:

create index my_index on my_table (v3);

select v1 from my_table where v3 = '13406157616';


上面語句怎樣才能使用索引呢?

有以下三種方法使它使用索引:

    使用覆蓋索引

    CREATE INDEX cover_index ON my_table(v3) INCLUDE (v1);


    查看效果

    0: jdbc:phoenix:> select v1 from my_table where v3 = '13406157616';
    +------+
    |  V1  |
    +------+
    | wenyuan|
    +------+
    1 row selected (0.01 seconds)



    使用 Hint 強制索引

   

SELECT /*+ INDEX(my_table my_index) */ v1 FROM my_table WHERE v3 = '13406157616';


    查看效果

    0: jdbc:phoenix:> SELECT /*+ INDEX(my_table my_index) */ v1 FROM my_table WHERE v3 = '13406157616';
    +------+
    |  V1  |
    +------+
    | wenyuan|
    +------+
    1 row selected (0.044 seconds)


    使用本地索引

    CREATE LOCAL INDEX local_index on my_table (v3);


    查看效果

   

0: jdbc:phoenix:> select v1 from my_table where v3 = '13406157616';
    +------+
    |  V1  |
    +------+
    | wenyuan|
    +------+
    1 row selected (0.025 seconds)

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM