排序与分页 #
一、排序概述 #
1.1 排序特点 #
Cassandra的排序有以下特点:
text
排序特点:
✓ 仅支持聚簇列排序
✓ 排序方向必须与表定义一致
✓ 默认按聚簇列升序
✓ 可通过CLUSTERING ORDER指定
1.2 排序限制 #
text
排序限制:
不支持
├── 非聚簇列排序
├── 多方向排序(部分支持)
└── ORDER BY + ALLOW FILTERING
限制
├── 必须指定分区键
└── 排序方向受表定义约束
二、CLUSTERING ORDER #
2.1 表定义排序 #
sql
-- 默认升序
CREATE TABLE events_asc (
device_id TEXT,
event_time TIMESTAMP,
data TEXT,
PRIMARY KEY (device_id, event_time)
);
-- event_time升序排列
-- 指定降序
CREATE TABLE events_desc (
device_id TEXT,
event_time TIMESTAMP,
data TEXT,
PRIMARY KEY (device_id, event_time)
) WITH CLUSTERING ORDER BY (event_time DESC);
-- event_time降序排列
-- 多列排序
CREATE TABLE multi_sort (
user_id UUID,
event_date DATE,
event_time TIMESTAMP,
data TEXT,
PRIMARY KEY (user_id, event_date, event_time)
) WITH CLUSTERING ORDER BY (event_date DESC, event_time ASC);
-- event_date降序,event_time升序
2.2 排序方向 #
text
排序方向规则:
单聚簇列
├── ASC:升序(默认)
└── DESC:降序
多聚簇列
├── 每列可独立指定方向
├── 必须按顺序指定
└── 方向在表创建时确定
三、ORDER BY使用 #
3.1 基本排序 #
sql
-- 按聚簇列排序
SELECT * FROM events
WHERE device_id = 'device-001'
ORDER BY event_time DESC;
-- 多列排序
SELECT * FROM multi_sort
WHERE user_id = ?
ORDER BY event_date DESC, event_time ASC;
3.2 排序规则 #
text
ORDER BY规则:
必须匹配表定义
├── 方向必须一致
├── 列顺序必须一致
└── 不能只指定部分列
示例(CLUSTERING ORDER BY (event_date DESC, event_time ASC)):
✓ ORDER BY event_date DESC
✓ ORDER BY event_date DESC, event_time ASC
✗ ORDER BY event_date ASC(方向不一致)
✗ ORDER BY event_time ASC(跳过event_date)
3.3 排序示例 #
sql
-- 表定义
CREATE TABLE orders (
user_id UUID,
order_date DATE,
order_id UUID,
amount DECIMAL,
PRIMARY KEY (user_id, order_date, order_id)
) WITH CLUSTERING ORDER BY (order_date DESC, order_id ASC);
-- 有效排序
SELECT * FROM orders WHERE user_id = ?
ORDER BY order_date DESC;
SELECT * FROM orders WHERE user_id = ?
ORDER BY order_date DESC, order_id ASC;
-- 无效排序
-- SELECT * FROM orders WHERE user_id = ?
-- ORDER BY order_date ASC; -- 方向不一致
-- SELECT * FROM orders WHERE user_id = ?
-- ORDER BY amount DESC; -- 非聚簇列
四、分页机制 #
4.1 LIMIT分页 #
sql
-- 限制返回行数
SELECT * FROM users LIMIT 10;
-- 组合条件
SELECT * FROM orders
WHERE user_id = ?
LIMIT 100;
4.2 基于主键分页 #
sql
-- 第一页
SELECT * FROM orders
WHERE user_id = ?
LIMIT 100;
-- 第二页(使用上一页最后一条记录的主键)
SELECT * FROM orders
WHERE user_id = ?
AND (order_date, order_id) > (?, ?)
LIMIT 100;
4.3 Token分页 #
sql
-- 使用Token分页
SELECT * FROM users
WHERE token(user_id) > token(?)
LIMIT 100;
-- 组合排序
SELECT * FROM users
WHERE token(user_id) > token(?)
LIMIT 100;
五、驱动分页 #
5.1 Java驱动 #
java
// 自动分页
Statement statement = QueryBuilder.select()
.all()
.from("orders")
.where(QueryBuilder.eq("user_id", userId))
.setFetchSize(100);
ResultSet resultSet = session.execute(statement);
// 迭代时自动获取下一页
for (Row row : resultSet) {
// 处理每一行
System.out.println(row.getUUID("order_id"));
}
// 手动分页
ResultSet resultSet = session.execute(statement);
while (!resultSet.isFullyFetched()) {
resultSet.fetchMoreResults();
// 处理当前页
for (Row row : resultSet) {
// 处理行
}
}
5.2 Python驱动 #
python
from cassandra.query import SimpleStatement
# 自动分页
query = "SELECT * FROM orders WHERE user_id = %s"
statement = SimpleStatement(query, fetch_size=100)
rows = session.execute(statement, (user_id,))
for row in rows:
# 处理每一行
print(row.order_id)
# 手动分页
rows = session.execute(statement, (user_id,))
while rows:
for row in rows.current_rows:
# 处理行
pass
if rows.has_more_pages:
rows = session.execute(statement, (user_id,), paging_state=rows.paging_state)
else:
break
5.3 Go驱动 #
go
// 自动分页
query := session.Query(
"SELECT * FROM orders WHERE user_id = ?",
userId,
).PageSize(100)
iter := query.Iter()
for {
row := map[string]interface{}{}
if !iter.MapScan(row) {
break
}
// 处理行
}
六、分页最佳实践 #
6.1 分页大小选择 #
text
分页大小建议:
小数据
├── fetch_size: 100-500
└── 适合交互式查询
中等数据
├── fetch_size: 500-1000
└── 适合批量处理
大数据
├── fetch_size: 1000-5000
└── 适合数据导出
注意
├── 过小:频繁请求
├── 过大:内存压力
└── 根据数据大小调整
6.2 分页优化 #
text
分页优化建议:
1. 使用合适fetch_size
└── 平衡请求次数和内存
2. 避免深度分页
└── 使用Token范围分页
3. 监控分页性能
└── 使用tracing分析
4. 处理分页状态
└── 保存paging_state用于断点续传
七、排序与分页组合 #
7.1 排序分页 #
sql
-- 排序后分页
SELECT * FROM orders
WHERE user_id = ?
ORDER BY order_date DESC
LIMIT 100;
-- 排序后翻页
SELECT * FROM orders
WHERE user_id = ?
AND order_date < ?
ORDER BY order_date DESC
LIMIT 100;
7.2 复合主键分页 #
sql
-- 复合主键分页
SELECT * FROM orders
WHERE user_id = ?
AND (order_date, order_id) > (?, ?)
ORDER BY order_date DESC, order_id ASC
LIMIT 100;
八、性能考虑 #
8.1 排序性能 #
text
排序性能考虑:
聚簇列排序
├── 数据已按聚簇列排序存储
├── 无额外排序开销
└── 性能最优
反向排序
├── 需要反向遍历
├── 性能略低
└── 但仍可接受
8.2 分页性能 #
text
分页性能考虑:
浅分页
├── 性能好
└── 前几页响应快
深度分页
├── 需要跳过大量数据
├── 性能下降
└── 考虑Token范围分页
建议
├── 限制最大页数
├── 使用Token分页
└── 避免跳页查询
九、总结 #
排序与分页要点:
- 排序限制:仅支持聚簇列排序
- 方向一致:ORDER BY必须与表定义一致
- 分页方式:LIMIT、主键分页、Token分页
- 驱动分页:使用fetch_size自动分页
- 分页大小:根据数据大小选择合适值
- 避免深度分页:使用Token范围分页
下一步,让我们学习索引!
最后更新:2026-03-27