1. 程式人生 > >Apache Phoenix基本操作(2)

Apache Phoenix基本操作(2)

1.      如何對映一個Phoenix的表到一個HBase的表?

你可以通過Create table/create view DDL語句在一個已經存在的HBase表上建立一個Phoenix表或者檢視。對於Createtable來說,我們將建立任何元資料(表,列族),這些之前都是不存在的。我們也將對於每行記錄新增一個空的key值,以便查詢時按照我們的方式(不需要在scan過程中對所有的列進行投影)。

另外需要注意的是,這些序列化的位元組的方式必須匹配在Phoenix中序列化位元組的方式。對於Varchar,Char和Unsigned_*型別,我們使用HBase位元組的方法。Char位元組僅僅為單個位元組,Unsigned型別的值大於或等於0。

如果建立一個HBase的表,如下:

create 't1', {NAME => 'f1', VERSIONS=> 5}

你有一個HBase的表,表名為t1,列族為f1。請記住,在HBase裡面,你不能模仿這KeyValues 或者行鍵的結構,你在Phoenix中指定的資訊是建立在表和列族之上的。

因此在Phoenix中,你可以建立一個對應的檢視,如下:

CREATE VIEW "t1" ( pk VARCHAR PRIMARY KEY, "f1".val VARCHAR );

pk列定義了你的行鍵的型別為VARCHAR型別,"f1".val列定義了你的HBase表包含KeyValues ,包含一個列族和列修飾符"f1".val,並且他們的值是Varchar型別的。

如果你建立HBase表時,都使用大寫名稱,如下:

create 'T1', {NAME => 'F1', VERSIONS=> 5}

你可以建立對應的Phoenix檢視,可以不需要雙引符號:

CREATE VIEW t1 ( pk VARCHAR PRIMARY KEY,f1.val VARCHAR )

或者你建立一個新的HBase表,僅僅讓Phoenix為你如下的一切事情(根本不需要使用HBase shell):

CREATE TABLE t1 ( pk VARCHAR PRIMARY KEY,val VARCHAR )

這裡補充一點Family Column:

如果在Phoenix SQL中建立table時為qualifier指定了family,如下:

CREATE TABLE "example" (my_pk bigint notnull, m1.col varchar(50), m2.col varchar(50), m3.col varchar(50) constraint pk primary key (my_pk)) ;

Phoenix primary key 與HBase rowkey 的關係:

在建立phoenix table時,必須指定一個primary key,但是這個主鍵我們不一定用到。如果我們想在用Phoenix建立table時,讓Phoniex的主鍵自動地與HBase的rowkey對應起來,則可以用以下方式來建立:

create table"{空間名:表名}"  ("pk"varchar primary key, "{1}" varchar, "{2}" varchar, "{3}" varchar)  salt_buckets=10;

這樣,Phoniex的主鍵(名為pk)就自動地與HBase的rowkey對應起來了。

注:

(1)    自己定義的HBase中的 HTableName,ColumnFamily,以及Column,需要和Phoenix中保持一致。(最好都用大寫)

(2)    Phoenix操作HBase,我們有兩種方式,建立表和建立檢視。

這兩種方式的區別如下:

建立表的話,可讀可寫,就可以對HBase進行插入,查詢,刪除操作。

建立檢視的話,是隻讀的,一般就只可以進行查詢操作

刪除Phoenix中表時,會將HBase對應的表刪掉。但是刪除Phoenix檢視操作,卻不會影響HBase原始表的結構。

因為使用Phoenix,建立表後,會自動和HBase建立關聯對映。當你使用Phoenix刪除和HBase之間的關係時,就會將HBase中的表也刪掉了。所以用檢視,會對原始的HBase表影響小一些。

2.      優化Phoenix有哪些提示?

2.1   使用Salting方式提升讀寫效能

Salting能夠通過預分割槽(pre-splitting)資料到多個region中來顯著提升讀寫效能。

Salting 翻譯成中文是加鹽的意思,本質是在hbase中,rowkey的byte陣列的第一個位元組位置設定一個系統生成的byte值,這個byte值是由主鍵生成rowkey的byte陣列做一個雜湊演算法,計算得來的。Salting之後可以把資料分佈到不同的region上,這樣有利於phoenix併發的讀寫操作。

CREATE TABLE TEST (HOST VARCHAR NOT NULL PRIMARY KEY, DESCRIPTION  VARCHAR) SALT_BUCKETS=16;

注:

(1)      理性情況下,對於擁有四核CPUs的16個RegionServer的HBase叢集來說,選擇salt buckets在32-64個以獲取較好的效能。Salt bucket的個數必須在1-256之間。

(2)      這裡說明一下Salted Tables

為了避免讀寫HBase表資料時產生hot-spot問題,我們使用Phoenix來建立表時可以採用salted table。

salted table可以自動在每一個rowkey前面加上一個位元組,這樣對於一段連續的rowkeys,它們在表中實際儲存時,就被自動地分佈到不同的region中去了。當指定要讀寫該段區間內的資料時,也就避免了讀寫操作都集中在同一個region上。

簡而言之,如果我們用Phoenix建立了一個saltedtable,那麼向該表中寫入資料時,原始的rowkey的前面會被自動地加上一個byte(不同的rowkey會被分配不同的byte),使得連續的rowkeys也能被均勻地分佈到多個regions。

建立salted table:

CREATE TABLE "test:salted" (pk VARCHAR PRIMARY KEY, c1 VARCHAR, c2 VARCHAR, c3 VARCHAR) SALT_BUCKETS=5;

上述語句建立了一個名為"test:salted"的table(HBase中事先要建立名為test的namespace),SALT_BUCKETS=5 說明該salted table由5個bucket組成(必須在1~256之間)。

上面在建立table時,沒有指定family,只指定了qualifier(c1, c2, c3),因此在HBase shell向表salted寫入資料時,column name 要寫成'0:[qualifier]'(如'0:c1'),否則HBase會報錯。

另外,建立salted table需要注意兩點:

A. 建立salted table後,應該使用Phoenix SQL來讀寫資料,而不要混合使用Phoenix SQL和HBase API

B. 如果通過Phoenix建立了一個salted table,那麼只有通過Phoenix SQL插入資料才能使得被插入的原始rowkey前面被自動加上一個byte,通過HBase shell插入資料無法prefix原始的rowkey

4.2 Pre-split

Salting能夠自動的設定表預分割槽,但是你得去控制表是如何分割槽的,所以在建phoenix表時,可以精確的指定要根據什麼值來做預分割槽,比如:

CREATE TABLE TEST (HOST VARCHAR NOT NULL PRIMARY KEY, DESCRIPTION VARCHAR) SPLIT ON ('CS','EU','NA');

4.3 使用多列族

列族包含相關的資料都在獨立的檔案中,在Phoenix設定多個列族可以提高查詢效能。例如:

CREATE TABLE TEST (MYKEY VARCHAR NOT NULL PRIMARY KEY, A.COL1 VARCHAR,A.COL2 VARCHAR, B.COL3 VARCHAR);

4.4 使用壓縮

在資料量大的表上使用壓縮演算法來提高效能。

例如:

CREATE TABLE TEST (HOST VARCHAR NOT NULL PRIMARY KEY, DESCRIPTION VARCHAR) COMPRESSION='GZ';

4.5 建立二級索引

下面將會介紹。

4.6 優化HBase叢集引數

4.7 優化Phoenix引數

3.      如何在表上建立二級索引?

從Phoenix 2.1版本開始,Phoenix支援可變和不可變(資料插入後不再更新)資料建立二級索引。Phoenix 2.0版本僅支援在不可變資料建立二級索引。

示例:

3.1   建立表

不可變表:create table test (mykey varchar primary key, col1 varchar,col2 varchar) IMMUTABLE_ROWS=true;

可變表:create table test (mykey varchar primary key, col1 varchar,col2 varchar);

3.2   在col2建立索引

create index idx on test (col2);

3.3   在col1和一個覆蓋列col2上建立索引

create index idx on test (col1) include (col2);

在test表中upsert資料,Phoenix查詢優化器將選擇使用合適的索引。你可以使用explain plan進行檢視(http://phoenix.apache.org/language/index.html#explain)。當然你也可以使用hint(http://phoenix.apache.org/language/index.html#hint)方式指定一個需要使用的索引。

4.      為什麼我的二級索引沒有被使用?

除非所有查詢使用的列被索引或者覆蓋列,否則二級索引不會被使用。所有列組成資料表的主鍵將被包含在索引中。

例子:

建立表:

create table usertable (id varchar primary key,firstname varchar, lastname varchar);

create index idx_name on usertable (firstname);

這裡建立二級索引時報錯了如下:

java.sql.SQLException: ERROR 1029 (42Y88):Mutable secondary indexes must have the hbase.regionserver.wal.codec propertyset to org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec in thehbase-sites.xml of every region server. tableName=IDX

根據錯誤日誌,需要在RegionServer每個節點的hbase-site.xml中配置支援可變的二級索引的配置項:

<property>

 <name>hbase.regionserver.wal.codec</name>

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

</property>

<property>

<name>hbase.region.server.rpc.scheduler.factory.class</name> <value>org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory</value>

<description>Factory to create the Phoenix RPC Scheduler that usesseparate queues for index and metadata updates</description>

</property>

<property>

 <name>hbase.rpc.controllerfactory.class</name>

<value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory</value>

<description>Factory to create the Phoenix RPCScheduler that uses separate queues for index and metadataupdates</description>

</property>

<property>

<name>hbase.coprocessor.regionserver.classes</name> <value>org.apache.hadoop.hbase.regionserver.LocalIndexMerger</value>

</property>

在每一個Master的hbase-site.xml中加入如下的屬性:

<property>

  <name>hbase.master.loadbalancer.class</name>

<value>org.apache.phoenix.hbase.index.balancer.IndexLoadBalancer</value>

</property>

<property>

   <name>hbase.coprocessor.master.classes</name>

  <value>org.apache.phoenix.hbase.index.master.IndexMasterObserver</value>

</property>

查詢:

select id, firstname, lastname from usertablewhere firstname = 'foo';

請注意這個查詢不會用到索引,因為lastname不是被索引或者覆蓋列的部分。我們可以查詢執行計劃進行驗證,比如:

0:jdbc:phoenix:SZB-L0023780:2181:/hbase114> explain select id, firstname,lastname from usertable where firstname = 'foo';

+------------------------------------------------------------------------------------------------------------------+

|                                PLAN                                 |

+------------------------------------------------------------------------------------------------------------------+

| CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBINFULL SCAN OVER USERTABLE     |

|    SERVER FILTER BY FIRSTNAME = 'foo'                                   |

+------------------------------------------------------------------------------------------------------------------+

為了修改這個建立索引的問題,要麼對lastname建立索引,要麼建立覆蓋索引,如下:

drop index idx_name on usertable;

create index idx_name on usertable (firstname) include(lastname);

我們再次驗證一下

0: jdbc:phoenix:SZB-L0023780:2181:/hbase114>explain select id, firstname, lastname from usertable where firstname = 'foo';

+-------------------------------------------------------------------------------------------------------------------------+

|                                PLAN                                     |

+-------------------------------------------------------------------------------------------------------------------------+

| CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBINRANGE SCAN OVER IDX_NAME ['foo']  |

+------------------------------------------------------------------------------------------------------------------------+

根據執行計劃的結果,可以看出使用了IDX_NAME索引。

5.      Phoenix有多快,為什麼如此之快?

全表掃描100M的資料量通過在20s完成(中等大小叢集的窄表)。如果查詢時增加一些索引列過濾的話,時間會減低到毫秒級別。

為什麼Phoenix全表掃描還那麼快?

(1)      Phoenix使用region邊界拆分查詢,並且客戶端使用配置的執行緒數進行並行查詢。

(2)      聚合操作將在服務端的協處理器中完成

6.      為什麼我的查詢不走Range scan?

首先看一下建立表的語句:

CREATE TABLE TEST (pk1 char(1) not null, pk2char(1) not null, pk3 char(1) not null, non_pk varchar CONSTRAINT PK PRIMARY KEY(pk1, pk2, pk3));

Range Scan意味著僅會掃描表的一部分子集的行記錄。如果你使用主鍵約束中的首個列開頭的話,就會使用Range Scan方式。

比如下面的查詢將會使用Full Scan方式:

select * from test where pk2='x' and pk3='y';

而下面的查詢將會使用Range Scan方式:

select * from test where pk1='x' and pk2='y';

DEGENERATE SCAN意味著一個查詢不可能返回任何行記錄。

FULL SCAN意味著將掃描表的所有行記錄。

SKIP SCAN意味著要麼表的部分子集,要麼掃描表的所有記錄,然而它將根據過濾條件跳過大量的記錄。在一些情況下,當你的leading primary key columns的基數比較低時,它往往比FULL SCAN更有效率。

7.      我應該快取Phoenix JDBC連線嗎?

No,沒有必要快取Phoenix JDBC連線。

Phoenix的連線物件不同於絕大部分的JDBC連線,因為其是底層是HBase連線的。如果Phoenix連續被重用,有可能之前使用的使用者留下的HBase連線狀態並不是良好的,所以最好還是新建立一個Phoenix連線,可以避免潛在的問題。

8.      為什麼執行upsert操作時,Phoenix新增一個empty/dummy的KeyValue?

我們先來看一下示例:

create table HADOOP (rk Integer primarykey,info.name varchar ,info.score Integer );

upsert into HADOOP values(1,'Hadoop',90);

檢視HBase的表內容:

hbase(main):037:0> scan 'HADOOP'

ROW                 COLUMN+CELL                                                                                                                                  

 \x80\x00\x00\x01   column=INFO:NAME, timestamp=1472634053972,value=Hadoop

 \x80\x00\x00\x01   column=INFO:SCORE, timestamp=1472634053972,value=\x80\x00\x00Z

 \x80\x00\x00\x01   column=INFO:_0, timestamp=1472634053972,value=x

我們再通過Phoenix插入一行記錄:

upsert into HADOOP values(2,'Spark',95);

再次檢視HBase的表內容:

hbase(main):037:0> scan 'HADOOP'

ROW                 COLUMN+CELL                                                                                                                                  

 \x80\x00\x00\x01   column=INFO:NAME, timestamp=1472634053972, value=Hadoop

 \x80\x00\x00\x01   column=INFO:SCORE, timestamp=1472634053972,value=\x80\x00\x00Z

 \x80\x00\x00\x01   column=INFO:_0, timestamp=1472634053972,value=x

 \x80\x00\x00\x02   column=INFO:NAME, timestamp=1472634140841,value=Spark

 \x80\x00\x00\x02   column=INFO:SCORE, timestamp=1472634140841,value=\x80\x00\x00_

 \x80\x00\x00\x02   column=INFO:_0, timestamp=1472634140841,value=x

可以發現針對每一行,都會增加一列_0

empty/dummy的KeyValue(列修飾符_0)是需要的,為了確保給定的列能夠被所有行訪問,這是從提升查詢效能方面考慮的。

據你所知,資料是以KeyValues形式儲存在HBase中的,意味著全部的行鍵儲存著每個列值。這也意味著除非至少有一個列儲存,否則行鍵根本不儲存資料。

這部分內容,後續我們有時間從原始碼層面給大家說明一下。

9.      如何將帶有Schema的表移到namespace中?

對於基於Kerberos的環境來說,執行的使用者需要有admin許可權建立namespace。

表將僅僅對映到名稱為schema_name的namespace中,目前不支援遷移已經存在的表到不同的schema或者namespace。

我們來看一下測試過程:

[[email protected]]$ bin/psql.py SZB-L0023780:2181:hbase114 -mmyworld.HADOOP

Starting upgrading table:myworld.HADOOP...please don't kill it in between!!

java.lang.IllegalArgumentException:phoenix.schema.isNamespaceMappingEnabled is not enabled!!

         atorg.apache.phoenix.util.UpgradeUtil.upgradeTable(UpgradeUtil.java:1717)

         atorg.apache.phoenix.util.PhoenixRuntime.main(PhoenixRuntime.java:221)

可以看到需要設定引數允許namespace mapping。

<property>

   <name>phoenix.schema.isNamespaceMappingEnabled</name>

   <value>true</value>

</property>

這裡一定要注意:如果設定為true,建立的帶有schema的表將對映到一個namespace,這個需要客戶端和服務端同時設定。一旦設定為true,就不能回滾了。舊的客戶端將無法再正常工作。所以建議大家都檢視官方文件,確定後再進行設定。

示例:將表“table_name”移動到“schema_name”的namespace中。

bin/psql.py <zookeeper> -m<schema_name>.<table_name>

相關推薦

Apache Phoenix基本操作(2)

1.      如何對映一個Phoenix的表到一個HBase的表?你可以通過Create table/create view DDL語句在一個已經存在的HBase表上建立一個Phoenix表或者檢視。對於Createtable來說,我們將建立任何元資料(表,列族),這些之前

Apache Phoenix基本操作(1)

本篇我們將介紹phoenix的一些基本操作。1.      如何使用Phoenix輸出Hello World?1.1   使用sqlline終端命令sqlline.py SZB-L0023780:2181:/hbase1140:jdbc:phoenix:SZB-L002378

Git基礎入門(四)Git基本操作2

git 操作 基礎忽略文件: 在實際開發過程中總有些文件無需納入Git的管理,比如日誌文件、臨時文件等 在這種情況下,我們可以在工作目錄中創建一個名為.gitignore的文件,列出要忽略的文件名或者表達式 例:cat .gitignore *.[oa]

linux 基本操作2

pgrep 查詢條件 pstree init 6 elf raid6 可能 組合 stop RAID陣列概述? 廉價冗余磁盤陣列– Redundant Arrays of Inexpensive Disks– 通過硬件/軟件技術,將多個較小/低速的磁盤整合成一個大磁盤 –

數據庫的基本操作2

mysqlmysql-day03一、mysql存儲引擎1.1 存儲引擎介紹: 是mysql數據庫軟件自帶的功能程序,每種存儲引擎的功能和數據存儲方式也不同存儲引擎就處理表的處理器 1.2 查看數據庫服務支持的存儲引擎有那些?mysql> show engines;InnoDB

數據結構基本操作2

span 不能 maxsize tee 刪除 let error std 實現 1 //順序表的查找 2 //按值查找 3 //在L中查找與e 相同的數據元素位置 4 int LocateElem(Sqlist L,ElemType e){ 5 for

OpenCV學習(5) Mat的基本操作(2)

http://www.cnblogs.com/mikewolf2002/p/3320734.html      本章我們學習一下Mat中的常用操作,因為在後面其它的教程中,我們經常要對影象進行各種處理,也要使用這些操作。   一、 Mat

linux的基本操作2

/dev/ha[a-d]    IDE硬碟(過時了)/dev/sd[a-p]    U盤,scsi,sata,ssd硬碟(流行)/dev/cdrom     光碟 CD-ROM/dev/mouse    滑鼠 fdisk -l          &

Linux作業系統基本操作 2

vim的常用功能 1.1 vim的三種模式及作用: 1)普通模式 瀏覽檔案 2)插入模式 對檔案內容進行編輯,此時就可以寫入程式,按Esc可回到命令模式。 3)命令模式 臨時更改vim的工作分那個是,對字元進行批量處理, 永久更改vim需要編輯

例題SQL語句詳解-資料庫基本操作2

1.4 表的操作 1.4.1 顯示所有表 語法: show tables 1.4.2 建立表 語法: create table [if not exists] 表名( 欄位名 資料型別 [null|not null] [auto_in

Mysql資料庫基本操作(2)

-- 資料庫的操作 -- 連結資料庫 mysql -uroot -p mysql -uroot -pmysql -- 退出資料庫 exit/quit/ctrl+d -- sql語句最後需要有分號;結尾 -- 顯示資料庫版本

hadoop 2.7.3基本操作

dir 不出 管理 查看 運行 oca 好的 nbsp 資源管理 ./bin/hdfs dfs -mkdir -p input 新建文件夾 YARN 有個好處是可以通過 Web 界面查看任務的運行情況:http://localhost:8088/cluster 但 Y

linux雲自動化運維基礎知識2(系統的基本操作

linux運維切換用戶 如圖所示:在命令提示符之後輸入su - username 註意:高級用戶切換到低級用戶不需要密碼,低級用戶切換身份需要密碼。註意:此處密碼無回顯。2.虛擬控制臺:Ctrl+Alt+F(1|7) 進入圖形 Ctrl+Alt+F(2~6) 進入虛擬控制

2、hive的基本操作

like -s txt code del class ext data 數據 1、創建表 hive>CREATE TABLE userTables(id INT,name STRING); 或者 hive> CREATE TABLE userTabl

手動配置wamp環境(2)--MySQL安裝與基本操作

密碼 環境 rdb amp tro 啟動 nal margin alt MySQL數據庫簡介 MySQL是一個關系型數據庫管理系統,由瑞典MySQL AB 公司開發,目前屬於 Oracle 旗下產品。MySQL 最流行的關系型數據庫管理系統,在 WEB 應用方面MySQL

SpringMVC基本操作2

正常 esp 模型 over edi 錯誤 handle 之前 表現 1.)使用 POJO 對象綁定請求參數值 ? Spring MVC 會按請求參數名和 POJO 屬性名進行自動匹 配,自動為該對象填充屬性值。支持級聯屬性。 如:dept.deptId、dept.addr

web自動化2-selenium基本操作之元素定位

main .com blog text lin div spa wid 操作 id driver.find_elenment_by_id("kw") name driver.find_element_by_name("kw") class name diver.find

MySQL數據庫操作2基本操作

大於 ase 存在 delete div .... desc 搜索 查看數據庫 創建數據庫:CREATE DATABASE [IF NOT EXISTS] 庫名例子:CREATE DATABASE `mydb`;CREATE DATABASE IF NOT EXISTS `

2.QT字符串及一些基本操作

spa pac body slot exp str delet str2 AR mainwindow.h 1 #ifndef MAINWINDOW_H 2 #define MAINWINDOW_H 3 4 #include <QMainWindow>

matlab基本操作2

sin res 9.png 一個 nbsp 分享圖片 輸出 .com 返回 %求特征值和特征向量 x=0:0.01:50; A=[1 2 3 12;4 5 6 11;7 8 9 10;2 3 4 5]; B=[2 7;3 4]; eig(A); % ans = % %