apache phoenix sql 命令大全详解
这是一份非常详细的 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
来分析查询性能。