HBase Phoenix集成 #
一、Phoenix概述 #
Phoenix是构建在HBase之上的SQL层,允许使用SQL语句操作HBase。
1.1 Phoenix特点 #
text
Phoenix特点
├── SQL支持
│ └── 标准SQL语法
│
├── JDBC驱动
│ └── 兼容JDBC接口
│
├── 索引支持
│ └── 二级索引
│
├── 事务支持
│ └── ACID事务
│
└── 性能优化
└── 查询优化器
1.2 Phoenix架构 #
text
┌─────────────────────────────────────────────────────────────────────┐
│ Phoenix 架构 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Application │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ JDBC / Phoenix Client │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Phoenix Query Server │ │
│ │ - SQL Parser │ │
│ │ - Query Optimizer │ │
│ │ - Query Executor │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ HBase │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
二、Phoenix安装 #
2.1 下载安装 #
bash
# 下载Phoenix
wget https://archive.apache.org/dist/phoenix/phoenix-5.1.2/phoenix-hbase-2.4-5.1.2-bin.tar.gz
# 解压
tar -zxvf phoenix-hbase-2.4-5.1.2-bin.tar.gz -C /opt/
# 创建软链接
ln -s /opt/phoenix-hbase-2.4-5.1.2-bin /opt/phoenix
2.2 配置 #
bash
# 复制Phoenix jar包到HBase lib目录
cp /opt/phoenix/phoenix-server-hbase-2.4-5.1.2.jar /opt/hbase/lib/
# 重启HBase
stop-hbase.sh
start-hbase.sh
2.3 连接Phoenix #
bash
# 命令行连接
/opt/phoenix/bin/sqlline.py localhost:2181
# 或使用sqlline
/opt/phoenix/bin/sqlline.py zk1,zk2,zk3:2181
三、Phoenix SQL基础 #
3.1 创建表 #
sql
-- 创建表
CREATE TABLE user (
id VARCHAR PRIMARY KEY,
name VARCHAR,
age INTEGER,
email VARCHAR
);
-- 创建表(指定列族)
CREATE TABLE user (
id VARCHAR PRIMARY KEY,
info.name VARCHAR,
info.age INTEGER,
info.email VARCHAR
);
-- 创建表(指定压缩)
CREATE TABLE user (
id VARCHAR PRIMARY KEY,
name VARCHAR,
age INTEGER
) COMPRESSION='SNAPPY';
-- 创建表(预分区)
CREATE TABLE user (
id VARCHAR PRIMARY KEY,
name VARCHAR,
age INTEGER
) SPLIT ON ('10', '20', '30', '40');
3.2 插入数据 #
sql
-- 插入数据
UPSERT INTO user (id, name, age, email)
VALUES ('user001', '张三', 25, 'zhangsan@example.com');
UPSERT INTO user (id, name, age, email)
VALUES ('user002', '李四', 30, 'lisi@example.com');
-- 批量插入
UPSERT INTO user (id, name, age)
SELECT id, name, age FROM user_temp;
3.3 查询数据 #
sql
-- 查询所有数据
SELECT * FROM user;
-- 条件查询
SELECT * FROM user WHERE age > 20;
-- 排序查询
SELECT * FROM user ORDER BY age DESC;
-- 分页查询
SELECT * FROM user LIMIT 10 OFFSET 0;
-- 聚合查询
SELECT COUNT(*) FROM user;
SELECT AVG(age) FROM user;
SELECT MAX(age), MIN(age) FROM user;
-- 分组查询
SELECT age, COUNT(*) FROM user GROUP BY age;
-- 连接查询
SELECT u.name, o.amount
FROM user u
JOIN orders o ON u.id = o.user_id;
3.4 更新数据 #
sql
-- 更新数据(Phoenix使用UPSERT)
UPSERT INTO user (id, name, age) VALUES ('user001', '张三丰', 26);
-- 条件更新
UPSERT INTO user (id, name, age)
SELECT id, name, age + 1 FROM user WHERE id = 'user001';
3.5 删除数据 #
sql
-- 删除数据
DELETE FROM user WHERE id = 'user001';
-- 删除所有数据
DELETE FROM user;
3.6 删除表 #
sql
-- 删除表
DROP TABLE user;
-- 删除表(如果存在)
DROP TABLE IF EXISTS user;
四、Phoenix索引 #
4.1 全局索引 #
sql
-- 创建全局索引
CREATE INDEX idx_user_name ON user (name);
-- 创建覆盖索引
CREATE INDEX idx_user_name_age ON user (name) INCLUDE (age, email);
-- 使用索引
SELECT name, age FROM user WHERE name = '张三';
4.2 本地索引 #
sql
-- 创建本地索引
CREATE LOCAL INDEX idx_local_name ON user (name);
-- 本地索引特点
-- 数据和索引在同一Region
-- 适合写多读少场景
4.3 函数索引 #
sql
-- 创建函数索引
CREATE INDEX idx_lower_name ON user (LOWER(name));
-- 使用函数索引
SELECT * FROM user WHERE LOWER(name) = '张三';
4.4 索引管理 #
sql
-- 查看索引
!indexes user
-- 删除索引
DROP INDEX idx_user_name ON user;
-- 禁用索引
ALTER INDEX idx_user_name ON user DISABLE;
-- 重建索引
ALTER INDEX idx_user_name ON user REBUILD;
4.5 异步索引 #
sql
-- 创建异步索引
CREATE INDEX idx_async_name ON user (name) ASYNC;
-- 使用MapReduce构建索引
./bin/phoenix-sqlline.py -m mycluster:2181:/hbase -t idx_async_name
五、Phoenix视图 #
5.1 创建视图 #
sql
-- 创建视图(不修改HBase数据)
CREATE VIEW user_view (
id VARCHAR PRIMARY KEY,
name VARCHAR,
age INTEGER
);
-- 基于已有表创建视图
CREATE VIEW user_info AS
SELECT id, name, age FROM user;
5.2 视图操作 #
sql
-- 查询视图
SELECT * FROM user_view;
-- 删除视图
DROP VIEW user_view;
六、Phoenix序列 #
6.1 创建序列 #
sql
-- 创建序列
CREATE SEQUENCE user_seq START WITH 1 INCREMENT BY 1;
-- 创建序列(带缓存)
CREATE SEQUENCE user_seq START WITH 1 INCREMENT BY 1 CACHE 100;
6.2 使用序列 #
sql
-- 获取下一个值
SELECT NEXT VALUE FOR user_seq;
-- 获取当前值
SELECT CURRENT VALUE FOR user_seq;
-- 使用序列插入
UPSERT INTO user (id, name)
VALUES (NEXT VALUE FOR user_seq, '张三');
6.3 管理序列 #
sql
-- 删除序列
DROP SEQUENCE user_seq;
七、Phoenix JDBC #
7.1 连接字符串 #
java
// 连接字符串
String url = "jdbc:phoenix:zk1,zk2,zk3:2181";
// 带认证连接
String url = "jdbc:phoenix:zk1,zk2,zk3:2181:/hbase:user:password";
7.2 JDBC示例 #
java
import java.sql.*;
public class PhoenixJDBC {
public static void main(String[] args) throws Exception {
// 加载驱动
Class.forName("org.apache.phoenix.jdbc.PhoenixDriver");
// 获取连接
String url = "jdbc:phoenix:localhost:2181";
Connection conn = DriverManager.getConnection(url);
// 创建Statement
Statement stmt = conn.createStatement();
// 执行查询
ResultSet rs = stmt.executeQuery("SELECT * FROM user");
// 遍历结果
while (rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
int age = rs.getInt("age");
System.out.println(id + " - " + name + " - " + age);
}
// 关闭连接
rs.close();
stmt.close();
conn.close();
}
}
7.3 PreparedStatement #
java
// 使用PreparedStatement
String sql = "SELECT * FROM user WHERE age > ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, 20);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("name"));
}
rs.close();
pstmt.close();
7.4 批量操作 #
java
// 批量插入
PreparedStatement pstmt = conn.prepareStatement(
"UPSERT INTO user (id, name, age) VALUES (?, ?, ?)"
);
for (int i = 0; i < 1000; i++) {
pstmt.setString(1, "user" + i);
pstmt.setString(2, "用户" + i);
pstmt.setInt(3, 20 + i % 50);
pstmt.addBatch();
}
pstmt.executeBatch();
conn.commit();
pstmt.close();
八、Phoenix性能优化 #
8.1 索引优化 #
text
索引优化建议
├── 选择合适的索引类型
│ ├── 全局索引:读多写少
│ └── 本地索引:写多读少
│
├── 使用覆盖索引
│ └── INCLUDE子句避免回表
│
├── 避免索引失效
│ ├── 使用索引列
│ └── 避免函数操作
│
└── 定期维护索引
└── 重建索引
8.2 查询优化 #
sql
-- 使用Hint强制使用索引
SELECT /*+ INDEX(user idx_user_name) */ * FROM user WHERE name = '张三';
-- 使用覆盖索引
SELECT name, age FROM user WHERE name = '张三';
-- 限制返回行数
SELECT * FROM user LIMIT 100;
-- 使用分页
SELECT * FROM user LIMIT 100 OFFSET 0;
8.3 表设计优化 #
sql
-- 使用压缩
CREATE TABLE user (
id VARCHAR PRIMARY KEY,
name VARCHAR
) COMPRESSION='SNAPPY';
-- 预分区
CREATE TABLE user (
id VARCHAR PRIMARY KEY,
name VARCHAR
) SPLIT ON ('10', '20', '30');
-- 设置版本数
CREATE TABLE user (
id VARCHAR PRIMARY KEY,
name VARCHAR
) VERSIONS=3;
九、Phoenix与HBase映射 #
9.1 映射已有HBase表 #
sql
-- 映射已有HBase表
CREATE VIEW "hbase_table" (
pk VARCHAR PRIMARY KEY,
"cf"."col1" VARCHAR,
"cf"."col2" INTEGER
);
-- 注意:表名和列族名需要用双引号
9.2 创建表映射 #
sql
-- 创建表(同时创建HBase表)
CREATE TABLE "hbase_table" (
pk VARCHAR PRIMARY KEY,
"cf"."col1" VARCHAR,
"cf"."col2" INTEGER
) COLUMN_ENCODED_BYTES=0;
十、常见问题 #
10.1 索引不生效 #
sql
-- 问题:查询未使用索引
-- 解决:使用Hint或检查索引列
-- 使用Hint
SELECT /*+ INDEX(user idx_name) */ * FROM user WHERE name = '张三';
-- 检查索引
!indexes user
10.2 性能问题 #
sql
-- 问题:查询慢
-- 解决:优化查询和索引
-- 使用EXPLAIN分析
EXPLAIN SELECT * FROM user WHERE name = '张三';
-- 查看执行计划
10.3 连接问题 #
bash
# 问题:无法连接
# 解决:检查ZooKeeper配置
# 检查ZooKeeper
zkCli.sh -server localhost:2181
ls /hbase
十一、总结 #
本节介绍了Phoenix集成:
| 功能 | 说明 |
|---|---|
| SQL支持 | 标准SQL语法操作HBase |
| 索引 | 全局索引、本地索引、覆盖索引 |
| JDBC | 标准JDBC接口 |
| 视图 | 虚拟表,不修改数据 |
| 序列 | 自增序列 |
下一步,让我们学习二级索引!
最后更新:2026-03-27