为啥 Cassandra 不允许通过 IN 限制查询集群键?
Posted
技术标签:
【中文标题】为啥 Cassandra 不允许通过 IN 限制查询集群键?【英文标题】:Why Cassandra doesn't let to query clustering key by IN restriction?为什么 Cassandra 不允许通过 IN 限制查询集群键? 【发布时间】:2016-09-08 08:36:19 【问题描述】:有谁知道为什么我不能使用查询来限制 IN
和 I select
集合列的聚类列?
让我详细说明一下。假设我有类似于以下的数据模型:
create table inventory (
sku text,
class text,
unit text,
node text,
supply map<text, frozen<delta_and_time>>,
supply_compacted int,
primary key ((sku, class, unit), node));
当我尝试使用以下选择语句时:
select sku, class, unit, node, supply_compacted where sku = '0'
and class = 'good' and unit = 'each' and node in ('1', '2', '3')
一切都很好。但是当我尝试使用相同的限制select *
时,我得到了关注
错误:
Cannot restrict clustering columns by IN relations when a collection is selected by the query
我试图找出为什么在 C* 中有这样的限制,但我找不到任何东西。我也查看了代码,但没有信息为什么要执行这样的检查。
有谁知道这种限制的原因是什么?
【问题讨论】:
【参考方案1】:这是基于集合数据类型如何被“入侵”到现有存储引擎中的限制。 Map 集合是通过将每个键作为唯一列名存储在与聚类列相同的区域中来实现的。因此,Cassandra 很难高效地执行“IN”操作,尤其是对于每个“行”的大型集合大小。
但是,我确实认为您可以重新设计数据模型以绕过此限制,甚至不使用 Collection 类型(因为如果您不小心,它们会出现很多问题)。看起来“supply_compacted”可能是供应图中总库存的汇总?如果是这样,您可以执行以下操作:
create table inventory (
sku text,
class text,
unit text,
node text,
supply_compacted int static, -- stored once, total amount of inventory across all nodes
supply frozen<delta_and_time>,
primary key ((sku, class, unit), node)
);
【讨论】:
您能否详细说明same area as the clustering column
?
这是迄今为止我在技术中看到的最奇怪的限制......【参考方案2】:
我最初的想法是该约束是由于对内存和网络的影响来获取集合,因为可以在限制条件下一次返回多个集合。但是,我发现如果仅通过指定分区键的限制较少,查询就可以工作。
我的测试数据(在 Cassandra 3.7 上):
cqlsh:test> create table mytable(X text, Y text, Z text, mylist list<int>, primary key (X,Y));
cqlsh:test> insert into mytable (X,Y,Z,mylist) values('x','y1','z1',[1,2,3]);
cqlsh:test> insert into mytable (X,Y,Z,mylist) values('x','y2','z2',[4,5,6]);
cqlsh:test> select x,y,z from mytable where x = 'x' and y in ('y1');
x | y | z
---+----+----
x | y1 | z1
(1 rows)
cqlsh:test> select * from mytable where x = 'x' and y in ('y1');
InvalidRequest: Error from server: code=2200 [Invalid query] message="Cannot restrict clustering columns by IN relations when a collection is selected by the query"
cqlsh:test> select * from mytable where x = 'x';
x | y | mylist | z
---+----+-----------+----
x | y1 | [1, 2, 3] | z1
x | y2 | [4, 5, 6] | z2
(2 rows)
底层 sstable 转储:
$ sstabledump mb-1-big-Data.db
[
"partition" :
"key" : [ "x" ],
"position" : 0
,
"rows" : [
"type" : "row",
"position" : 15,
"clustering" : [ "y1" ],
"liveness_info" : "tstamp" : "2016-09-13T08:14:33.172799Z" ,
"cells" : [
"name" : "z", "value" : "z1" ,
"name" : "mylist", "deletion_info" : "marked_deleted" : "2016-09-13T08:14:33.172798Z", "local_delete_time" : "2016-09-13T08:14:33Z" ,
"name" : "mylist", "path" : [ "1a1a0760-798a-11e6-851a-e3954ecad15b" ], "value" : "1" ,
"name" : "mylist", "path" : [ "1a1a0761-798a-11e6-851a-e3954ecad15b" ], "value" : "2" ,
"name" : "mylist", "path" : [ "1a1a0762-798a-11e6-851a-e3954ecad15b" ], "value" : "3"
]
,
"type" : "row",
"position" : 99,
"clustering" : [ "y2" ],
"liveness_info" : "tstamp" : "2016-09-13T08:14:49.772718Z" ,
"cells" : [
"name" : "z", "value" : "z2" ,
"name" : "mylist", "deletion_info" : "marked_deleted" : "2016-09-13T08:14:49.772717Z", "local_delete_time" : "2016-09-13T08:14:49Z" ,
"name" : "mylist", "path" : [ "23fefce0-798a-11e6-851a-e3954ecad15b" ], "value" : "4" ,
"name" : "mylist", "path" : [ "23fefce1-798a-11e6-851a-e3954ecad15b" ], "value" : "5" ,
"name" : "mylist", "path" : [ "23fefce2-798a-11e6-851a-e3954ecad15b" ], "value" : "6"
]
]
]
正如您所见,集合与非主键列并没有真正的不同,除了在将其返回给客户端之前需要进行聚合。我想知道这是否是对旧的 thrift 实现的限制,并且即使没有明显的原因不能做到这一点,也会被延续。
【讨论】:
以上是关于为啥 Cassandra 不允许通过 IN 限制查询集群键?的主要内容,如果未能解决你的问题,请参考以下文章
为啥不可能有像 Cassandra 这样的 RDBMS/SQL 样式表?