关于 ycql
ycql 是一项 YugabyteDB YCQL 最佳实践技能,面向数据库开发者,涵盖模式设计、查询优化和运行配置。
主要功能
- 01分区键与聚簇列设计
- 02全局及覆盖索引建议
- 03数据类型与容量限制
- 04TTL 与一致性级别说明
- 05查询、批处理与重试优化
- 06大表扫描及清理建议
适用场景
- 01规划订单等表的分区和排序
- 02为常用查询选择索引与语句
- 03配置数据过期和读取一致性
- 04优化批处理及大型表扫描
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yugabyte/ yugabytedb-skills --skill ycql安装后在 Claude Code 中输入/ycql确认已加载。
详细介绍
YugabyteDB YCQL 最佳实践
YCQL 是 YugabyteDB 与 Cassandra 兼容的 API(端口 9042)。它提供具有强一致性(ACID)的全局二级索引,这是相较于 Apache Cassandra 的一项关键优势。
模式设计
分区键和聚簇列
设计分区键以实现均匀的数据分布,并设计聚簇列以便在分区内高效进行范围扫描:
CREATE TABLE orders (
customer_id UUID,
order_date TIMESTAMP,
order_id UUID,
total DECIMAL,
PRIMARY KEY ((customer_id), order_date DESC, order_id)
) WITH CLUSTERING ORDER BY (order_date DESC, order_id ASC);
- 分区键(
customer_id):决定平板的放置位置。应选择能实现均匀分布的键。 - 聚簇列(
order_date、order_id):决定分区内的排序顺序。
全局二级索引
YugabyteDB 中的 YCQL 二级索引是全局且强一致的(ACID),不同于 Cassandra 的本地索引:
CREATE INDEX idx_orders_date ON orders (order_date);
覆盖索引
使用 INCLUDE 子句直接从索引提供查询结果,无需查找表:
CREATE INDEX idx_orders_customer ON orders (customer_id) INCLUDE (total, order_date);
唯一索引
CREATE UNIQUE INDEX idx_users_email ON users (email);
数据类型
- **JSONB:**支持无模式数据,但仅用于真正动态的值。对于频繁访问的模式,常规列的性能优于 JSONB。
- **计数器递增:**YugabyteDB 支持使用 CAS 操作在一次 Raft 往返中递增或递减整数(Apache Cassandra 中需要 4 次)。
- **集合:**应针对小型数据集进行设计。大型集合会显著影响性能。
大小限制
- **列:**保持在 2 MB 左右或更小
- **行:**保持在 32 MB 左右或更小
TTL(生存时间)
可在表、行或列级别自动使数据过期:
-- Table-level TTL
CREATE TABLE events (
id UUID PRIMARY KEY,
data TEXT
) WITH default_time_to_live = 86400; -- 24 hours
-- Row-level TTL on insert
INSERT INTO events (id, data) VALUES (uuid(), 'event data') USING TTL 3600;
-- Column-level TTL
UPDATE events USING TTL 7200 SET data = 'updated' WHERE id = ?;
**注意:**事务表不支持 TTL。
一致性级别
YugabyteDB YCQL 仅支持两个一致性级别:QUORUM(默认)和 ONE。写入始终具有强一致性(QUORUM)。使用 ONE 进行追随者读取(从最近的副本读取可能过时但延迟较低的数据)。
// Default: QUORUM (strong consistency)
Statement stmt = SimpleStatement.newInstance("SELECT * FROM orders WHERE customer_id = ?", id)
.setConsistencyLevel(ConsistencyLevel.ONE); // Read from nearest replica (may be stale)
轻量级事务(原子化读取-修改-写入)
IF EXISTS / IF NOT EXISTS 操作比 Apache Cassandra 快得多:只需 1 次 Raft 往返,而 LWT 需要 4 次 Raft 往返:
-- Atomic insert-if-not-exists
INSERT INTO users (id, email, name) VALUES (?, ?, ?) IF NOT EXISTS;
-- Atomic conditional update
UPDATE accounts SET balance = ? WHERE id = ? IF balance >= ?;
查询优化
预处理语句(始终使用)
预处理语句支持分区感知路由:驱动程序会计算分区哈希,并将查询直接发送到正确的平板 Leader:
PreparedStatement ps = session.prepare("SELECT * FROM orders WHERE customer_id = ?");
BoundStatement bs = ps.bind(customerId);
session.execute(bs);
批处理
批处理操作会在单次 RPC 调用中发送所有操作:
BatchStatement batch = BatchStatement.newInstance(DefaultBatchType.UNLOGGED);
batch = batch.add(ps1.bind(...));
batch = batch.add(ps2.bind(...));
session.execute(batch);
为获得最佳性能,应使用批处理将目标为同一分区的操作分组。
连接池
使用单个集群对象管理连接。对于 64–128 个线程,每个 YB-TServer 通常 1–2 个连接就足够。使用预处理语句时,驱动程序会自动处理令牌感知路由。
重试策略
默认重试策略会在某些故障时重试一次。对于写入密集型工作负载,可配置带退避机制的自定义重试策略,以应对负载均衡期间平板 Leader 的短暂变更。
大型表操作
使用 partition_hash 将扫描并行分发到各个平板:
SELECT * FROM large_table WHERE partition_hash(id) >= 0 AND partition_hash(id) < 5000;
SELECT * FROM large_table WHERE partition_hash(id) >= 5000 AND partition_hash(id) < 10000;
TRUNCATE 与 DELETE
TRUNCATE 比 DELETE 快得多。DELETE 会插入标记(墓碑),需要进行压缩。清理整张表时应使用 TRUNCATE。
内存配置
对于仅部署 YCQL 的环境,在 yb-master 上设置 --use_memory_defaults_optimized_for_ysql=false,以避免为 PostgreSQL 层预留内存。