Cassandra 查询语言 (CQL):插入、更新和删除

⚡ 智能摘要

Cassandra 查询语言 (Query Language) 处理插入、更新、删除和读取操作,其语法与 SQL 类似,但底层语义不同。本页将介绍每种语句、合并了插入和更新的 upsert 行为,以及 WHERE 子句的真正局限性。

  • 插入行为: 只有主键是必填项,省略的列不占用存储空间。
  • 🔄 Upsert 语义: 插入和更新是相同的操作,因此写入已存在的键会静默地覆盖它。
  • 🗑️ 删除费用: 被移除的行会变成墓碑,只有在压缩运行后才会消失。
  • 🔍 Where条款的限制: 筛选功能可以作用于主键列,也可以作用于已建立索引的其他列。
  • 📊 综合支持率: 计数、最小值、最大值、总和 AVG 支持 GROUP BY,但只能在一个分区内高效使用。
  • 🚫 仍不支持: 根据设计,连接、OR 条件和跨分区分析仍然在 CQL 之外。

Cassandra CQL 插入 更新 删除

插入资料

此 Cassandra 插入语句将数据写入 Cassandra 行形式的列。 Cassandra 插入查询将仅存储用户指定的列。您必须仅指定主键列。

未指定值时不会占用任何空间。插入后不返回任何结果。

句法

INSERT INTO KeyspaceName.TableName (ColumnName1, ColumnName2, ColumnName3)
VALUES (Column1Value, Column2Value, Column3Value);

例如:

这是执行的快照 Cassandra 插入表查询将在表中插入一条记录 Cassandra 表‘学生’。

插入资料

INSERT INTO University.Student (RollNo, Name, dept, Semester)
VALUES (2, 'Michael', 'CS', 2);

成功执行命令后插入 Cassandra,将在 Cassandra 表格学生学号为 2、姓名为 Michael、部门为 CS、学期为 2。

这是当前数据库状态的快照。

插入资料

更新插入数据

Cassandra 执行 upsert。Upsert 意味着 Cassandra 如果主键不存在,则插入一行,否则,如果主键已经存在,则更新该行。

这会带来一个值得明确说明的实际后果:INSERT 语句永远不会报告重复键错误,因此意外的重复插入操作会在没有任何警告的情况下覆盖现有行。当必须避免这种情况时,可以在语句后添加 IF NOT EXISTS 语句,使其成为一个轻量级事务。

INSERT INTO University.Student (RollNo, Name)
VALUES (2, 'Michael') IF NOT EXISTS;

轻量级事务使用跨副本的共识轮,因此比普通写入慢得多,应该保留给真正需要检查的情况。

更新资料

此 Cassandra 更新查询用于更新 Cassandra 表。如果更新数据后没有返回结果,则表示数据更新成功,否则将返回错误。列值在'Set'子句中更改,而数据则通过'Where'子句进行过滤。

句法

UPDATE KeyspaceName.TableName
SET ColumnName1 = NewValue1,
    ColumnName2 = NewValue2
WHERE ColumnName = ColumnValue;

例如:

这是显示更新数据之前数据库状态的屏幕截图。

更新资料

这是执行的快照 Cassandra 更新命令,更新学生表中的记录。

更新资料

UPDATE University.Student
SET name = 'Hayden'
WHERE rollno = 1;

成功执行更新查询后 Cassandra “更新学生”,学生姓名将从“Clark”更改为“Hayden”,学号为 1。

以下是显示更新数据后的数据库状态的屏幕截图。

更新资料

由于 upsert 行为,对不存在的主键执行 UPDATE 操作时,系统会创建该行而不是失败。

Cassandra 删除资料

命令“Delete”会从 Student 表中删除整行或部分列。删除数据时,不会立即从表中删除。而是用墓碑标记已删除的数据,并在压缩后删除。

句法

DELETE FROM KeyspaceName.TableName
WHERE ColumnName1 = ColumnValue;

以上 Cassandra 删除行语法将根据 where 子句中的数据过滤删除一行或多行。

DELETE ColumnName1, ColumnName2 FROM KeyspaceName.TableName
WHERE ColumnName1 = ColumnValue;

上述语法将从表中删除一些列。

例如:

这是显示删除数据之前当前数据库状态的快照。

Cassandra 删除资料

这是从表 Student 中删除一行的命令的快照。

Cassandra 删除资料

DELETE FROM University.Student WHERE rollno = 1;

成功执行 CQL 删除命令后,将从 Student 表中删除 rollno 值为 1 的一行。

这是显示删除数据后的数据库状态的快照。

Cassandra 删除资料

墓碑标记会保留 gc_grace_seconds 秒,默认值为十天,这样,在删除操作期间离线的节点在恢复后就无法恢复该行。因此,删除大卷会留下标记,后续每次读取都必须扫描这些标记。

什么是 Cassandra 不支持

CQL 借用了 SQL 语法,但没有借用关系执行模型,因此一些熟悉的结构表现不同或缺失。

  1. CQL 不支持表之间的连接。相关数据必须在写入时反规范化到同一个表中。
  2. CQL 不支持 WHERE 子句中的 OR 条件。请使用 IN 语句处理单个列,或运行单独的查询。
  3. CQL 不支持 UNION 或 INTERSECT。
  4. 非主键列必须先建立索引才能进行筛选。
  5. 大于和小于比较仅适用于聚类列,因为只有这些列在磁盘上是排序的。
  6. 使用 LIKE 进行模式匹配需要 SASI 索引,并且不能用于普通列。

一个长期存在的说法需要纠正。聚合函数是受支持的: 计数、最小值、最大值、总和 AVG 到达 Cassandra 2.2和 通过...分组 3.10 版本已推出。需要注意的是适用范围而非可用性。

SELECT dept, COUNT(*) FROM University.Student
WHERE RollNo = 1 GROUP BY dept;

如上所述,如果仅限于单个分区,聚合操作效率很高。但如果遍历整个表,则需要进行集群范围的扫描,这就是为什么…… Cassandra 仍然不适用于临时分析,这也是为什么繁重的报告工作通常会被推迟到其他场景。 Spark 或者外部仓库。

Cassandra 条款的地方

In Cassandra,数据检索是一个敏感问题。该列被过滤在 Cassandra 通过在非主键列上创建索引。

句法

SELECT ColumnNames FROM KeyspaceName.TableName
WHERE ColumnName1 = Column1Value
  AND ColumnName2 = Column2Value;

例如:

  • 下面是显示没有经过数据过滤的从学生表检索数据的快照。

Cassandra 条款的地方

SELECT * FROM University.Student;

从学生表中检索两条记录。

  • 以下快照显示了通过数据过滤从 Student 检索数据的过程。检索到一条记录。

数据按名称列筛选。检索所有名称等于指定值的记录。 Guru99.

Cassandra 条款的地方

SELECT * FROM University.Student WHERE name = 'Guru99';

WHERE 子句可以引用哪些列的规则直接由主键决定。

  • 分区键 必须完整提供该信息才能进行有效查询,因为它标识了保存数据的节点。
  • Cluster列 之后可能会受到限制,但只能按照宣布的顺序进行限制。ping 其中一个被拒绝。
  • 只允许对最后引用的聚类列进行范围比较,不允许对更早的聚类列进行范围比较。
  • 任何 其他栏 需要一个辅助索引,这部分内容将在……中介绍。 创建和删除索引 教程。

当查询被拒绝时, Cassandra 通常建议添加 ALLOW FILTERING。请将其视为警告而非修复方案:它会扫描每个节点上的每个分区,而更改模式几乎总是正确的应对措施。

常见问题

批处理将语句分组,使它们同时成功或失败。它适用于保持重复表的同步,但不适用于批量加载,因为跨多个分区进行批处理会严重降低协调器的速度。

驱动程序使用分页状态令牌自动分页。在 cqlsh 中,PAGING 设置分页大小。避免使用计数器来模拟 OFFSET,因为 Cassandra 没有有效的行跳过ping 机制。

如果副本宕机时间超过 gc_grace_seconds,且墓碑标记已被压缩清除,则该副本仍会保留旧行并将其重新展开。定期修复可以避免这种情况。

简单的单表查询可以很好地转换。但任何包含连接、OR 或子查询的查询都没有直接对应的 CQL 语句,而 AI 通常使用 ALLOW FILTERING 来掩盖这个问题,但这并非根本解决方案。

是的,粘贴 TRACING ON 输出通常可以清晰地读取墓碑扫描、宽分区或跨节点跳转信息。在应用建议的模式更改之前,请在副本上验证该更改。

总结一下这篇文章: