深入理解CQL中的Where子句

虽然CQL和SQL他们之间有很多的不同,但是他们也有很多相类似的语法。造成这些差异的原因主要来自于Cassandra处理分布式数据并旨在防止低效查询的事实。

其中CQL与SQL一个很大不同的地方在于他们的where子句。本文的目的就是描述CQL WHERE子句所支持的内容以及与普通SQL不同的原因。

主键列

在Cassandra数据中,主键列有两种数据类型组成而且他们有着特殊的意义:分区键列(the partition key columns )和集群列(the clustering columns)。他们两组合在一起

就确定了你每行的主键(相当于mysql的主键一样)。

分区键(partition key)列是主键的第一部分,其作用是将数据均匀地分布在集群中。行将依据分区键(partition key)的hash值分布在集群周围(注:说白了就是每行的数据放在集群的哪台机器是根据partition key进行hash计算来决定的)。

聚簇列(the clustering columns)通常用于聚集分区的数据,从而可以非常有效地检索行。

由于它们扮演的角色不同,分区键,clustering和普通列在WHERE子句使用中有着不同的限制。而且,这些限制条件根据查询类型而不同:比如SELECT,UPDATE或DELETE。

SELECT语句的WHERE子句限制

分区键key的限制

分区键列仅支持两个运算符:=和IN

IN的使用限制

在2.2版本之前,IN只能应用到分区键的最后一个列。所以,比如,如果你的表是下面这样的话:

CREATE TABLE numberOfRequests (

cluster text,

date text,

time text,

numberOfRequests int,

PRIMARY KEY ((cluster, date), time)

)

在2.1版本中,您只能在date这列上使用IN运算符。在2.2版本中,你可以在分区键列中的任何列中使用IN运算符.

最后,你的查询会像这样子:

SELECT * FROM numberOfRequests

WHERE cluster IN ('cluster1', 'cluster2')

AND date = '2015-05-06'

AND time >= '12:00'

AND time <= '14:00';

这个查询从2.2版本开始是正确的,但是在之前的版本是错误的。

这个更新使CQL更统一了,但是你还是应该小心在分区键列使用IN运算符的限制。 Ryan Svihla的好文章会给你一个清晰的解释,告诉你为什么要尽量避免它们。

2.2版本引入的另一个变化是操作结果不会按IN子句指定的分区键顺序返回。从2.2版本开始,操作结果以列类型的自然顺序返回而且重复值被忽略。

无限制的分区键列

Cassandra要求您要么限制所有分区键列要么一点都不限制,除非你的查询可以使用二级索引。

这意味着这个查询像这样子的:

SELECT * FROM numberOfRequests WHERE cluster='cluster1' AND time ='12:00';

这个查询将会拒绝因为date这列是不受限制的。

之所以这样,是因为Cassandra需要所有的分区键列才能够计算散列,以便它能够定位包含该分区的节点。

如果没有在分区键上指定限制条件,但在集群键上指定了某些限制条件,则Cassandra将要求ALLOW FILTERING被添加到查询中。有关ALLOW FILTERING的更多信息,您应该查看ALLOW FILTERING的解释。

, >=, <= and < operators

Cassandra distributes the partition accross the nodes using the selected partitioner.由于只有ByteOrderedPartitioner保持数据的有序分布,所以Cassandra不直接在分区键上支持>,> =,<=和<运算符。

然而,它允许您通过使用标记功能(token function)在分区键上使用>,>,<=和<运算符。

SELECT * FROM numberOfRequests

WHERE token(cluster, date) > token('cluster1', '2015-06-03')

AND token(cluster, date) <= token('cluster1', '2015-06-05')

AND time = '12:00';

如果使用ByteOrderedPartitioner,则可以在多个分区上执行一些范围查询。你应该小心,不建议使用ByteOrderedPartitioner,因为它可能会导致群集不平衡。

Clustering column的限制

Clustering column支持单列的=,IN,>,> =,<=,<,CONTAINS和CONTAINS KEY运算符以及多列的=,IN,>,> =,<=和<运算符。

clustering columns的无限制

clustering columns的作用是对分区内的数据进行群集。如果你有下面的表格:

CREATE TABLE numberOfRequests (

cluster text,

date text,

datacenter text,

hour int,

minute int,

numberOfRequests int,

PRIMARY KEY ((cluster, date), datacenter, hour, minute))

数据将按以下方式存储在每个分区中:

{datacenter: US_WEST_COAST {hour: 0 {minute: 0 {numberOfRequests: 130}} {minute: 1 {numberOfRequests: 125}} … {minute: 59 {numberOfRequests: 97}}} {hour: 1 {minute: 0 …

您可以看到,为了在没有二级索引的情况下以有效的方式检索数据,你需要知道你选择的所有集群键列。

所以,如果你执行下面语句:

SELECT * FROM numberOfRequests

WHERE cluster = ‘cluster1’

AND date = ‘2015-06-05’

AND datacenter = 'US_WEST_COAST'

AND hour = 14

AND minute = 00;

Cassandra将高效的找到上面所查询的数据,但是如果你执行的语句是下面这样的:

SELECT * FROM numberOfRequests

WHERE cluster = ‘cluster1’

AND date = ‘2015-06-05’

AND hour = 14

AND minute = 0;

Cassandra会拒绝上面这条语句的查询,因为它必须扫描整个分区才能找到请求的数据,效率不高(注:其实就是clustering key只能从左向右加条件且中间不能断,你可以只用给datacenter = 'US_WEST_COAST' 条件,hour和minute不给,但是你不能使用了minute字段但是没hour字段的查询)。

IN在Clustering column中的限制

在2.2版本之前,只有最后一个集群列(clustering columns)允许对集群列进行IN限制。在2.2中,IN限制可以用于任何列,下面的查询将起作用:

SELECT * FROM numberOfRequests

WHERE cluster = ‘cluster1’

AND date = ‘2015-06-05’

AND datacenter = 'US_WEST_COAST'

AND hour IN (14, 15)

AND minute = 0;

通过使用多列IN限制(multi-column IN restriction),可以在2.2版本之前检索相同的一组数据:

SELECT * FROM numberOfRequests

WHERE cluster = ‘cluster1’

AND date = ‘2015-06-05’

AND datacenter = 'US_WEST_COAST'

AND (hour, minute) IN ((14, 0), (15, 0));

在2.2中,多列IN限制可以应用于任何一组集群列。

SELECT * FROM numberOfRequests

WHERE cluster = ‘cluster1’

AND date = ‘2015-06-05’

AND (datacentre, hour) IN (('US_WEST_COAST', 14), (‘US_EAST_COAST’, 17))

AND minute = 0;

在2.2之前,多列IN限制只能应用于最后一组被限制的集群列。结果,以前的查询在2.1中是无效的。但是下面的查询是完全有效的。

SELECT * FROM numberOfRequests

WHERE cluster = ‘cluster1’

AND date = ‘2015-06-05’

AND datacenter = 'US_WEST_COAST'

AND (hour) IN ((14), (15));

, >=, <= and < restrictions(>, >=, <= and < 的使用限制)

单列在执行范围查询的时候只能出现在查询条件的最后一栏。

因此,下面的查询是正确的:

SELECT * FROM numberOfRequests

WHERE cluster = ‘cluster1’

AND date = ‘2015-06-05’

AND datacenter = 'US_WEST_COAST'

AND hour= 12

AND minute >= 0 AND minute <= 30;

SELECT * FROM numberOfRequests

WHERE cluster = ‘cluster1’

AND date = ‘2015-06-05’

AND datacenter = 'US_WEST_COAST'

AND hour >= 12;

SELECT * FROM numberOfRequests

WHERE cluster = ‘cluster1’

AND date = ‘2015-06-05’

AND datacenter > 'US';

但是下面这条语句是不正确的:

SELECT * FROM numberOfRequests

WHERE cluster = ‘cluster1’

AND date = ‘2015-06-05’

AND datacenter = 'US_WEST_COAST'

AND hour >= 12 AND minute = 0;

多列范围查询的时候最一组clustering columns的限制。

SELECT * FROM numberOfRequests

WHERE cluster = ‘cluster1’

AND date = ‘2015-06-05’

AND datacenter = 'US_WESTCOAST'

AND (hour, minute) >= (12, 0) AND (hour, minute) <= (14, 0)

如果你的查询是多列分片且后面一组是第一组列的子集,那么第二组的查询的列必须以第一组的第一列打头,如下面的列子:

SELECT * FROM numberOfRequests

WHERE cluster = ‘cluster1’

AND date = ‘2015-06-05’

AND datacenter = 'US_WEST_COAST'

AND (hour, minute) >= (12, 30) AND (hour) < (14)

这条语句是正确的,但是下面这条是错误的:

SELECT * FROM numberOfRequests

WHERE cluster = ‘cluster1’

AND date = ‘2015-06-05’

AND datacentre = 'US_WEST_COAST'

AND (hour, minute) >= (12, 0)

AND (minute) <= (45)

CONTAINS 和CONTAINS KEY 的使用限制

CONTAINS和CONTAINS KEY限制只能在查询使用二级索引时用于集合。

二级索引查询

对二级索引的直接查询只支持=,CONTAINS或CONTAINS KEY。

CONTAINS只能用于集合类型。 CONTAINS KEY只能用于map集合且map的key是建立了index的。

例如,你如果有这样的table:

CREATE TABLE contacts (

id int PRIMARY KEY,

firstName text,

lastName text,

phones map<text, text>,

emails set<text>

);

CREATE INDEX ON contacts (firstName);

CREATE INDEX ON contacts (keys(phones)); // Using the keys function to index the map keys

CREATE INDEX ON contacts (emails);

接下来的查询是生效的:

SELECT * FROM contacts WHERE firstname = 'Benjamin';

SELECT * FROM contacts WHERE phones CONTAINS KEY 'office';

SELECT * FROM contacts WHERE emails CONTAINS 'Benjamin@oops.com';

二级索引过滤器

二级索引查询允许您使用过滤在非索引列上使用=,>,> =,<=和<,CONTAINS和CONTAINS KEY来查询返回的结果。

因此,下面的查询是有效的,只要指定了ALLOW FILTERING:

SELECT * FROM contacts

WHERE firstname = 'Benjamin'

AND lastname = 'Lerer'

ALLOW FILTERING;

SELECT * FROM contacts

WHERE phones CONTAINS KEY 'office'

AND phones CONTAINS '0000.0000.0000'

ALLOW FILTERING;

你应该谨慎的使用filtering,因为这操作代价很高。

分区键上的二级索引限制

当Cassandra必须执行二级索引查询时,它将联系所有节点以检查位于每个节点上的二级索引的部分。如果所有分区键组件都受到限制,则Cassandra将使用该信息只查询包含指定分区键的节点,这将使查询更高效。

对于二级索引查询,分区键列上只支持=操作。

Clustering column restrictions and Secondary indices

对于每个索引值,Cassandra存储了整个主键(分区键列+集群列)的每一行包含值。当执行索引查询时,Casssandra将从索引中检索包含该值的行的主键。然后它将从表中检索行并执行所需的任何过滤。

如果第一个Clustering column已经被限制,Cassandra将对索引返回的主键执行一个过滤,使得过滤效率更高。

对于这种类型的过滤,Cassandra的 Clustering column将接受以下操作:=,IN,>,> =,<=和<。

所以,如果我们将以下二级索引添加到numberOfRequests表中:

CREATE INDEX ON numberOfRequests (minute);

他下面的查询是完全有效的:

SELECT * FROM numberOfRequests

WHERE cluster = 'cluster1'

AND date = '2015-06-05'

AND datacenter IN ('US_WEST_COAST', 'US_EAST_COAST')

AND minute = 0

ALLOW FILTERING;

WHERE子句对UPDATE和DELETE语句的限制

在UPDATE和DELETE语句中,所有主键列都必须受到限制,唯一允许的限制是:

1. 单列情况 = 可以作用在任何分区键或集群列上

2.单列IN 在最后一个分区键列上的限制

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容