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