這是一份非常詳細的 Apache Phoenix SQL 命令大全和詳解。Phoenix 作為 HBase 上的 SQL 層,其語法大部分與標準 SQL 兼容,但也有許多針對 HBase 的特性擴展。
核心概念
在開始之前,請記住 Phoenix 的兩個核心概念:
- 主鍵(PRIMARY KEY):必須存在。它映射到 HBase 的 Row Key,并且所有列都會自動編碼到主鍵的列族中(除非單獨指定)。主鍵可以是復合主鍵。
- 列族(COLUMN_FAMILY):HBase 的概念。在 Phoenix 中,可以在建表時或通過
ALTER
命令為列指定列族,以實現更好的物理存儲分組。
一、DDL(數據定義語言)
1. CREATE TABLE - 創建表
創建表是 Phoenix 中最關鍵的操作,因為它直接影響到 HBase 的存儲結構和查詢性能。
基礎語法:
CREATE TABLE [IF NOT EXISTS] schema_name.table_name (column_name data_type [PRIMARY KEY] [NULL | NOT NULL] [DEFAULT value],column_name data_type [NULL | NOT NULL],...CONSTRAINT constraint_name PRIMARY KEY (column1, column2, ...)
) [TABLENAME='hbase_namespace:hbase_table',][COLUMN_FAMILY='family_name',][SALT_BUCKETS=integer],[DISABLE_WAL=false|true],[IMMUTABLE_ROWS=true|false],[COMPRESSION='GZ'|'LZ4'|'NONE'|'SNAPPY'],[TTL=integer],[UPDATE_CACHE_FREQUENCY=integer];
關鍵參數詳解:
TABLENAME
: 指定映射到的 HBase 表名。如果省略,Phoenix 會創建一個同名的 HBase 表。SALT_BUCKETS
(極重要): 加鹽。通過預分區(split
)來解決寫熱點問題。值通常是 region server 數量的倍數。強烈建議對寫密集的表使用此選項。DISABLE_WAL
: 是否禁用 HBase 的預寫日志(Write-Ahead Log)。禁用后可提高寫入速度,但存在數據丟失風險。通常用于可以容忍數據丟失的臨時數據。IMMUTABLE_ROWS
: 表是否不可變。如果為true
,則優化寫入路徑,適用于只寫入一次的數據(如日志)。COMPRESSION
: 設置 HBase 表的壓縮算法,節省存儲空間。TTL
: 行的存活時間(秒),超過時間的數據會自動被 HBase 清除。UPDATE_CACHE_FREQUENCY
: 指導客戶端何時更新元數據緩存。
示例:
-- 簡單創建表,id是主鍵(即HBase的Row Key)
CREATE TABLE my_table (id VARCHAR PRIMARY KEY,name VARCHAR,age INTEGER
);-- 使用復合主鍵((user_id, transaction_id) 共同組成Row Key)
CREATE TABLE orders (user_id VARCHAR NOT NULL,transaction_id VARCHAR NOT NULL,date DATE,amount DECIMAL(10, 2),CONSTRAINT pk PRIMARY KEY (user_id, transaction_id) -- 復合主鍵
);-- 高級創建表,指定鹽桶、壓縮、列族和TTL
CREATE TABLE event_log (event_id BIGINT NOT NULL,event_time TIMESTAMP NOT NULL,payload VARCHAR,CONSTRAINT pk PRIMARY KEY (event_id, event_time)
)
SALT_BUCKETS = 10,
COMPRESSION = 'GZ',
TTL = 86400, -- 數據保留1天(60*60*24)
UPDATE_CACHE_FREQUENCY = 3000;
2. CREATE VIEW - 創建視圖
視圖是只讀的,映射到一個已存在的 HBase 表。用于為現有 HBase 表提供 Phoenix SQL 接口。
語法:
CREATE VIEW [IF NOT EXISTS] view_name (column_name data_type [PRIMARY KEY] [NULL | NOT NULL],...
) AS SELECT * FROM existing_hbase_table;
-- 或者直接映射,但需要指定列
CREATE VIEW "my_hbase_table" ( pk VARCHAR PRIMARY KEY, "col1"."value" VARCHAR );
注意:如果 HBase 表名或列族名不是大寫,需要用雙引號引起來。
3. CREATE INDEX - 創建二級索引
二級索引可以極大提高對非主鍵列的查詢速度。
語法:
CREATE INDEX [IF NOT EXISTS] index_name
ON table_name (column_list)
[INCLUDE (include_column_list)] -- 覆蓋索引,避免回查主表
[ASYNC] -- 異步構建索引
[INDEX_TYPE='index_type']; -- 索引類型(GLOBAL, LOCAL, ...)
索引類型:
- 全局索引(GLOBAL):默認。適用于讀多寫少的場景。查詢時必須包含索引中的列才能生效,否則會全表掃描。
- 本地索引(LOCAL):適用于寫多讀少的場景。查詢時即使未完全覆蓋索引列,也能利用索引。
LOCAL
索引數據和原數據存儲在同一個 Region 中。
示例:
-- 創建全局索引
CREATE INDEX idx_name ON my_table (name);-- 創建覆蓋索引(Include),查詢age時無需回表
CREATE INDEX idx_name_include_age ON my_table (name) INCLUDE (age);-- 創建異步全局索引
CREATE INDEX async_idx ON my_table (age) ASYNC;-- 創建本地索引
CREATE LOCAL INDEX local_idx ON orders (date);
4. ALTER TABLE - 修改表
語法:
-- 添加列
ALTER TABLE table_name ADD column_name data_type [NULL | NOT NULL];-- 刪除列
ALTER TABLE table_name DROP COLUMN column_name;-- 修改列數據類型(需兼容)
ALTER TABLE table_name ALTER COLUMN column_name SET DATA_TYPE new_data_type;
示例:
ALTER TABLE my_table ADD email VARCHAR;
ALTER TABLE my_table DROP COLUMN email;
5. DROP - 刪除
語法:
-- 刪除表(也會刪除HBase中的表)
DROP TABLE [IF EXISTS] table_name;-- 刪除視圖
DROP VIEW [IF EXISTS] view_name;-- 刪除索引
DROP INDEX [IF EXISTS] index_name ON table_name;
二、DML(數據操縱語言)
1. UPSERT - 插入/更新
Phoenix 使用 UPSERT
而不是標準的 INSERT
和 UPDATE
。如果行存在則更新,不存在則插入。這直接對應 HBase 的 Put
操作。
語法:
UPSERT INTO table_name [(column1, column2, ...)]
VALUES (value1, value2, ...);UPSERT INTO table_name [(column1, column2, ...)]
SELECT ... FROM another_table;
示例:
-- 插入單條數據
UPSERT INTO my_table (id, name, age) VALUES ('001', 'Alice', 25);-- 插入多條數據(Phoenix 4.8+)
UPSERT INTO my_table VALUES ('002', 'Bob', 30), ('003', 'Charlie', 28);-- 從查詢結果插入
UPSERT INTO target_table (col1, col2)
SELECT source_col1, source_col2 FROM source_table;
2. DELETE - 刪除數據
語法:
DELETE FROM table_name [WHERE clause];
警告:如果沒有
WHERE
子句,將清空整個表!
示例:
DELETE FROM my_table WHERE id = '001';
DELETE FROM orders WHERE amount < 10;
3. SELECT - 查詢數據
語法與標準 SQL 基本一致。
語法:
SELECT [DISTINCT] column_list
FROM table_name
[WHERE clause]
[GROUP BY column_list]
[HAVING clause]
[ORDER BY column_list [ASC|DESC]]
[LIMIT number]
[OFFSET number];
特殊函數和操作:
COUNT(), SUM(), AVG(), MIN(), MAX()
: 聚合函數。SUBSTR(string, start, length)
: 子字符串函數。TO_DATE(string)
,TO_NUMBER(string)
: 類型轉換函數。EXPLAIN
: 查看查詢執行計劃,用于性能調優。
示例:
-- 簡單查詢
SELECT * FROM my_table WHERE name = 'Alice';-- 分頁查詢
SELECT id, name FROM orders ORDER BY date DESC LIMIT 10 OFFSET 20;-- 聚合查詢
SELECT user_id, SUM(amount) as total_amount
FROM orders
GROUP BY user_id
HAVING total_amount > 1000;-- 使用EXPLAIN查看執行計劃,判斷是否使用了索引
EXPLAIN SELECT * FROM my_table WHERE name = 'Alice';
-- 輸出中如果出現 `FULL SCAN`,則可能性能較差。
-- 如果出現 `RANGE SCAN OVER INDEX_NAME`,則說明索引生效。
三、系統與元數據命令
1. 查看表信息
!tables
!-- 或者
!table
此命令列出當前連接中的所有 Phoenix 表和視圖。
2. 查看表結構
!describe table_name
!-- 或者
!desc table_name
3. 查看索引
!indexes table_name
列出指定表上的所有索引。
4. 查看查詢計劃
EXPLAIN your_select_query;
5. 性能分析
EXPLAIN ANALYZE your_select_query;
不僅顯示計劃,還會實際執行并報告每個步驟花費的時間。
四、實用技巧和注意事項
-
大小寫敏感:
- 如果不加雙引號,Phoenix 會自動將表名、列名等轉換為大寫。
- 如果 HBase 中的表名或列族/列名是小寫或混合大小寫,必須在 Phoenix 中用雙引號引起來。
- 例如:
CREATE VIEW "myLowerCaseTable" (...);
-
Row Key 設計:Phoenix 的性能極度依賴 Row Key(主鍵)的設計。遵循 HBase 的最佳實踐:
- 避免單調遞增的 Row Key(如自增ID),以免造成寫熱點。使用加鹽(SALT_BUCKETS) 或 哈希 來分散寫入。
- 將常用的查詢條件放在主鍵的前面部分(對于復合主鍵)。
-
二級索引選擇:
- 全局索引:讀快寫慢,需要覆蓋索引。
- 本地索引:寫快讀慢,查詢時更靈活,無需覆蓋索引。
-
批量處理:在
sqlline.py
中,使用upsert
批量插入數據時,先執行autocommit off;
可以大幅提升性能,最后再執行commit;
。 -
JDBC 連接:在 Java 應用中,使用 Phoenix 的 JDBC 驅動來連接,URL 格式為:
jdbc:phoenix:zookeeper_quorum[:port][:/hbase-root-znode]
總結
命令類別 | 核心命令 | 主要用途和特點 |
---|---|---|
DDL | CREATE TABLE | 核心,需精心設計主鍵和鹽桶 |
CREATE INDEX | 提高查詢性能,分全局和本地 | |
ALTER TABLE / DROP | 修改結構,刪除對象 | |
DML | UPSERT | 插入和更新(HBase Put) |
SELECT | 查詢,支持大部分SQL語法 | |
DELETE | 刪除數據 | |
系統命令 | !tables , !desc | 查看元數據 |
EXPLAIN | 性能調優神器 |
建議:在測試環境中結合實際用例進行練習,并經常使用 EXPLAIN
來分析查詢性能。