Cassandra教程FG008-Cassandra索引与查询优化实战
本文档风哥主要介绍Cassandra数据库索引与查询优化实战,包括索引概述、索引类型、查询优化概念、索引设计原则、索引创建策略、查询优化策略、SAI索引实战、SASI索引实战、查询优化实战、用户查询优化实战、订单查询优化实战、日志查询优化实战等内容,风哥教程参考Cassandra官方文档Indexing和Performance内容编写,适合DBA人员和开发人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。
Part01-基础概念与理论知识
1.1 Cassandra数据库索引概述
Cassandra数据库索引是提高查询效率的重要手段。与传统关系型数据库不同,Cassandra的索引机制有其独特的特点和限制。更多视频教程www.fgedu.net.cn
1.1.1 Cassandra数据库索引特点
# 1. 索引类型
– 二级索引(Secondary Index)
– SAI索引(Storage-Attached Index)
– SASI索引(SSTable Attached Secondary Index)
– 全文搜索索引
# 2. 索引作用
– 支持非分区键列查询
– 提高查询效率
– 避免全表扫描
# 3. 索引限制
– 高基数列索引效率低
– 索引增加写入开销
– 索引占用存储空间
– 索引维护成本
# 4. 索引适用场景
– 低到中等基数列
– 查询频率高的列
– 等值查询场景
– 范围查询场景(SAI)
# 索引与分区键关系
分区键查询: 直接定位分区,效率最高
索引查询: 先查索引表,再查数据表,效率较低
# 查询优先级
1. 分区键查询(最优)
2. 分区键+聚簇键查询
3. 分区键+索引查询
4. 索引查询
5. ALLOW FILTERING(最差)
1.1.2 Cassandra数据库索引工作原理
# 二级索引工作原理
1. 创建索引时,Cassandra创建隐藏的索引表
2. 索引表存储索引列值到分区键的映射
3. 查询时,先查索引表获取分区键
4. 再根据分区键查询数据表
# 索引表结构
索引列值 → 分区键列表
# 示例
原表: fgedu_users (user_id PRIMARY KEY, email, name)
索引: CREATE INDEX idx_email ON fgedu_users (email);
索引表结构:
email | user_id
—————-+————————————–
user1@fgedu.cn | uuid-1
user2@fgedu.cn | uuid-2
# 查询过程
SELECT * FROM fgedu_users WHERE email = ‘user1@fgedu.cn’;
1. 查索引表: email = ‘user1@fgedu.cn’ → user_id = uuid-1
2. 查数据表: user_id = uuid-1 → 完整数据
# SAI索引工作原理
1. 索引数据存储在SSTable中
2. 支持范围查询和排序
3. 更高效的存储和查询
1.2 Cassandra数据库索引类型
Cassandra数据库索引类型详解:
1.2.1 Cassandra数据库二级索引
# 特点
– Cassandra内置索引
– 创建隐藏索引表
– 支持等值查询
– 适用于低基数列
# 语法
CREATE INDEX [IF NOT EXISTS] index_name
ON table_name (column_name);
# 示例
CREATE INDEX idx_email ON fgedu_users (email);
CREATE INDEX idx_status ON fgedu_orders (status);
# 优点
– 创建简单
– 自动维护
– 支持等值查询
# 缺点
– 高基数列效率低
– 增加写入延迟
– 占用存储空间
– 不支持范围查询
# 适用场景
– 低基数列(如status、type)
– 查询频率高
– 等值查询
# 不适用场景
– 高基数列(如email、user_id)
– 范围查询
– 频繁更新的列
1.2.2 Cassandra数据库SAI索引
# 特点
– Cassandra 4.0引入
– 索引数据存储在SSTable中
– 支持范围查询
– 支持排序
– 更高效的存储
# 语法
CREATE CUSTOM INDEX index_name
ON table_name (column_name)
USING ‘StorageAttachedIndex’;
# 示例
CREATE CUSTOM INDEX idx_email_sai ON fgedu_users (email)
USING ‘StorageAttachedIndex’;
CREATE CUSTOM INDEX idx_created_sai ON fgedu_orders (created_at)
USING ‘StorageAttachedIndex’;
# 优点
– 支持范围查询
– 支持排序
– 存储效率高
– 查询性能好
– 支持多列索引
# 缺点
– 需要Cassandra 4.0+
– 增加写入开销
– 占用存储空间
# 适用场景
– 范围查询
– 排序查询
– 中等基数列
– 需要高性能查询
# SAI索引类型
1. SAI普通索引
– 支持等值和范围查询
2. SAI全文索引
– 支持文本搜索
– 支持模糊匹配
1.2.3 Cassandra数据库SASI索引
# 特点
– Cassandra 3.4引入
– 索引数据存储在SSTable中
– 支持范围查询
– 支持LIKE查询
# 语法
CREATE CUSTOM INDEX index_name
ON table_name (column_name)
USING ‘org.apache.cassandra.index.sasi.SASIIndex’
WITH OPTIONS = {
‘mode’: ‘MODE’,
‘analyzer_class’: ‘CLASS’,
‘case_sensitive’: ‘true|false’
};
# 示例
CREATE CUSTOM INDEX idx_name_sasi ON fgedu_users (user_name)
USING ‘org.apache.cassandra.index.sasi.SASIIndex’
WITH OPTIONS = {
‘mode’: ‘CONTAINS’,
‘analyzer_class’: ‘org.apache.cassandra.index.sasi.analyzer.StandardAnalyzer’,
‘case_sensitive’: ‘false’
};
# SASI模式
1. PREFIX: 前缀匹配
WHERE user_name LIKE ‘张%’
2. CONTAINS: 包含匹配
WHERE user_name LIKE ‘%张%’
3. SPARSE: 稀疏索引
适用于高基数列
# 优点
– 支持LIKE查询
– 支持范围查询
– 查询性能好
# 缺点
– 配置复杂
– 增加写入开销
– 维护成本高
# 适用场景
– 文本搜索
– LIKE查询
– 范围查询
1.3 Cassandra数据库查询优化概念
Cassandra数据库查询优化概念详解:
1.3.1 Cassandra数据库查询执行过程
# 1. 查询解析
– 解析CQL语句
– 验证语法正确性
– 生成查询计划
# 2. 查询优化
– 确定分区键
– 选择索引
– 优化查询路径
# 3. 查询执行
– 定位分区
– 读取数据
– 过滤结果
# 4. 结果返回
– 组装结果集
– 返回客户端
# 查询类型
1. 分区键查询
– 直接定位分区
– 效率最高
2. 索引查询
– 先查索引表
– 再查数据表
– 效率中等
3. 全表扫描
– 扫描所有分区
– 效率最低
– 需要ALLOW FILTERING
# 查询优化目标
1. 减少扫描分区数
2. 减少扫描行数
3. 减少网络传输
4. 提高查询响应速度
1.3.2 Cassandra数据库查询性能影响因素
# 1. 分区键设计
– 分区键选择影响数据分布
– 热点分区导致性能下降
– 分区大小影响查询效率
# 2. 索引设计
– 索引类型影响查询效率
– 索引列基数影响性能
– 索引维护影响写入性能
# 3. 数据量
– 数据量影响扫描时间
– 大分区影响查询效率
– 墓碑影响读取性能
# 4. 集群状态
– 节点数量影响并行度
– 网络延迟影响响应时间
– 节点负载影响性能
# 5. 一致性级别
– 一致性级别影响延迟
– 高一致性级别增加延迟
– 低一致性级别提高性能
# 6. 缓存配置
– 缓存命中率影响性能
– 缓存大小影响效果
– 缓存策略影响效率
# 性能优化方向
1. 优化分区键设计
2. 合理使用索引
3. 控制分区大小
4. 优化一致性级别
5. 配置合理缓存
6. 监控集群状态
Part02-生产环境规划与建议
2.1 Cassandra数据库索引设计原则
Cassandra数据库索引设计原则详解:
2.1.1 Cassandra数据库索引选择原则
# 1. 优先考虑表结构设计
– 索引是补充手段
– 优先优化表结构
– 查询驱动设计
# 2. 评估列基数
– 低基数列: 二级索引
– 中等基数列: SAI索引
– 高基数列: 重新设计表结构
# 3. 评估查询模式
– 等值查询: 二级索引、SAI索引
– 范围查询: SAI索引
– 文本搜索: SASI索引、SAI全文索引
# 4. 评估更新频率
– 频繁更新: 谨慎使用索引
– 较少更新: 可使用索引
– 只读数据: 大量使用索引
# 5. 评估数据量
– 小数据量: 索引效果好
– 大数据量: 需要分区优化
# 索引决策流程
1. 分析查询需求
2. 评估是否需要索引
3. 选择索引类型
4. 创建索引
5. 测试性能
6. 调整优化
# 不建议使用索引的场景
1. 高基数列
2. 频繁更新的列
3. 写入密集型场景
4. 可以通过表结构优化解决
2.1.2 Cassandra数据库索引设计最佳实践
# 1. 索引数量控制
– 单表索引不超过3个
– 索引过多影响写入性能
– 选择最常用的查询列
# 2. 索引列选择
– 选择查询频率高的列
– 选择基数适中的列
– 选择更新频率低的列
# 3. 索引类型选择
– Cassandra 4.0+: 优先使用SAI
– Cassandra 3.x: 使用二级索引或SASI
– 文本搜索: 使用SASI或SAI全文索引
# 4. 索引命名规范
– 前缀idx_表示索引
– 包含表名和列名
– 示例: idx_users_email
# 5. 索引监控
– 监控索引大小
– 监控索引查询性能
– 监控索引维护开销
# 6. 索引维护
– 定期重建索引
– 清理无效索引
– 优化索引配置
# 索引设计检查清单
[ ] 查询需求已分析
[ ] 列基数已评估
[ ] 索引类型已选择
[ ] 索引命名规范
[ ] 性能测试已完成
[ ] 监控方案已制定
2.2 Cassandra数据库索引创建策略
Cassandra数据库索引创建策略详解:
2.2.1 Cassandra数据库索引创建时机
# 1. 表创建后创建索引
– 先创建表
– 导入数据
– 创建索引
# 2. 数据量小时创建
– 数据量小时创建索引快
– 大数据量创建索引慢
# 3. 业务低峰期创建
– 索引创建消耗资源
– 避免高峰期创建
# 4. 索引创建步骤
步骤1: 分析查询需求
步骤2: 选择索引列
步骤3: 选择索引类型
步骤4: 创建索引
步骤5: 验证索引效果
步骤6: 监控索引性能
# 索引创建注意事项
1. 大表创建索引可能很慢
2. 创建索引期间性能下降
3. 建议在测试环境先验证
4. 监控创建进度
2.2.2 Cassandra数据库索引创建语法
# 1. 二级索引
CREATE INDEX [IF NOT EXISTS] index_name
ON table_name (column_name);
# 示例
CREATE INDEX idx_email ON fgedu_users (email);
CREATE INDEX IF NOT EXISTS idx_status ON fgedu_orders (status);
# 2. SAI索引
CREATE CUSTOM INDEX index_name
ON table_name (column_name)
USING ‘StorageAttachedIndex’;
# 示例
CREATE CUSTOM INDEX idx_email_sai ON fgedu_users (email)
USING ‘StorageAttachedIndex’;
# 3. SASI索引
CREATE CUSTOM INDEX index_name
ON table_name (column_name)
USING ‘org.apache.cassandra.index.sasi.SASIIndex’
WITH OPTIONS = {
‘mode’: ‘MODE’,
‘analyzer_class’: ‘CLASS’
};
# 示例
CREATE CUSTOM INDEX idx_name_sasi ON fgedu_users (user_name)
USING ‘org.apache.cassandra.index.sasi.SASIIndex’
WITH OPTIONS = {‘mode’: ‘CONTAINS’};
# 4. 集合索引
CREATE INDEX idx_tags ON fgedu_users (tags); — SET
CREATE INDEX idx_attrs ON fgedu_users (KEYS(attributes)); — MAP keys
CREATE INDEX idx_attr_values ON fgedu_users (VALUES(attributes)); — MAP values
CREATE INDEX idx_attr_entries ON fgedu_users (ENTRIES(attributes)); — MAP entries
# 5. 删除索引
DROP INDEX [IF EXISTS] index_name;
# 示例
DROP INDEX IF EXISTS idx_email;
2.3 Cassandra数据库查询优化策略
Cassandra数据库查询优化策略详解:
2.3.1 Cassandra数据库查询优化方法
# 1. 分区键优化
– 查询必须包含分区键
– 避免全表扫描
– 合理设计分区键
# 2. 聚簇键优化
– 利用聚簇键排序
– 支持范围查询
– 减少扫描行数
# 3. 索引优化
– 合理使用索引
– 选择合适的索引类型
– 监控索引性能
# 4. 分页优化
– 使用LIMIT分页
– 使用分页状态
– 避免大结果集
# 5. 一致性级别优化
– 选择合适的一致性级别
– 平衡一致性和性能
– 使用本地一致性
# 6. 并行查询优化
– 使用异步查询
– 并行查询多个分区
– 提高吞吐量
# 查询优化检查清单
[ ] 查询包含分区键
[ ] 使用聚簇键排序
[ ] 索引使用合理
[ ] 分页查询实现
[ ] 一致性级别合适
[ ] 并行查询优化
2.3.2 Cassandra数据库查询优化技巧
# 1. 避免SELECT *
# 不好的做法
SELECT * FROM fgedu_users WHERE user_id = ?;
# 好的做法
SELECT user_id, user_name, email FROM fgedu_users WHERE user_id = ?;
# 2. 使用LIMIT
SELECT * FROM fgedu_orders WHERE user_id = ? LIMIT 100;
# 3. 使用分页状态
# 应用代码实现
Statement statement = QueryBuilder.select()
.from(“fgedu_users”)
.where(eq(“user_id”, userId))
.setFetchSize(100);
ResultSet results = session.execute(statement);
PagingState pagingState = results.getExecutionInfo().getPagingState();
# 4. 使用IN查询(谨慎使用)
SELECT * FROM fgedu_users WHERE user_id IN (?, ?, ?);
# 5. 使用TOKEN查询(特殊情况)
SELECT * FROM fgedu_users WHERE TOKEN(user_id) > ? LIMIT 100;
# 6. 避免ALLOW FILTERING
# 不好的做法
SELECT * FROM fgedu_users WHERE age > 25 ALLOW FILTERING;
# 好的做法:创建索引或重新设计表结构
# 7. 使用并行查询
# 同时查询多个分区
List
for (UUID userId : userIds) {
futures.add(session.executeAsync(
“SELECT * FROM fgedu_users WHERE user_id = ?”, userId
));
}
Part03-生产环境项目实施方案
3.1 Cassandra数据库SAI索引实战
Cassandra数据库SAI索引实战:
3.1.1 Cassandra数据库创建SAI索引
# cqlsh 192.168.1.101 9042 -u fgedu -p Fgedu@2024
Connected to fgedu_cluster at 192.168.1.101:9042
# 切换到Keyspace
cqlsh> USE fgedudb;
cqlsh:fgedudb>
# 创建SAI索引
# 在email列创建SAI索引
cqlsh:fgedudb> CREATE CUSTOM INDEX idx_users_email_sai
… ON fgedu_users (email)
… USING ‘StorageAttachedIndex’;
# 在created_at列创建SAI索引(支持范围查询)
cqlsh:fgedudb> CREATE CUSTOM INDEX idx_orders_created_sai
… ON fgedu_orders (created_at)
… USING ‘StorageAttachedIndex’;
# 在status列创建SAI索引
cqlsh:fgedudb> CREATE CUSTOM INDEX idx_orders_status_sai
… ON fgedu_orders (status)
… USING ‘StorageAttachedIndex’;
# 查看索引
cqlsh:fgedudb> DESCRIBE TABLE fgedu_users;
CREATE TABLE fgedudb.fgedu_users (
user_id uuid PRIMARY KEY,
email text,
user_name text,
…
) WITH …
CREATE CUSTOM INDEX idx_users_email_sai ON fgedudb.fgedu_users (email)
USING ‘StorageAttachedIndex’;
# 验证索引
cqlsh:fgedudb> SELECT * FROM system_schema.indexes
… WHERE keyspace_name = ‘fgedudb’;
keyspace_name | table_name | index_name | kind | options
—————+————–+————————-+——–+———
fgedudb | fgedu_users | idx_users_email_sai | CUSTOM | {‘class_name’: ‘org.apache.cassandra.index.sai.StorageAttachedIndex’}
fgedudb | fgedu_orders | idx_orders_created_sai | CUSTOM | {‘class_name’: ‘org.apache.cassandra.index.sai.StorageAttachedIndex’}
fgedudb | fgedu_orders | idx_orders_status_sai | CUSTOM | {‘class_name’: ‘org.apache.cassandra.index.sai.StorageAttachedIndex’}
(3 rows)
3.1.2 Cassandra数据库使用SAI索引查询
# 等值查询
cqlsh:fgedudb> SELECT * FROM fgedu_users
… WHERE email = ‘zhangsan@fgedu.net.cn’;
user_id | email | user_name | created_at
————————————–+———————-+———–+———————————-
8e5f6a7b-8c9d-0e1f-2a3b-4c5d6e7f8a9b | zhangsan@fgedu.net.cn | zhangsan | 2024-01-15 10:30:00.123000+0000
(1 row)
# 范围查询
cqlsh:fgedudb> SELECT * FROM fgedu_orders
… WHERE created_at >= ‘2024-01-01’
… AND created_at < '2024-02-01'
... LIMIT 100;
order_id | created_at | status | user_id
--------------------------------------+----------------------------------+---------+--------------------------------------
8e5f6a7b-8c9d-0e1f-2a3b-4c5d6e7f8a9b | 2024-01-15 10:30:00.123000+0000 | CREATED | 9f7g8h9i-0j1k-2l3m-4n5o-6p7q8r9s0t1u
(1 row)
# 多条件查询
cqlsh:fgedudb> SELECT * FROM fgedu_orders
… WHERE status = ‘PAID’
… AND created_at >= ‘2024-01-01’
… LIMIT 100;
# 组合查询(分区键+索引)
cqlsh:fgedudb> SELECT * FROM fgedu_orders
… WHERE user_id = 9f7g8h9i-0j1k-2l3m-4n5o-6p7q8r9s0t1u
… AND status = ‘PAID’;
# 使用EXPLAIN分析查询
cqlsh:fgedudb> EXPLAIN SELECT * FROM fgedu_users WHERE email = ‘test@fgedu.net.cn’;
# 删除SAI索引
cqlsh:fgedudb> DROP INDEX IF EXISTS idx_users_email_sai;
3.2 Cassandra数据库SASI索引实战
Cassandra数据库SASI索引实战:
3.2.1 Cassandra数据库创建SASI索引
# 创建PREFIX模式索引(前缀匹配)
cqlsh:fgedudb> CREATE CUSTOM INDEX idx_users_name_prefix
… ON fgedu_users (user_name)
… USING ‘org.apache.cassandra.index.sasi.SASIIndex’
… WITH OPTIONS = {
… ‘mode’: ‘PREFIX’,
… ‘case_sensitive’: ‘false’
… };
# 创建CONTAINS模式索引(包含匹配)
cqlsh:fgedudb> CREATE CUSTOM INDEX idx_users_name_contains
… ON fgedu_users (user_name)
… USING ‘org.apache.cassandra.index.sasi.SASIIndex’
… WITH OPTIONS = {
… ‘mode’: ‘CONTAINS’,
… ‘analyzer_class’: ‘org.apache.cassandra.index.sasi.analyzer.StandardAnalyzer’,
… ‘case_sensitive’: ‘false’
… };
# 创建SPARSE模式索引(稀疏索引,适用于高基数列)
cqlsh:fgedudb> CREATE CUSTOM INDEX idx_users_id_sparse
… ON fgedu_users (user_id)
… USING ‘org.apache.cassandra.index.sasi.SASIIndex’
… WITH OPTIONS = {
… ‘mode’: ‘SPARSE’
… };
# 查看索引
cqlsh:fgedudb> DESCRIBE TABLE fgedu_users;
3.2.2 Cassandra数据库使用SASI索引查询
# 前缀匹配查询
cqlsh:fgedudb> SELECT * FROM fgedu_users
… WHERE user_name LIKE ‘张%’;
user_id | user_name | email
————————————–+———–+——————–
8e5f6a7b-8c9d-0e1f-2a3b-4c5d6e7f8a9b | 张三 | zhangsan@fgedu.cn
9f7g8h9i-0j1k-2l3m-4n5o-6p7q8r9s0t1u | 张四 | zhangsi@fgedu.cn
(2 rows)
# 包含匹配查询
cqlsh:fgedudb> SELECT * FROM fgedu_users
… WHERE user_name LIKE ‘%三%’;
user_id | user_name | email
————————————–+———–+——————–
8e5f6a7b-8c9d-0e1f-2a3b-4c5d6e7f8a9b | 张三 | zhangsan@fgedu.cn
(1 row)
# 范围查询
cqlsh:fgedudb> SELECT * FROM fgedu_users
… WHERE user_name >= ‘张’
… AND user_name < '赵';
# 组合查询
cqlsh:fgedudb> SELECT * FROM fgedu_users
… WHERE user_name LIKE ‘%三%’
… AND email LIKE ‘%@fgedu.cn’;
# 删除SASI索引
cqlsh:fgedudb> DROP INDEX IF EXISTS idx_users_name_contains;
3.3 Cassandra数据库查询优化实战
Cassandra数据库查询优化实战:
3.3.1 Cassandra数据库查询性能分析
# 1. 使用TRACING分析查询
cqlsh:fgedudb> TRACING ON;
cqlsh:fgedudb> SELECT * FROM fgedu_users WHERE user_id = ?;
Tracing session: 8e5f6a7b-8c9d-0e1f-2a3b-4c5d6e7f8a9b
activity | timestamp | source | source_elapsed
—————————————————–+—————————-+————–+—————-
Execute CQL3 | 2024-01-15 10:30:00.123000 | 192.168.1.101 | 0
Parsing SELECT * FROM … | 2024-01-15 10:30:00.123100 | 192.168.1.101 | 100
preparing statement | 2024-01-15 10:30:00.123200 | 192.168.1.101 | 200
determining replicas for query | 2024-01-15 10:30:00.123300 | 192.168.1.101 | 300
sending request to … | 2024-01-15 10:30:00.123400 | 192.168.1.101 | 400
reading data | 2024-01-15 10:30:00.123500 | 192.168.1.101 | 500
sending response | 2024-01-15 10:30:00.123600 | 192.168.1.101 | 600
processing result | 2024-01-15 10:30:00.123700 | 192.168.1.101 | 700
(8 rows)
# 关闭TRACING
cqlsh:fgedudb> TRACING OFF;
# 2. 使用nodetool分析
# 查看表统计信息
# nodetool tablestats fgedudb.fgedu_users
Total number of tables: 1
————————-
Keyspace : fgedudb
Table: fgedu_users
SSTable count: 5
Space used (live): 1073741824
Space used (total): 1073741824
Number of keys (estimate): 1000000
Memtable cell count: 10000
Memtable data size: 10485760
Memtable switch count: 10
Read count: 100000
Read latency: 0.123 ms
Write count: 500000
Write latency: 0.045 ms
Pending flushes: 0
# 3. 使用系统表分析
cqlsh:fgedudb> SELECT * FROM system_schema.columns
… WHERE keyspace_name = ‘fgedudb’
… AND table_name = ‘fgedu_users’;
3.3.2 Cassandra数据库查询优化实施
# 1. 优化分区键查询
# 原查询
SELECT * FROM fgedu_orders WHERE user_id = ?;
# 优化后(添加聚簇键范围)
SELECT * FROM fgedu_orders
WHERE user_id = ?
AND order_time >= ?
AND order_time < ?;
# 2. 优化索引查询
# 原查询(全表扫描)
SELECT * FROM fgedu_users WHERE email = ?;
# 优化后(使用索引)
CREATE CUSTOM INDEX idx_email_sai ON fgedu_users (email)
USING 'StorageAttachedIndex';
SELECT * FROM fgedu_users WHERE email = ?;
# 3. 优化分页查询
# 原查询
SELECT * FROM fgedu_logs LIMIT 10000;
# 优化后(使用分页状态)
# 应用代码实现
Statement statement = QueryBuilder.select()
.from("fgedu_logs")
.setFetchSize(100);
ResultSet results = session.execute(statement);
while (!results.isFullyFetched()) {
results.fetchMoreResults();
for (Row row : results) {
// 处理数据
}
}
# 4. 优化并行查询
# 原查询(串行)
for (UUID userId : userIds) {
ResultSet results = session.execute(
"SELECT * FROM fgedu_users WHERE user_id = ?", userId
);
}
# 优化后(并行)
List
for (UUID userId : userIds) {
futures.add(session.executeAsync(
“SELECT * FROM fgedu_users WHERE user_id = ?”, userId
));
}
for (ResultSetFuture future : futures) {
ResultSet results = future.get();
// 处理结果
}
# 5. 优化一致性级别
# 原查询
CONSISTENCY QUORUM;
SELECT * FROM fgedu_users WHERE user_id = ?;
# 优化后(降低一致性级别)
CONSISTENCY LOCAL_ONE;
SELECT * FROM fgedu_users WHERE user_id = ?;
Part04-生产案例与实战讲解
4.1 Cassandra数据库用户查询优化实战
Cassandra数据库用户查询优化实战案例:
4.1.1 Cassandra数据库用户查询场景分析
# 场景1: 根据用户ID查询
# 最优方案:分区键查询
cqlsh:fgedudb> SELECT * FROM fgedu_users WHERE user_id = ?;
# 性能:毫秒级
# 说明:直接定位分区,效率最高
# 场景2: 根据邮箱查询
# 方案1:创建索引
cqlsh:fgedudb> CREATE CUSTOM INDEX idx_email_sai ON fgedu_users (email)
… USING ‘StorageAttachedIndex’;
cqlsh:fgedudb> SELECT * FROM fgedu_users WHERE email = ?;
# 方案2:创建邮箱索引表
cqlsh:fgedudb> CREATE TABLE fgedu_users_by_email (
… email text PRIMARY KEY,
… user_id uuid
… );
# 两步查询
cqlsh:fgedudb> SELECT user_id FROM fgedu_users_by_email WHERE email = ?;
cqlsh:fgedudb> SELECT * FROM fgedu_users WHERE user_id = ?;
# 场景3: 根据用户名模糊查询
# 方案:创建SASI索引
cqlsh:fgedudb> CREATE CUSTOM INDEX idx_name_sasi ON fgedu_users (user_name)
… USING ‘org.apache.cassandra.index.sasi.SASIIndex’
… WITH OPTIONS = {‘mode’: ‘CONTAINS’};
cqlsh:fgedudb> SELECT * FROM fgedu_users WHERE user_name LIKE ‘%张%’;
# 场景4: 根据状态查询
# 方案:创建二级索引(低基数列)
cqlsh:fgedudb> CREATE INDEX idx_status ON fgedu_users (status);
cqlsh:fgedudb> SELECT * FROM fgedu_users WHERE status = ‘ACTIVE’;
4.1.2 Cassandra数据库用户查询优化实施
# 1. 创建必要的索引
cqlsh:fgedudb> CREATE CUSTOM INDEX idx_users_email_sai ON fgedu_users (email)
… USING ‘StorageAttachedIndex’;
cqlsh:fgedudb> CREATE CUSTOM INDEX idx_users_phone_sai ON fgedu_users (phone)
… USING ‘StorageAttachedIndex’;
cqlsh:fgedudb> CREATE INDEX idx_users_status ON fgedu_users (status);
# 2. 创建查询表
# 按创建时间查询用户
cqlsh:fgedudb> CREATE TABLE fgedu_users_by_created (
… created_date date,
… created_time timestamp,
… user_id uuid,
… user_name text,
… email text,
… PRIMARY KEY (created_date, created_time)
… ) WITH CLUSTERING ORDER BY (created_time DESC);
# 按地区查询用户
cqlsh:fgedudb> CREATE TABLE fgedu_users_by_region (
… region text,
… user_id uuid,
… user_name text,
… email text,
… PRIMARY KEY (region, user_id)
… );
# 3. 查询性能测试
# 开启TRACING
cqlsh:fgedudb> TRACING ON;
# 测试分区键查询
cqlsh:fgedudb> SELECT * FROM fgedu_users WHERE user_id = ?;
# 预期:1-5ms
# 测试索引查询
cqlsh:fgedudb> SELECT * FROM fgedu_users WHERE email = ?;
# 预期:5-20ms
# 测试模糊查询
cqlsh:fgedudb> SELECT * FROM fgedu_users WHERE user_name LIKE ‘%张%’;
# 预期:20-100ms
# 关闭TRACING
cqlsh:fgedudb> TRACING OFF;
# 4. 监控查询性能
# 查看慢查询日志
# grep “slow query” /cassandra/logs/system.log
# 分析查询统计
# nodetool tablestats fgedudb.fgedu_users
4.2 Cassandra数据库订单查询优化实战
Cassandra数据库订单查询优化实战案例:
4.2.1 Cassandra数据库订单查询场景分析
# 场景1: 根据订单ID查询
# 最优方案:分区键查询
cqlsh:fgedudb> SELECT * FROM fgedu_orders WHERE order_id = ?;
# 场景2: 根据用户ID查询订单列表
# 方案:分区键+聚簇键查询
cqlsh:fgedudb> SELECT * FROM fgedu_orders
… WHERE user_id = ?
… ORDER BY order_time DESC
… LIMIT 20;
# 场景3: 根据订单状态查询
# 方案:创建索引表
cqlsh:fgedudb> CREATE TABLE fgedu_orders_by_status (
… status text,
… order_time timestamp,
… order_id uuid,
… user_id uuid,
… amount decimal,
… PRIMARY KEY (status, order_time)
… ) WITH CLUSTERING ORDER BY (order_time DESC);
cqlsh:fgedudb> SELECT * FROM fgedu_orders_by_status
… WHERE status = ‘PAID’
… LIMIT 100;
# 场景4: 根据时间范围查询
# 方案:创建时间分区表
cqlsh:fgedudb> CREATE TABLE fgedu_orders_by_date (
… order_date date,
… order_time timestamp,
… order_id uuid,
… user_id uuid,
… amount decimal,
… status text,
… PRIMARY KEY (order_date, order_time)
… ) WITH CLUSTERING ORDER BY (order_time DESC);
cqlsh:fgedudb> SELECT * FROM fgedu_orders_by_date
… WHERE order_date = ‘2024-01-15’
… LIMIT 100;
4.2.2 Cassandra数据库订单查询优化实施
# 1. 创建索引表
# 按状态查询
cqlsh:fgedudb> CREATE TABLE fgedu_orders_by_status (
… status text,
… created_at timestamp,
… order_id uuid,
… user_id uuid,
… amount decimal,
… PRIMARY KEY (status, created_at)
… ) WITH CLUSTERING ORDER BY (created_at DESC);
# 按日期查询
cqlsh:fgedudb> CREATE TABLE fgedu_orders_by_date (
… order_date date,
… order_time timestamp,
… order_id uuid,
… user_id uuid,
… amount decimal,
… status text,
… PRIMARY KEY (order_date, order_time)
… ) WITH CLUSTERING ORDER BY (order_time DESC);
# 2. 数据同步写入
cqlsh:fgedudb> BEGIN BATCH
… INSERT INTO fgedu_orders (order_id, user_id, order_time, amount, status)
… VALUES (?, ?, ?, ?, ‘CREATED’);
… INSERT INTO fgedu_orders_by_status (status, created_at, order_id, user_id, amount)
… VALUES (‘CREATED’, ?, ?, ?, ?);
… INSERT INTO fgedu_orders_by_date (order_date, order_time, order_id, user_id, amount, status)
… VALUES (?, ?, ?, ?, ?, ‘CREATED’);
… APPLY BATCH;
# 3. 查询性能测试
# 开启TRACING
cqlsh:fgedudb> TRACING ON;
# 测试用户订单查询
cqlsh:fgedudb> SELECT * FROM fgedu_orders
… WHERE user_id = ?
… ORDER BY order_time DESC
… LIMIT 20;
# 测试状态查询
cqlsh:fgedudb> SELECT * FROM fgedu_orders_by_status
… WHERE status = ‘PAID’
… LIMIT 100;
# 测试日期查询
cqlsh:fgedudb> SELECT * FROM fgedu_orders_by_date
… WHERE order_date = ‘2024-01-15’
… LIMIT 100;
# 关闭TRACING
cqlsh:fgedudb> TRACING OFF;
# 4. 查询优化脚本
#!/bin/bash
# order_query_optimize.sh
# from:www.itpux.com.qq113257174.wx:itpux-com
# web: http://www.fgedu.net.cn
# 统计订单查询性能
echo “订单查询性能统计:”
echo “==================”
# 统计分区键查询
echo “分区键查询:”
cqlsh -e “SELECT COUNT(*) FROM fgedudb.fgedu_orders WHERE user_id = ?” 2>&1 | grep “Query”
# 统计索引查询
echo “索引查询:”
cqlsh -e “SELECT COUNT(*) FROM fgedudb.fgedu_orders_by_status WHERE status = ‘PAID'” 2>&1 | grep “Query”
echo “统计完成”
4.3 Cassandra数据库日志查询优化实战
Cassandra数据库日志查询优化实战案例:
4.3.1 Cassandra数据库日志查询场景分析
# 场景1: 查询最近日志
# 方案:分区键+聚簇键查询
cqlsh:fgedudb> SELECT * FROM fgedu_logs
… WHERE log_date = ‘2024-01-15’
… ORDER BY log_time DESC
… LIMIT 100;
# 场景2: 查询特定级别日志
# 方案:创建索引表
cqlsh:fgedudb> CREATE TABLE fgedu_logs_by_level (
… log_level text,
… log_date date,
… log_time timestamp,
… log_id uuid,
… message text,
… PRIMARY KEY ((log_level, log_date), log_time)
… ) WITH CLUSTERING ORDER BY (log_time DESC);
cqlsh:fgedudb> SELECT * FROM fgedu_logs_by_level
… WHERE log_level = ‘ERROR’
… AND log_date = ‘2024-01-15’
… LIMIT 100;
# 场景3: 查询特定服务日志
# 方案:创建服务分区表
cqlsh:fgedudb> CREATE TABLE fgedu_logs_by_service (
… service_name text,
… log_date date,
… log_time timestamp,
… log_id uuid,
… log_level text,
… message text,
… PRIMARY KEY ((service_name, log_date), log_time)
… ) WITH CLUSTERING ORDER BY (log_time DESC);
cqlsh:fgedudb> SELECT * FROM fgedu_logs_by_service
… WHERE service_name = ‘user-service’
… AND log_date = ‘2024-01-15’
… LIMIT 100;
# 场景4: 查询包含关键字的日志
# 方案:创建SASI索引
cqlsh:fgedudb> CREATE CUSTOM INDEX idx_message_sasi ON fgedu_logs (message)
… USING ‘org.apache.cassandra.index.sasi.SASIIndex’
… WITH OPTIONS = {‘mode’: ‘CONTAINS’};
cqlsh:fgedudb> SELECT * FROM fgedu_logs
… WHERE message LIKE ‘%error%’
… LIMIT 100;
4.3.2 Cassandra数据库日志查询优化实施
# 1. 创建日志表结构
# 主日志表
cqlsh:fgedudb> CREATE TABLE fgedu_logs (
… log_date date,
… log_time timestamp,
… log_id uuid,
… log_level text,
… service_name text,
… logger text,
… message text,
… stack_trace text,
… PRIMARY KEY (log_date, log_time)
… ) WITH CLUSTERING ORDER BY (log_time DESC)
… AND default_time_to_live = 604800; — 7天自动过期
# 按级别分表
cqlsh:fgedudb> CREATE TABLE fgedu_logs_by_level (
… log_level text,
… log_date date,
… log_time timestamp,
… log_id uuid,
… service_name text,
… message text,
… PRIMARY KEY ((log_level, log_date), log_time)
… ) WITH CLUSTERING ORDER BY (log_time DESC)
… AND default_time_to_live = 2592000; — 30天自动过期
# 2. 创建索引
cqlsh:fgedudb> CREATE CUSTOM INDEX idx_service_sai ON fgedu_logs (service_name)
… USING ‘StorageAttachedIndex’;
cqlsh:fgedudb> CREATE CUSTOM INDEX idx_message_sasi ON fgedu_logs (message)
… USING ‘org.apache.cassandra.index.sasi.SASIIndex’
… WITH OPTIONS = {‘mode’: ‘CONTAINS’};
# 3. 查询性能测试
# 开启TRACING
cqlsh:fgedudb> TRACING ON;
# 测试日期查询
cqlsh:fgedudb> SELECT * FROM fgedu_logs
… WHERE log_date = ‘2024-01-15’
… LIMIT 100;
# 测试级别查询
cqlsh:fgedudb> SELECT * FROM fgedu_logs_by_level
… WHERE log_level = ‘ERROR’
… AND log_date = ‘2024-01-15’;
# 测试关键字查询
cqlsh:fgedudb> SELECT * FROM fgedu_logs
… WHERE message LIKE ‘%exception%’
… LIMIT 100;
# 关闭TRACING
cqlsh:fgedudb> TRACING OFF;
# 4. 日志清理
# 自动清理(通过TTL)
# 手动清理
cqlsh:fgedudb> DELETE FROM fgedu_logs WHERE log_date < '2024-01-01';
Part05-风哥经验总结与分享
5.1 Cassandra数据库索引最佳实践
Cassandra数据库索引最佳实践总结:
- 优先优化表结构:索引是补充手段,优先通过表结构设计解决查询需求
- 选择合适的索引类型:根据查询场景选择SAI、SASI或二级索引
- 控制索引数量:单表索引不超过3个,避免过多索引影响写入性能
- 监控索引性能:定期监控索引大小、查询性能和维护开销
- 及时清理无效索引:删除不再使用的索引,减少维护成本
- 测试验证:在生产环境部署前充分测试索引效果
5.2 Cassandra数据库查询最佳实践
# 1. 分区键优先
– 查询必须包含分区键
– 避免全表扫描
– 合理设计分区键
# 2. 使用聚簇键
– 利用聚簇键排序
– 支持范围查询
– 减少扫描行数
# 3. 合理使用索引
– 选择合适的索引类型
– 监控索引性能
– 及时维护索引
# 4. 分页查询
– 使用LIMIT分页
– 使用分页状态
– 避免大结果集
# 5. 并行查询
– 使用异步查询
– 并行查询多个分区
– 提高吞吐量
# 6. 一致性级别
– 选择合适的一致性级别
– 平衡一致性和性能
– 使用本地一致性
# 7. 避免ALLOW FILTERING
– 重新设计表结构
– 创建必要的索引
– 使用查询表
# 8. 监控查询性能
– 使用TRACING分析
– 监控慢查询
– 定期优化
5.3 Cassandra数据库性能监控工具
Cassandra数据库性能监控工具推荐:
5.3.1 Cassandra数据库监控工具
# 1. nodetool
# 查看集群状态
# nodetool status
# 查看表统计
# nodetool tablestats fgedudb.fgedu_users
# 查看表直方图
# nodetool tablehistograms fgedudb.fgedu_users
# 查看压缩统计
# nodetool compactionstats
# 查看GC统计
# nodetool gcstats
# 2. cqlsh TRACING
# 开启查询追踪
cqlsh> TRACING ON;
cqlsh> SELECT * FROM fgedu_users WHERE user_id = ?;
cqlsh> TRACING OFF;
# 3. 系统日志
# 查看慢查询日志
# grep “slow query” /cassandra/logs/system.log
# 查看错误日志
# grep “ERROR” /cassandra/logs/system.log
# 4. JMX监控
# 使用JConsole或VisualVM连接
# 监控JVM指标
# 5. DataStax OpsCenter
# DataStax官方监控工具
# 图形化界面
# 支持告警和报告
# 6. Prometheus + Grafana
# 开源监控方案
# 支持自定义指标
# 图形化展示
# 7. 第三方工具
– Instaclustr
– DataStax Astra
– ScyllaDB Monitoring
本文档详细介绍了Cassandra数据库索引与查询优化实战,包括索引概述、索引类型、查询优化概念、索引设计原则、索引创建策略、查询优化策略、SAI索引实战、SASI索引实战、查询优化实战、用户查询优化实战、订单查询优化实战、日志查询优化实战、索引最佳实践、查询最佳实践、性能监控工具等内容。通过学习本文档,读者可以掌握Cassandra数据库索引和查询优化技能,为应用开发打下坚实基础。
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
