如何避免cassandra中的二级索引?

bra*_*orm 13 cql3 secondary-indexes cassandra-2.0

我一再听说二级索引(在cassandra中)只是为了方便而不是为了获得更好的性能.建议在基数较低时使用二级索引的唯一情况(例如性别column为男性或女性的两个值)

考虑这个例子:

CREATE TABLE users ( 
userID uuid, 
firstname text, 
lastname text, 
state text, 
zip int, 
PRIMARY KEY (userID) 
);
Run Code Online (Sandbox Code Playgroud)

现在,除非我在users on上创建二级索引,否则我无法执行此查询firstname index

select * from users where firstname='john'
Run Code Online (Sandbox Code Playgroud)

如何对此表进行非规范化,以便我可以使用此查询:这是使用复合键的唯一有效方法吗?还有其他选择或建议吗?

CREATE TABLE users ( 
    userID uuid, 
    firstname text, 
    lastname text, 
    state text, 
    zip int, 
    PRIMARY KEY (firstname,userID) 
    );
Run Code Online (Sandbox Code Playgroud)

med*_*oma 19

为了提出一个好的数据模型,您需要确定要执行的第一个ALL查询.如果您只需要按名字(或名字和用户ID)查找用户,那么您的第二个设计就好了...

如果您还需要按姓氏查找用户,则可以创建另一个表,该表具有相同的字段,但主键位于(lastname,userID).显然,您需要在同一时间更新两个表.数据重复在Cassandra中很好.

但是,如果您担心两个或更多表所需的空间,您可以创建一个按用户标识分区的单个用户表,以及要查询的字段的其他表:

CREATE TABLE users ( 
    userID uuid, 
    firstname text, 
    lastname text, 
    state text, 
    zip int, 
    PRIMARY KEY (userID) 
);

CREATE TABLE users_by_firstname (
    firstname text,
    userid uuid,
    PRIMARY KEY (firstname, userid)
);
Run Code Online (Sandbox Code Playgroud)

此解决方案的缺点是您需要两个查询来按用其名字检索用户:

SELECT userid FROM users_by_firstname WHERE firstname = 'Joe';
SELECT * FROM users WHERE userid IN (...);
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助

  • 我认为你的问题的本质是"如何对这个表进行非规范化,以便我可以进行此查询".如前所述,除非您通过分区键预过滤数据,否则二级索引的性能不会很好.根据我在一个相对较小的集群(5个节点)上的测试,它们比分区键的查询慢10倍.在更大的集群上,差异可能更大.根据我的经验,使用辅助表模拟它们要好得多,就像我使用users_by_firstname表一样. (4认同)
  • 正确.背后的原因是行由分区键分区,因此在查找期间,Cassandra确切地知道哪个节点保存数据.使用二级索引,每个节点都维护自己的索引,并且需要在所有节点上执行查询,然后需要组合结果.所以是的,分区键的两个查询比二级索引的查询快.使用不同的主键复制表也是一个很好的解决方案. (3认同)
  • 举个例子,你可以拥有用户表的主键(firstname,userid).然后,您可以在lastname上创建二级索引.在这种情况下,来自firstname ='Joe'和lastname ='Doe'的用户的查询SELECT*可以从姓氏上的索引中受益,因为数据已经由firstname预先过滤,因此它可以在单个节点上执行.另一个用例是当你不太关心性能时,只想要一个简单的解决方案. (2认同)