3.1 CQL 基础语法


3.1 CQL 基础语法

本节摘要:CQL 表面像 SQL,内核强制分区键完整性——无 JOIN、无无分区键 WHERE(除非 ALLOW FILTERING)。CREATE KEYSPACE 定义复制宪法;2011 年 1.2 起 CQL 取代 Thrift 成为默认接口(SOURCE 3.1)。

本节导读

阅读完本节,你应当能够:

  1. 编写 NTS keyspace 与带复合主键的 CREATE TABLE
  2. 使用 INSERT/UPDATE/DELETEUSING TTL
  3. 说明 CQL 与 PostgreSQL SQL 的三条硬差异
  4. 解释 ALLOW FILTERING 为何是性能告警

一、问题与直觉

开发者看到 SELECT 就以为能 WHERE email = ?——在 Cassandra 里,若 email 不是 partition key 的一部分,Coordinator 必须扫描全环,延迟从毫秒变分钟。MongoDB 可在任意字段建索引(代价是写放大);PostgreSQL B-tree 索引成熟。CQL 的设计是:在语法层拦住分布式灾难,把责任前移到建模。

二、核心原理

Keyspace = 复制 + 一致性策略容器

CREATE KEYSPACE retail WITH replication = { 'class': 'NetworkTopologyStrategy', 'dc1': 3 } AND durable_writes = true;

表 = partition 内有序宽行

CREATE TABLE sensor_readings ( device_id text, reading_time timestamp, temperature double, PRIMARY KEY (device_id, reading_time) ) WITH CLUSTERING ORDER BY (reading_time DESC);

语义:同一 device_id 共置;reading_time 仅分区内排序。合法查询:WHERE device_id = ? AND reading_time > ?。非法:WHERE temperature > 30(无 partition key)。

CQL 特性 说明 Mongo 对照
PRIMARY KEY 含 partition + clustering _id 默认单键
TTL 列/行自动过期 TTL index
LWT IF NOT EXISTS findAndModify
UDT/JSON 5.x 嵌套类型 原生 BSON

常用 DML

INSERT INTO sensor_readings (device_id, reading_time, temperature) VALUES ('dev-9', toTimestamp(now()), 22.5) USING TTL 86400; UPDATE sensor_readings USING TIMESTAMP 1700000000000 SET temperature = 23.0 WHERE device_id = 'dev-9' AND reading_time = '2024-01-01';

三、工程实践要点

类型:用 uuidtimeuuid 作 clustering 可时间排序;避免 text 超大 blob——改对象存储 + Cassandra 存指针。

索引:SAI(4.x)优于 legacy 2i 的写放大;仍不如把查询字段放进 PRIMARY KEY 可靠。

cqlshCONSISTENCY LOCAL_QUORUM 会话级设置;生产用 DataStax Java/Python 驱动 4.x。

⚠️ 常见坑SELECT * 在大 wide row 上拉取百万列——应限 clustering 范围。

💡 关键直觉:CQL 每条合法语句都隐含「只碰少数 partition」——违反即反模式。

一节小结

  • CQL 1.2+ 是默认 API;Thrift 已废弃
  • Keyspace 管复制; 管 co-location
  • 无 JOIN / 无 ad-hoc 扫 是设计不是缺陷
  • TTL / TIMESTAMP 是时序与生命周期原生工具
  • Mongo 灵活查询;CQL 强制路径

下一节深入 PRIMARY KEY 如何映射 Token Ring 与热点治理。

完整 DDL/DML 演练

从零建一个「订单 + 明细」的宽列模型,体会 CQL 的完整拼图:

CREATE KEYSPACE shop WITH replication = { 'class': 'NetworkTopologyStrategy', 'dc-east': 3 }; CREATE TABLE orders_by_user ( user_id text, order_ts timestamp, order_id text, total_amount decimal, status text, PRIMARY KEY (user_id, order_ts, order_id) ) WITH CLUSTERING ORDER BY (order_ts DESC); -- 插入:PRIMARY KEY 的每个字段都必须给全 INSERT INTO orders_by_user (user_id, order_ts, order_id, total_amount, status) VALUES ('u-7788', '2024-08-14 10:00:00', 'ord-1', 199.00, 'paid'); -- 合法的范围查询:分区键等值 + 聚类键范围 SELECT * FROM orders_by_user WHERE user_id = 'u-7788' AND order_ts >= '2024-08-01'; -- 非法的查询:必须带分区键 -- SELECT * FROM orders_by_user WHERE status = 'paid';
-- UPDATE 语义:按主键定位,无则插入(upsert) UPDATE orders_by_user SET status = 'shipped' WHERE user_id = 'u-7788' AND order_ts = '2024-08-14 10:00:00' AND order_id = 'ord-1'; -- DELETE 写 tombstone,物理清理交给 Compaction DELETE FROM orders_by_user WHERE user_id = 'u-7788' AND order_ts = '2024-08-14 10:00:00' AND order_id = 'ord-1';

类型系统要点

类型 用途 注意事项
uuid / timeuuid 无序列号主键 timeuuid 可排序,uuid 不可
counter 原子计数器 不能建在普通表主键上,需单独 counter 表
map / set / list 集合列 集合修改会整列重写,勿高频更新
frozen 嵌套结构快照 冻结后只能整体替换
blob / text 二进制与大文本 超大 blob 应存对象存储
CREATE TABLE user_tags ( user_id text PRIMARY KEY, tags set<text> ); -- 集合操作:整列重写是 CQL 的固有语义 UPDATE user_tags SET tags = tags + {'vip'} WHERE user_id = 'u-1';

cqlsh 实用技巧

# 非交互查询:适合脚本与 CI cqlsh -e "SELECT * FROM shop.orders_by_user LIMIT 10" # 导出结果集到文件 cqlsh -e "COPY shop.orders_by_user TO '/tmp/orders.csv'" # 追踪单条语句的分布式路径 cqlsh -e "TRACING ON; SELECT * FROM shop.orders_by_user LIMIT 1"

COPY 命令支持导入导出,是小数据量迁移与备份的常用工具;大数据量仍建议 sstableloader 或驱动流式写入。TRACING 是诊断「这条查询扫了几个分区」的首选工具——看到 rowssstables 数量就能判断查询是否命中建模预期。

CQL 与 SQL 的三条硬差异

差异 SQL(PostgreSQL) CQL
查询入口 任意列可过滤 必须含完整分区键
数据组织 规范化 + JOIN 反规范化 + 双表
更新语义 UPDATE 覆盖旧行 按列时间戳仲裁(upsert)
-- 最后一条示例:CQL 的 upsert 语义(同主键再写即更新) INSERT INTO orders_by_user (user_id, order_ts, order_id, status) VALUES ('u-7788', '2024-08-14 10:00:00', 'ord-1', 'cancelled'); -- 若其他列(amount)曾写入且时间戳更新,将保留;本语句未写 amount 不会置空

这条特性在生产中常被忽视:CQL 的 UPDATE/INSERT 是「列级时间戳仲裁」,不是行级整体替换。所以补丁式写入不能靠「只传部分列」清空旧值——清空必须显式 DELETE 该列。理解这一点,才算真正告别 SQL 心智进入 CQL 世界。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U