Phoenix 異步創建索引


date: 2020-11-07 15:34:00
updated: 2020-11-13 17:17:00

Phoenix 異步創建索引

當表數據量過大的時候,創建索引會報錯,可以修改服務器端的 hbase.rpc.timeout,默認是1分鍾,可以自定義時間。也可以異步創建索引,通過在語句后面添加async 關鍵字。

需要注意的是:

  1. 異步創建索引只支持全局索引
  2. 執行async語句只是第一步,還需要通過執行jar包來保證索引真正的建立

1. 為什么只支持全局索引?

首先是本地索引和全局索引的一些概念和區別

  • 本地索引
    • 適合寫多讀少的情況
    • 索引數據直接寫在原表里,不會新建一張表。在 phoenix-sqlline 里執行 !tables 的確會發現創建的本地索引表,但是那個只是一個映射,並不是單獨存在的。由於索引數據直接寫在表里,所以原表的數據量=原始數據+索引數據。
    • 本地索引rowkey的設計規則: 原數據region的start key+"\x00"+二級索引字段1+"\x00"+二級索引字段2(復合索引)…+"\x00"+原rowkey。
    • 索引數據和真實數據存放在同一台機器上,減少了網絡傳輸的開銷。同理,創建索引后的rowkey的最開始的部分是 原數據region的start key,這樣在通過二級索引定位到數據后,可以在當前的region中直接找到數據,減少網絡開銷。減少網絡開銷,也意味着寫入的速度會變快。但是多了一步通過rowkey查找數據的過程,所以讀的過程就不如直接讀取列族里的數據的速度快。
  • 全局索引
    • 適合讀多寫少的情況
    • 索引數據會單獨存在一張表里。
    • 全局索引必須是查詢語句中所有列都包含在全局索引中,它才會生效。

      Select * 不會命中索引
      select 具體的字段 from table where col ...
      col 必須是第一個主鍵或者是索引里包含的字段才會命中索引
      如果索引表包含 a、b 三個字段,where 里有 a 和 c 兩個字段,那么也不會走索引,因為c不在索引里,發現索引走不通,只能走全表

    • 為了命中索引,要把需要查詢的字段通過 include 關鍵字來一起寫入索引表里,也就是覆蓋索引。
    • 寫入數據的同時需要往索引表同步寫數據,而索引表是分布在不同的數據節點上的,跨節點的數據傳輸帶來了較大的性能消耗,所以寫慢;但是查詢的時候,如果命中了索引表,那就直接把數據帶出來了,讀會快。

綜上,本地索引不是表,全局索引才是表,而async是針對表的一種方式,所以只能作用於全局索引

2. 如何執行async

  1. 首先是需要創建一個全局索引,同時使用 async

create index XXX on database.tablename(col1, col2) include(col3, col4) async

此時去看這個表,會發現 index_state 字段的值是 building,說明索引表還沒創建好,這是因為 async 關鍵字會初始化一個mr作業,只是把創建索引的數據文件准備好,還沒有正式開始

  1. 執行mr作業
hbase org.apache.phoenix.mapreduce.index.IndexTool \
--schema 庫名 --data-table 表名 --index-table 索引表名 \
--output-path hdfs路徑指向一個文件件即可

庫名、表名、索引表名盡量都不要小寫

這個命令執行后可能會報錯,遇到 org.apache.phoenix.mapreduce.index.IndexTool 依賴的jar沒法加載,那就可以換一個方式執行

java -cp ./本地文件夾路徑:/data1/cloudera/parcels/PHOENIX/lib/phoenix/phoenix-5.0.0-cdh6.2.0-client.jar  org.apache.phoenix.mapreduce.index.IndexTool   --schema 庫名 --data-table 表名 --index-table 索引表名     --output-path hdfs路徑指向一個文件件即可

本地文件夾里需要包含 hbase yarn hdfs 的配置文件

如果遇到 java.io.IOException: Can't get Master Kerberos principal for use as renewer 說明缺少yarn的配置文件

如果遇到 org.apache.hadoop.security.AccessControlException: Permission denied: user=phoenix, access=WRITE, inode="/user":hdfs:supergroup:drwxr-xr-x 需要在 hbase-site.xml 文件里添加 hbase.fs.tmp.dir 配置項,值是hdfs上一個有讀寫權限的目錄路徑。
原因:從 org.apache.phoenix.mapreduce.index.IndexTool 開始追代碼,會找到 org.apache.hadoop.hbase.mapreduce.HFileOutputFormat2,在配置mr作業的時候,configurePartitioner() 方法里 String hbaseTmpFsDir = conf.get("hbase.fs.tmp.dir", HConstants.DEFAULT_TEMPORARY_HDFS_DIRECTORY); 會去讀取配置文件里的這個值,默認是 "/user/" + System.getProperty("user.name") + "/hbase-staging"

3. 附

  1. 查詢執行計划,判斷是否命中索引表
內容 含義
CLIENT 表明操作在客戶端執行還是服務端執行,客戶端盡量返回少的數據。若為 SERVER 表示在服務端執行。
FILTER BY expression 返回和過濾條件匹配的結果。
FULL SCAN OVER tableName 表明全表掃描某張業務表。
RANGE SCAN OVER tableName [ … ] 表明代表范圍掃描某張表,括號內代表 rowkey 的開始和結束。
ROUND ROBIN 無 ORDER BY 操作時, ROUND ROBIN 代表最大化客戶端的並行化。
x-CHUNK 執行此操作的線程數。
PARALLEL x-WAY 表明合並多少並行的掃描。
EST_BYTES_READ 執行查詢時預計掃描的總字節數。
EST_ROWS_READ 執行查詢時預計掃描多少行。
EST_INFO_TS 收集查詢信息的 epoch time
  1. 在創建索引的過程中,發現了一個可能是版本bug的地方,已提官網issue,鏈接如下

官網issue地址

問題:如果在創建本地索引時,有一個字段設置了default value,在生成的索引表里就只會顯示默認值,不管是什么類型;如果這個類型是tinyint的話,還可能會造成之后主鍵的數據,原表的數據是對的,但是索引表是錯的,如果命中了索引表,那么就返回的是錯誤的數據。


免責聲明!

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



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