Cassandra的数据模型类似于关系型数据库的模型,且提供了与SQL语言非常类似的CQL语言进行操作。

但是Cassandra的数据模型类似于多层键值对结构,与关系型数据库存在巨大差别。

本文基于: [cqlsh 5.0.1 | Cassandra 3.11.2 | CQL spec 3.4.4 | Native protocol v4]

目录:

多层KV结构

Cassandra 的数据模型由 keyspace (类似关系型数据库里的database), column family(类似关系型数据库里的table), 主键(key)和列(column)组成。

对于一个 column family 不应该想象成关系型数据库中的表, 而是一个多层的key-value结构:

Map<PartitionKey, SortedMap<ClusteringKey, Column>>

我们使用CQL来描述:

create table table1 (
key1 int,
key2 int,
content text,
PRIMARY KEY ((key1), key2)
);

在上述CQL创建的表(column family)中,key1是 partition key, 而 key2 是 clustering key, key1 和 key2 称为主键(PRIMARY KEY)

Cassandra支持更复杂的表结构:

CREATE TABLE table2 (
pkey1 int,
pkey2 int,
ckey1 int,
ckey2 int,
content text,
PRIMARY KEY ((pkey1, pkey2), ckey1, ckey2)
);

此时的数据结构可以描述为:

Map<pkey1, Map<pkey2, SortedMap<ckey1, SortedMap<ckey2, content>>>>

作为一个分布式数据库, Cassandra 根据 partition key 决定数据如何在集群的各个节点上分区。clustering key 决定数据在分区内的排序。

查询

下文中将以 table2 为例介绍 cassadra 数据模型的特性。

从上文使用Map描述的表结构可知,我们无法根据非主键进行查询(如table2中的data):

SELECT * FROM table2 WHERE content='a'; -- error
SELECT * FROM table2 WHERE pkey1 = 1 AND content='a'; -- error
SELECT * FROM table2 WHERE pkey1 = 1 AND pkey2 = 1; -- right

通常情况下,在对形如((pkey1, pkey2), ckey1, ckey2)这样的主键列进行查询时需要注意:

  • partition key 仅支持精确查询(=, in), 不能进行范围查询(>, <, >=, <=)。注: Cassandra 不支持 != 查询。
  • 涉及多个 partition key 的查询必须提供前置 partition key 的精确值。即若要查询 pkey2 则必须提供 pkey1 的精确值。
  • 涉及 clustering key 的查询,必须提供所有 partition key 的精确值
  • 涉及的 clustering key 不能跳跃,若要根据 ckey2 进行查询则必须提供 ckey1 的精确值

(请不要记忆上述结论,根据Cassandra的内部数据结构很容易明白可以进行什么样的查询)

下面根据具体示例说明。

仅涉及partition key:

SELECT * FROM table2 WHERE pkey1 = 1; -- right
SELECT * FROM table2 WHERE pkey1=1 AND pkey2=1; -- right
SELECT * FROM table2 WHERE pkey2=1; -- error

涉及一个 clustering key:

SELECT * FROM table2 WHERE pkey1=1 AND pkey2=1 AND ckey1>0; -- right
SELECT * FROM table2 WHERE pkey1=1 AND ckey1>0; -- error
SELECT * FROM table2 WHERE ckey1=1; -- error

涉及多个 clusterin key:

SELECT * FROM table2 WHERE pkey1=1 AND pkey2=1 AND ckey1=1 AND ckey2>0; -- right
SELECT * FROM table2 WHERE pkey1=1 AND pkey2=1 AND ckey2>0; -- error
SELECT * FROM table2 WHERE pkey1=1 AND pkey2=1 AND ckey1>0 AND ckey2=1; --error

排序

Cassandra 支持查询结果按照 clustering key 进行排序,不过排序功能也非常有限:

SELECT * FROM table2 WHERE pkey1=1 AND pkey2=1 ORDER BY ckey1; -- right
SELECT * FROM table2 WHERE pkey1=1 AND pkey2=1 ORDER BY ckey1, ckey2; -- right
SELECT * FROM table2 WHERE pkey1=1 AND pkey2=1 ORDER BY ckey2; -- error

使用排序功能和涉及 clustering key 的查询一样, 必须提供所有 partition key 的精确值(= 或 in 运算符)。这是因为 Cassandra 仅支持单个节点上数据的排序。

涉及多个 clustering key 的排序必须按照 clustering key 的顺序进行排序不能跳跃, 即可以ORDER BY ckey1, ckey2, 不能ORDER BY ckey2。

默认情况下只能进行升序排列,即ORDER BY ckey1 ASC, ORDER BY ckey2。

这是因为Cassandra只能根据每个节点上"SortedMap"固有的顺序排列查询结果,不过我们可以在创建表时自定义排序规则:

CREATE TABLE table2 (
pkey1 int,
pkey2 int,
ckey1 int,
ckey2 int,
content text,
PRIMARY KEY ((pkey1, pkey2), ckey1, ckey2)
) WITH CLUSTERING ORDER BY(ckey1 DESC, ckey2 ASC);

聚合

Cassandra 允许根据主键列定义的顺序进行聚合:

SELECT count(*) FROM table2 GROUP BY pkey1; -- right
SELECT count(*) FROM table2 GROUP BY pkey1, pkey2; -- right
SELECT count(*) FROM table2 GROUP BY pkey1, pkey2, ckey1, ckey2; -- right
SELECT count(*) FROM table2 WHERE pkey1=1 GROUP BY pkey2; -- error

这种聚合可以对多个节点上的数据进行聚合处理。

对于带有WHERE条件的查询, Cassandra 仅支持对单个节点上的数据进行聚合,就是说必须提供 partition key 的精确值才能进行聚合:

SELECT count(*) FROM table2 WHERE pkey1=1 AND pkey2=1 GROUP BY ckey1; -- right
SELECT count(*) FROM table2 WHERE pkey1=1 AND pkey2=1 GROUP BY ckey1, ckey2; -- right
SELECT count(*) FROM table2 WHERE pkey1=1 AND pkey2=1 GROUP BY ckey2; -- error
SELECT count(*) FROM table2 WHERE pkey1=1 GROUP BY pkey2; -- error

这一点与 Cassandra 查询时的特征是一致的。

Cassandra 支持 sum, min, max, count, distinct 等聚合功能, 不支持HAVING语句。

ALLOW FILTERING

上文我们提到一些 Cassandra 不支持的查询:

SELECT * FROM table2 WHERE ckey1=1;

可以看到 Cassandra 的报错信息:

Cannot execute this query as it might involve data filtering and thus may have unpredictable performance. If you want to execute this query despite the performance unpredictability, use ALLOW FILTERING

对于 Cassandra 多层嵌套KV的数据结构来说,不可能通过 key 查找到相应数据,只能搜索所有的数据来完成此查询。

对于一个有100万条数据表而言,ckey1=1的记录可能仅占5%, 此时 Cassandra 仍可以在可接受的时间内完成查询。但是,Cassandra 并不了解此查询需要搜索所有数据,因此需要操作者使用 ALLOW FILTERING 允许 Cassandra 扫描所有数据:

SELECT * FROM table2 WHERE ckey1=1 ALLOW FILTERING;

Cassandra 官方对于ALLOW FILTERING 进行了非常详尽的说明, 可以参考ALLOW FILTERING explained。

作者提醒, ALLOW FILTERING 可能消耗大量时间和资源,请谨慎在生产环境下使用此功能。

次级索引

除了主键列之外我们可以为 clustering key 和普通的值建立次级索引(secondary index)。

次级索引是一个另外的key-value映射, 可以根据索引列直接查找到数据。

创建索引:

CREATE INDEX idx_ckey1 on table2(ckey1);
CREATE INDEX idx_content on table2(content);

使用索引进行查询:

SELECT * FROM table2 WHERE ckey1=1; -- right
SELECT * FROM table2 WHERE content='a'; -- right
SELECT * FROM table2 WHERE ckey1>0; -- error
SELECT * FROM table2 WHERE pkey1=1 AND ckey1=1; --error

索引仅支持单独、精确查询, 不支持范围查询或者与主键(其它索引)联合查询。

请阅读官方文档When to use an index,了解索引的使用场景。

Cassandra 数据模型的更多相关文章

  1. Cassandra数据模型

    Ⅰ.数据模型 1.1 Column 一组包含Name/Value Pair的数据叫Row,其中每一组Name/Value Pair叫Column Column是Cassandra最基本的数据结构,它是 ...

  2. Cassandra 数据模型 (基于CQL,解决胖列数量限制及灵活性问题)(1.1及以上版本)

    文中主要交代Cassandra的编程模型及数据结构. 由于Cassandra版本数次更新,网上中文的资料已经有点过时,比较有代表性的比如ebuy那篇文章都已经过时了,于是自己找资料,结合官方博客写一篇 ...

  3. Cassandra数据模型和模式(Schema)的配置检查

    免责声明 本文档提供了有关DataStax Enterprise(DSE)和Apache Cassandra的常规数据建模和架构配置建议.本文档需要DSE / Cassandra基本知识.它不能代替官 ...

  4. Cassandra简介

    在前面的一篇文章<图形数据库Neo4J简介>中,我们介绍了一种非常流行的图形数据库Neo4J的使用方法.而在本文中,我们将对另外一种类型的NoSQL数据库——Cassandra进行简单地介 ...

  5. [转载] Cassandra入门 框架模型 总结

    转载自http://asyty.iteye.com/blog/1202072 一.Cassandra框架二.Cassandra数据模型 Colum / Colum Family, SuperColum ...

  6. 开源软件:NoSql数据库 - 图数据库 Cassandra

    转载原文:http://www.cnblogs.com/loveis715/p/5299495.html Cassandra简介 在前面的一篇文章<图形数据库Neo4J简介>中,我们介绍了 ...

  7. Cassandra标准列和超级列

    列(column)是Cassandra数据模型中的最基本的数据结构单元.列是一个由列名(key).值(value).时间戳(timestamp)构成的三元组.在关系型数据库中,你需要先定义列的名称和和 ...

  8. Cassandra基础

    Apache Cassandra特性 Apache Cassandra由Facebook基于Amazon的Dynamo及其在Google的Bigtable上的数据模型设计开发的面相列的数据库,实现没有 ...

  9. Cassandra 的数据存储结构——本质是SortedMap<RowKey, SortedMap<ColumnKey, ColumnValue>>

    Cassandra 的数据存储结构 Cassandra 的数据模型是基于列族(Column Family)的四维或五维模型.它借鉴了 Amazon 的 Dynamo 和 Google's BigTab ...

随机推荐

  1. python之模块调用

    1.以 atm_run 为入口,在atm中的main模块调用config中的settings from config import settings 2.以atm_run为入口,在main中调用log ...

  2. kbmmw 做REST 服务签名认证的一种方式

    一般对外提供提供REST 服务,由于信息安全的问题, 都要采用签名认证,今天简单说一下在KBMMW 中如何 实现简单的签名服务? 整个签名服务,模仿阿里大鱼的认证方式,大家可以根据实际情况自己修改. ...

  3. 安卓逆向学习---深入Smali文件

    参考:https://www.52pojie.cn/thread-396966-1-1.html Smali中的包信息 .class public Lcom/aaaaa; //他是com.aaaaa这 ...

  4. poj 3279(暴力)

    题意:有一个n*m的格子,每个格子都有黑白两面(0表示白色,1表示黑色).我们需要把所有的格子都反转成黑色,每反转一个格子,它上下左右的格子都会跟着反转.请求出用最小步数完成反转时每个格子反转的次数. ...

  5. H5+.Net Webapi集成微信分享前后端代码 微信JS-SDK wx.onMenuShareTimeline wx.onMenuShareAppMessage

    说明: 1/因为赚麻烦这里没有使用数据库或服务器缓存来存储access_token和jsapi_ticket,为了方便这里使用了本地的xml进行持久化这两个值以及这两个值的创建时间和有限期限. 2/每 ...

  6. Javascript百学不厌 - 模块模式

    记录自己觉得重要又可能忘记的东西 用模块模式产生安全的对象: var serial_maker = function () { var preifx = ''; var seq = 0; return ...

  7. 报警系统:php输出头信息以方便脚本抓取信息[排查篇]

    做监控系统时,需要对某个页面进行监控,可以通过很多方式进行报警,如:正常则输出一个规定的变量,错误时则不输出.但是还有一个更为方便的做法,就是当前错误时,直接使用header抛出信息,如: heade ...

  8. Ideas

    1.蔬菜店,自带种植的菜地.(实现蔬菜都是新采摘的.) 这个试用于农村,因为需要土地.农村现在蔬菜店大多也是外出进货.有些菜放久了,就坏掉了. 这里有问题就是,(1).如果销量不够,怎么让蔬菜不烂在菜 ...

  9. PHP画图的基本步骤GD库

    一:PHP新建一个图片步骤: :创建画布: $im=imagecreatetruecolor(300,80) 2:定义颜色: $black=imagecolorallocate($im, 0, 0, ...

  10. 个人博客搭建( wordpress )

    最近同学买了一台虚机( centos7 系统 ).一个域名,让帮忙搭一个个人博客.本着简单快捷,个人博客采用 wordpress 来搭建.为了以后博客系统的迁移方便,使用 docker 来安装 wor ...