考虑这样的表来存储用户的联系人 -
CREATE TABLE contacts {
user_name text,
contact_name text,
contact_id int,
contact_data blob,
PRIMARYKEY ((user, contact_name), contact_id)
// ^-- Note the composite partition key
}
复合分区键导致每个联系人一行。
假设有1亿用户,每个用户都有几百个联系人。
我可以使用
查找特定用户的特定联系人数据SELECT contact_data FROM contacts WHERE user_name='foo' AND contact_name='bar'
但是,也可以使用类似
之类的内容查找用户的所有联系人姓名SELECT contact_name FROM contacts WHERE user_name='foo'
? WHERE子句是否只包含构成主键的所有列中的一些?
编辑 - 我试过这个,而cassandra并不允许这样做。所以现在我的问题是,你如何建模数据以支持两个查询 -我可以想到两个选项 -
答案 0 :(得分:1)
在RDBMS中,查询计划程序可能能够为该类查询创建有效的查询计划。但卡桑德拉不能。卡桑德拉必须做一个表扫描。 Cassandra努力不让你做出那些类型的查询。所以它应该拒绝它。
答案 1 :(得分:1)
不,你不能。如果你看一下cassandra如何存储数据的机制,你就会明白为什么你不能通过复合分区键的一部分进行查询。
Cassandra根据分区键在节点之间分配数据。写请求的协调器使用分区键上的murmur3算法生成散列令牌,并将写请求发送给令牌的所有者。(每个节点具有它拥有的令牌范围)。在读取期间,协调器再次基于分区密钥计算散列令牌,并将读取请求发送到令牌的所有者节点。
由于您使用的是复合分区密钥,因此在写入请求期间,密钥(user,contact_name)的所有组件都将用于生成散列令牌。此令牌的所有者节点具有整行。在读取请求期间,您必须提供密钥的所有组件来计算令牌,并将读取请求发送给该令牌的正确所有者。因此,Cassandra强制您提供整个分区键。
答案 2 :(得分:0)
您可以使用两个具有相同结构但不具有相同分区键的不同表:
CREATE TABLE contacts {
user_name text,
contact_name text,
contact_id int,
contact_data blob,
PRIMARY KEY ((user_name, contact_name), contact_id)
}
CREATE TABLE contacts_by_users {
user_name text,
contact_name text,
contact_id int,
contact_data blob,
PRIMARY KEY ((user_name), contact_id)
}
使用此结构,您可以进行数据复制,并且必须手动维护这两个表。
如果您正在使用cassandra> 3.0,您还可以使用物化视图:
CREATE TABLE contacts {
user_name text,
contact_name text,
contact_id int,
contact_data blob,
PRIMARY KEY ((user_name, contact_name), contact_id)
}
CREATE MATERIALIZED VIEW contracts_by_users
AS
SELECT *
FROM contracts
WHERE user_name IS NOT NULL
AND contract_name IS NOT NULL
AND contract_id IS NOT NULL
PRIMARY KEY ((user_name), contract_name, contract_id)
WITH CLUSTERING ORDER BY contract_name ASC
在这种情况下,您只需维护表contracts
,视图将自动更新