postgres 把一个表的值转成另一个表的字段名_Phoenix系列创建Phoenix映射表
目前,在公司小部分的業務場景中有用到 Phoenix,但也僅限基于 Phoenix 的二級索引機制來進行查詢上的優化。雖然使用的頻次不大,但偶爾用到時,有些語句的使用方式和注意事項總記不太熟,每次都需要一頓谷歌和百度,然后從五花八門的文章中攝取著自己需要的信息。
本文是 Phoenix 系列的第一篇文章,我打算從 Phoenix 映射表的創建開始說起。Phoenix 映射表的創建雖然看起來很簡單,但其中的細節和潛在的坑著實也不少,且容我慢慢道來。
本文詳細記錄了 Phoenix 映射表的基本創建方式,以及我自己額外的一些思考和測試,如果文章中有描述不當的地方,還望大家多多指教,也歡迎大家在留言區踴躍發言。
1. 我的軟件環境
在開始正式介紹之前,還是先來說明下我 Phoenix 的版本。文中涉及到的關于 Phoenix 的使用小示例,基于的版本分別是PHOENIX-4.14.0-cdh5.13.2和PHOENIX-5.0.0-cdh6.2.0,其中兩個 Phoenix 對應的 HBase 的版本分別是HBase 1.2.0-cdh5.13.1和HBase 2.1.0-cdh6.3.1。如果沒有特別的說明,所選示例在兩個版本中運行方式以及結果是一樣的。
2. 關于 Phoenix
Phoenix 是一款優秀的基于 HBase 的數據庫中間件,由 Apache 官方出品,圈內共識,Apache 出品,必屬精品,當然,爛尾的除外哈。Phoenix 把用戶輸入的 SQL 語句翻譯成 HBase 底層的查詢 API,簡化了 HBase 客戶端的查詢方式,讓用戶可以使用標準的 SQL 語句來查詢 HBase 表里的數據。配合 Phoenix 的二級索引機制,Phoenix 可以實現更加方便和復雜的 HBase 數據查詢場景。有關 Phoenix 更深入的介紹,可以前往其官網查看。http://phoenix.apache.org/
3. 在 Phoenix 中創建不存在的 HBase 表的映射表
Phoenix 創建表的語句與 MySql 的語法有點相似,但需要關注的細節也有很多。
create?table?"user"(???"?id"?VARCHAR?PRIMARY?KEY,
????"info"."name"?VARCHAR,
????"info"."age"?VARCHAR)
?column_encoded_bytes=0;
把上述建表語句 copy 到 Phoenix 的 shell 下,運行后查看我們創建的表的信息。
同時,在 HBase 的 default 命名空間中,也自動創建出了一張名叫 user 的表。
跟以普通方式創建的 HBase 表相比,除了常規的表描述信息之外,Phoenix 創建的表還多了一些協處理器等的描述信息。望文生義,這些協處理器大致與 Scan、索引創建等等操作有關。
讓我們再來解讀下這個簡單的建表語句,“user”是表名,id 作為主鍵,也即是 HBase 表中的 RowKey,“info”最終在 HBase 中體現為表的列簇,“name","age"就是表的字段名,緊隨其后的是列的類型,統一都是 VARCHAR,也即字符串,字段名默認可以為空,如果強制不為空,則為其加上 NOT NULL。"id"因為要作為 RowKey,所以一定不能是空的。最后一行 column_encoded_bytes=0 表示需要禁用列映射規則,否則會降低查詢性能,所以一般情況下這里都置為 0。
到這里大家也許會發現,表名、字段名、列簇名都被引號包括,如果我不指定引號呢?讓我們先刪除表,然后重新運行如下的建表語句:
刪除表的操作是 drop table "user",如果待刪除的表不存在,就會拋出異常,如果想要避免表不存在的異常,則需要加上表是否存在的判斷,即運行 drop table if exists "user"。刪除表的同時,底層映射的 HBase 表也一同被刪除,這絕對是你刪庫跑路的利器,所以生產環境下還是謹慎使用吧。
create?table?user(???id?VARCHAR?PRIMARY?KEY,
????info.name?VARCHAR,
????info.age?VARCHAR)
?column_encoded_bytes=0;
然后查看下我們重新創建的表:
首先我們的表名被轉成了大寫,再 select 下數據。
查看下 HBase 表:
如上圖所示,引號的作用應該很明顯了吧,Phoenix 中表名、列簇名、字段名如果不加引號,會被默認轉成大寫。
4. 在 Phoenix 中創建存在的 HBase 表的映射表
接著,我們刪除剛剛創建的 user 表。再來嘗試如下的建表方式。首先在 HBase 的命令行下創建一張名叫 user 的表,其列簇是 info,create user,info 。此時 user 表就是一個普普通通的 HBase 表,然后運行如下建表語句:
create?table?"user"(???id?VARCHAR?PRIMARY?KEY,
????info.name?VARCHAR,
????info.age?VARCHAR)
?column_encoded_bytes=0;
上述建表語句中我故意把 user 加引號,是為了確保在 Phoenix 中創建的表就是小寫的名字,而不會在 HBase 中重新生成一張名叫 USER 的表。運行完查看下我們的 HBase 表。多了一個名叫 INFO 的列簇。所以,我們只有嚴格保證這些大小寫一一對應,才能保證 Phoenix 表與 HBase 確立正確一致的映射關系,重新運行如下建表語句。
create?table?"user"(???"?id"?VARCHAR?PRIMARY?KEY,
????"info"."name"?VARCHAR,
????"info"."age"?VARCHAR)
?column_encoded_bytes=0;
所以,我們可以先提前創建 HBase 表,再去創建該表的 Phoenix 映射表,保證大小寫一一對應,同樣可以達到如小節 3 中的效果。
5. 創建帶有 schema 的 Phoenix 表
直接運行如下建表語句:
create?table?"person"."user"(???"?id"?VARCHAR?PRIMARY?KEY,
????"info"."name"?VARCHAR,
????"info"."age"?VARCHAR)
?column_encoded_bytes=0;
如果這個名叫 person 的 schema 不存在就會遇到建表的異常。
運行 create schema "person"來創建 schema,同樣需要注意大小寫。能正確創建 schema 的前提是需要在 HBase 的服務端和 Phoenix 的客戶端增加如下配置:
<property>????????<name>phoenix.schema.isNamespaceMappingEnabledname>
????????<value>truevalue>
property>
<property>
????????<name>phoenix.schema.mapSystemTablesToNamespacename>
????????<value>truevalue>
property>
schema 創建完成之后,我們的表就能被正常創建了,Phoenix 的表創建完畢后,HBase 中會自動創建名為 person 的 namespace 和名為 person:user 的表。
6. 創建 Phoenix 表指定預分區
默認情況下創建的 Phoenix 表映射的 HBase 底層表只有一個分區,但是如果你的表數據很大,導數據時一個分區能把你急的肝疼。創建 Phoenix 表時預分區的方法有兩種,一種是提前創建一個具有預分區的 HBase 表,然后再創建 Phoenix 表來映射已經存在的表;另一種則是創建 Phoenix 表的同時指定好預分區的信息。
示例語句如下:
?create?table?"person"."user"(???"id"?VARCHAR?PRIMARY?KEY,
????"info"."name"?VARCHAR,
????"info"."age"?VARCHAR)?column_encoded_bytes=0
????SPLIT?ON?('1','2','3','4','5','6','7','8','9');
然后在 HBase 的表監控界面上,你就可以看到如下的分區信息:
還有一種比較糟糕情況是,你的 HBase 表提前創建好了,大量數據也導入了表中,此時你才想起來需要創建 Phoenix 表。在大量數據存在的前提下,在 Phoenix shell 中直接創建映射表,十有八九會遇到客戶端超時的異常,貌似不太影響使用,只是不知道會不會數據映射不完整。目前對于這種情況還沒找到合適的解決辦法,只能在創建表的開始階段就好好規劃下是否需要創建 Phoenix 表以及創建表時的預分區等,盡量避免出現這樣的尷尬狀況。
7. 各種數據寫入后的映射情況
在這一小節里將說明 HBase 的各種寫入方式寫入的數據能否在 Phoenix 中正常綁定,以及 Phoenix 端數據寫入后能否在 HBase 表中順利查到。
對于 HBase 的數據寫入方式,我在這里主要分成 bulkload 和普通的 hbase client api 寫入,首先來測試下 client api 的數據寫入方式,簡單起見我直接在 shell 下 put 一些數據。
再來查看 Phoenix 中的數據,數據正常綁定。
接著測試在 phoenix 表插入一些數據,然后觀察 HBase 的數據變化。
?upsert?into?"person"."user"?("id","name","age")?values('2',?'leo2','17');就不貼圖了,Phoenix 和 HBase 兩邊的數據是一一對應的。
那繼續來測試 bulkload 的方式導入數據,然后觀察 Phoenix 和 HBase 兩邊的數據情況吧!
測試之前,我們先用truncate_preserve 'person:user'命令清空 user 表里的數據。
準備一些測試數據,然后上傳至 hdfs 的某一個測試目錄。
使用如下命令先把 csv 文件轉換成 hfile:
hbase?org.apache.hadoop.hbase.mapreduce.ImportTsv?-Dimporttsv.separator=","?-Dimporttsv.bulk.output=/user/leo_jie/user_test_hfile?-Dimporttsv.columns=HBASE_ROW_KEY,info:name,info:age?person:user?/user/leo_jie/user_test.csv繼續運行如下命令,以 bulkload 的方式把數據導入 person:user 表里:
hbase?org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles?-Dcreate.table=no?/user/leo_jie/user_test_hfile?person:user以上命令成功運行結束后我們來檢查下 HBase 和 Phoenix 兩邊的數據:HBase:
Phoenix:
上述的測試是為了說明,數據不同的寫入方式對 HBase 和 Phoenix 兩邊的數據綁定是否有不同的影響,而目前看來,似乎沒有什么特殊的地方。后續還會測試數據不同的寫入方式,對 Phoenix 索引數據的影響,在那種場景下,還會是一樣的結果嗎?讓我們拭目以待!
8. 創建多個列簇 Phoenix 映射表
這一小節補充下多列簇 Phoenix 映射表的創建,直接上建表語句:
create?table?"person"."user2"(????"id"?VARCHAR?PRIMARY?KEY,
????"info"."name"?VARCHAR,
????"info"."age"??VARCHAR,
????"info2"."name"?VARCHAR,
????"info2"."age"?VARCHAR,
????"info2"."address"?VARCHAR)
?column_encoded_bytes=0;
以 put 的方式插入一些數據,然后在 Phoenix 中做以下查詢:
對于所屬不同列簇但名稱相同的字段的查詢,一定要顯示指定字段所屬的列簇名,不然查詢時會報異常。除此之外,跟單列簇創建方式相比,倒也沒啥特別之處了。
9. Phoenix 視圖
類似 MySql 等關系型數據庫中的視圖,Phoenix 也有自己的視圖概念,其視圖的創建方式與表的創建語句類似。如果單純只是為了查詢數據,強烈建議為 HBase 表創建 Phenix 的視圖映射,此時視圖的刪除對 HBase 的源表不會造成任何影響。
之前在倒騰 Phoenix 視圖的時候,頻繁遇到各種各樣的報錯,直至現在,對于其中的有些異常,依舊不明就里。下面先直接演示能正確創建視圖的語句吧!
首先創建一張 HBase 表,create 'USER','INFO'不要為這張表創建其 Phoenix 映射表,然后運行如下創建視圖的語句。
create?view?USER(ID?VARCHAR?PRIMARY?KEY,
INFO.NAME?VARCHAR,
INFO.AGE?VARCHAR);
view
在 HBase 中插入一些數據,觀察視圖中的數據是否會實時更新。答案是,在 HBase 中插入數據,Phoenix 視圖會實時更新數據。
那么以 bulkload 的方式更新數據呢?根據上文中提到的測試方法,我們再來實施一下。答案是,以 bulkload 的方式把數據導入 HBase 中,Phoenix 依舊會實時更新數據。
反過來,我們是否可以在 Phoenix 中 upset 數據呢?
?upsert?into?USER?(ID,NAME,AGE)?values('111',?'leo111','17');upsert
視圖是只讀的,不能做修改之類的操作。此時刪掉視圖,對 HBase 源表是沒有影響的。
drop view USER;
scan 'USER'
再來說明一下當初折騰視圖時遇到的各種各樣的異常。
「HBase 源表不存在而直接創建視圖」
error1看來 Phoenix 視圖創建跟 Phoenix 表創建有很大不同啊。
「HBase 源表存在且 Phoenix 映射表也存在」
刪除掉原來的測試表,然后直接用創建 Phoenix 表的方式,同時創建出 HBase 的源表。
create?table?USER(ID?VARCHAR?PRIMARY?KEY,
INFO.NAME?VARCHAR,
INFO.AGE?VARCHAR)
column_encoded_bytes=0;
此時我們再來運行視圖創建語句。
create?view?USER(ID?VARCHAR?PRIMARY?KEY,
INFO.NAME?VARCHAR,
INFO.AGE?VARCHAR);
如果直接運行這個語句,不出意外一定會報錯,報錯信息如下:Error: ERROR 1036 (42J04): Cannot modify the primary key of a VIEW if last PK column of parent is variable length. columnName=USER.ID (state=42J04,code=1036)
table 的名字是 USER,view 的名字也是 USER,但這真的是報錯的根本原因嗎?那讓我們換一個名字來試試看。
create?view?USER_VIEW(ID?VARCHAR?PRIMARY?KEY,
INFO.NAME?VARCHAR,
INFO.AGE?VARCHAR);
繼續報錯:
Error: ERROR 505 (42000): Table is read only. (state=42000,code=505),又回到了我們剛開始的異常,HBase 源表不存在而直接創建視圖。這時候如果你一頓谷歌加百度,十有八九會遇到類似這樣的視圖創建語句。
create?view?USER_VIEW(ID?VARCHAR?PRIMARY?KEY,
INFO.NAME?VARCHAR,
INFO.AGE?VARCHAR)?as?select?*?from?USER;
指定查詢數據集,也就是 select 的語句,再映射到視圖 USER_VIEW 上,依舊報錯:
Error: ERROR 1036 (42J04): Cannot modify the primary key of a VIEW if last PK column of parent is variable length. columnName=USER_VIEW.ID (state=42J04,code=1036)
聰明的你一定會這樣修改上述的語句。
?create?view?USER_VIEW?as?select?*?from?USER;這樣的創建語句其實很類似 hive 還有其他的一些關系型數據庫。如果,你還想創建指定列的視圖呢?
?create?view?USER_VIEW_NAME?as?select?NAME?from?USER;你以為這樣寫就可以了嗎?臉黑的我又遇見了這樣的報錯。
Error: ERROR 604 (42P00): Syntax error. Mismatched input. Expecting "ASTERISK", got "NAME" at line 1, column 38. (state=42P00,code=604)
百度了一波,從大佬的博客里了解到,目前在 Phoenix 創建視圖時,子句中不能選擇字段,只能用*號,否則就會報如上錯誤。
是否可以創建語法更復雜的視圖呢?例如,我已經有了一張 USER 表,再創建一張 PAY 表,記錄每個用戶的花銷。然后以 JOIN 的方式創建視圖 USER_PAY_VIEW。
left join當前版本的視圖支持的語法比較有限,SELECT 中不能有復雜的語法,否則解析時會無法判斷結束標記。
視圖使用時,一定要注意,在沒有創建索引的情況下,不要瞎寫 SQL 語句,什么 group by,order by。否則一旦表里的數據量過大,你十有八九能遇到全表掃描,嚴重情況下影響線上業務。這樣的規則,對表的查詢同樣適用。
10. 最后
最后來總結一下 Phoenix 的常規使用吧。Phoenix 表創建時要注意大小寫,如果需要使用小寫,那么請給表名,列簇名,字段名加上英文類型的雙引號;如果你的 HBase 表數據量過大,創建表時,請盡可能提前把對應的 Phoenix 映射表也創建出來吧,最后再導入數據;針對建表時的預分區操作,文中也提到了兩種方式。如果對表僅有查詢需要,那么請考慮創建視圖,但視圖的使用又有很大的限制,使用不當就會導致全表掃描,不僅影響查詢效率,還會影響線上的業務。
11. 參考鏈接
- https://blog.csdn.net/github_39577257/article/details/95968727
據說,關注我的人都找到了對象?
總結
以上是生活随笔為你收集整理的postgres 把一个表的值转成另一个表的字段名_Phoenix系列创建Phoenix映射表的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python怎么移除字符串中的换行符(去
- 下一篇: 苹果手机怎么看视频大小