深入理解CQL中的Where子句
发布网友
发布时间:2022-09-05 01:12
我来回答
共1个回答
热心网友
时间:2023-10-03 16:53
虽然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的解释。
Cassandra distributes the partition accross the nodes using the selected partitioner .由于只有ByteOrderedPartitioner保持数据的有序分布,所以Cassandra不直接在分区键上支持>,> =,<=和<运算符。
然而,它允许您通过使用标记功能(token function)在分区键上使用>,>,<=和<运算符。
SELECT * FROM numberOfRequests
如果使用ByteOrderedPartitioner,则可以在多个分区上执行一些范围查询。你应该小心,不建议使用ByteOrderedPartitioner,因为它可能会导致群集不平衡。
Clustering column的*
Clustering column支持单列的=,IN,>,> =,<=,<,CONTAINS和CONTAINS KEY运算符以及多列的=,IN,>,> =,<=和<运算符。
clustering columns的无*
clustering columns的作用是对分区内的数据进行群集。如果你有下面的表格:
CREATE TABLE numberOfRequests (
数据将按以下方式存储在每个分区中:
{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
Cassandra将高效的找到上面所查询的数据,但是如果你执行的语句是下面这样的:
SELECT * FROM numberOfRequests
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
通过使用多列IN*( multi-column IN restriction ),可以在2.2版本之前检索相同的一组数据:
SELECT * FROM numberOfRequests
在2.2中,多列IN*可以应用于任何一组集群列。
SELECT * FROM numberOfRequests
在2.2之前,多列IN*只能应用于最后一组被*的集群列。结果,以前的查询在2.1中是无效的。但是下面的查询是完全有效的。
SELECT * FROM numberOfRequests
单列在执行范围查询的时候只能出现在查询条件的最后一栏。
因此,下面的查询是正确的:
SELECT * FROM numberOfRequests
SELECT * FROM numberOfRequests
SELECT * FROM numberOfRequests
但是下面这条语句是不正确的:
SELECT * FROM numberOfRequests
多列范围查询的时候最一组clustering columns的*。
SELECT * FROM numberOfRequests
如果你的查询是多列分片且后面一组是第一组列的子集,那么第二组的查询的列必须以第一组的第一列打头,如下面的列子:
SELECT * FROM numberOfRequests
这条语句是正确的,但是下面这条是错误的:
SELECT * FROM numberOfRequests
CONTAINS 和CONTAINS KEY 的使用*
CONTAINS和CONTAINS KEY*只能在查询使用二级索引时用于集合。
二级索引查询
对二级索引的直接查询只支持=,CONTAINS或CONTAINS KEY。
CONTAINS只能用于集合类型。 CONTAINS KEY只能用于map集合且map的key是建立了index的。
例如,你如果有这样的table:
CREATE TABLE contacts (
);
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
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子句对UPDATE和DELETE语句的*
在UPDATE和DELETE语句中,所有主键列都必须受到*,唯一允许的*是:
1. 单列情况 = 可以作用在任何分区键或集群列上
2.单列IN 在最后一个分区键列上的*