• Cassandra Secondary Index 介绍


    摘要

    本文主要介绍cassandra中的索引,物化视图,有些知识点需要对cassandra有基本的认识才能理解。比如数据在cassandra节点中如何分布。如果有不明白的地方可以看本专栏之前文章。或者发送邮件和我探讨 cnstonefang@gmail.com。

    为什么叫secondary index

    CREATE TABLE user(
        id bigint,
        name text,
        email text,
        PRIMARY KEY(id)
    );
    

    在很多文档中可以看到cassandra index又被称为secondary index.这是相对primary index的概念。在创建上述user table 时,会根据primary key 默认创建 primary index,基于id 列。可以根据id来查询用户的信息。但是不同于关系型数据库。你没法根据email反向查id.为了实现这样的查询,可以基于email创建secondary index.

    CREATE INDEX email_index ON user(email);
    

    当你创建索引的时候,cassandra 会创建一个隐藏table来存储数据

    CREATE TABLE email_index(
       email text,
       id  bigint,
       PARMARY KEY(text,id)
    );
    

    secondary index 的这张表的信息是local aware的。和节点的数据存放在一起。而primary index是global.所以当你根据primary index columns 来查询的时候,cassandra ring 环上的每个节点都是知道数据是存储在哪些节点上的。但是如果根据secondary index columns 来查询。cassandra ring 环上的所有节点都是不知道数据放在哪些节点上的。必须要查询所有的节点。这也是为什么很多人说cassandra secondary index的效率很低的原因。但是实际上cassandra是不是会这么去查询呢,当然不会这么简单粗暴。一个1000节点的cluster,如果都去查的话,查询的coordinator肯定撑不住了。

    secondary index 查询

    cassandra 首先要查询所有节点,对于每个节点,要进行本地查询。没有secondary index时,不指定partition key,因为既要扫描所有的partition,每个patition里面还得全扫描,因此cassandra不允许这样的操作。创建了对应字段的secondary index后,如果不指定partition key,必须带上 ALLOW FILTERING,才能进行查询,但是不建议在生产环境中使用。

    本地查询:对于每个节点的本地查询,是比较简单明了的。根据secondary index columns值查询隐藏的index table,得到primary key,然后查询原表。

    cluster 查询:对于所有节点查询,cassandra 基于partition keys实现了一套复杂的算法来优化范围扫描查询。当然这套算法不止针对于secondary index.适用于所有的范围扫描。
    这套算法的基本点在于,循环查询。每一轮会根据CONCURRENCY_FACTOR 来决定有多少个节点会被查询,如果返回的数据不够。CONCURRENCT_FACTOR +1,直到返回的结果集够了。

    注意cassandra是根据token range 来查询这些节点的,所以返回的结果集没有特定的顺序。

    Notes
    尽管cassandra对范围查询进行了优化,但是不可否认的是基于secondary index查询的效率还是比较低。最好的实践是在对secondary index查询时,能够带上primary index 条件。比如partition =xxx,partition in(xx,yy)或者token(partition)>= xxx AND token(partition)<=yyy

    使用场合

    适用于有很多行都有的某个列(cassandra不要求每一行都必须存所有的列),并且这列的值范围比较大。
    另一方面,这些列不适合

    1.经常更新,删除的列

    cassandra 存储index 的墓碑有100K cells的限制,超过这个限制,基于index的column查询就会失败。
    另外index的数据也是存在隐藏表里面的。如果经常更新删除这列数据,不仅要写主表,还要写隐藏表。

    2.取值范围很低(low-cardinality)比如bool型

    对这样的列做索引,没什么意义。index 表中只有两个partition了。如果主表数据很多的话,就会
    每个partition就会很大。

    3.取值范围很高(high-cardinality)比如上面的例子,一个id对应一个email.

    如果对email做索引。那么当我们根据email查询时,就只有至多一个值了。最理想的情况,当我们
    查询一个节点时,就恰好查到了。最糟糕的情况,得查询完所有的节点,才能查到。

    看了2,3可能有些人很困惑,取值范围很低不适合index,取值范围很高也不适合index,有没有给出一个标准,什么
    样的叫取值范围高,什么样的叫取值范围低。让我怎么去判断。其实在cassandra的很多地方都存在这样的问题,没有一个
    非常严谨,准确的定义。需要使用者自己去平衡,根据实际的的表设计,数据分布去做性能分析,得出适合自己应用的表设计。

    与物化视图,新表的区别

    为了满足查询,cassandra经常需要创建新表,物化视图,索引来实现特点的查询。
    索引的特点在上面已经提到了。新创建一张表会有数据冗余,但是在分布式存储系统中,这是完全可以接受的,相比较视图新表多了数据维护。但是有些情况视图和索引都解决不了,比如上面提的low-cardinality 情况,视图也没法解决。因为视图是global的,会造成hot-spot情况,及视图数据都只存在某些固定的节点。

    另外视图的更新是异步更新的
    对cassandra感兴趣的童鞋可以参入群(104822562)一起学习探讨
    这里写图片描述

    参考

    http://www.planetcassandra.org/blog/cassandra-native-secondary-index-deep-dive/

    https://docs.datastax.com/en/cql/3.3/cql/cql_using/useWhenIndex.html

    http://www.datastax.com/dev/blog/materialized-view-performance-in-cassandra-3-x

    https://wiki.apache.org/cassandra/WritePathForUsers

  • 相关阅读:
    LeetCode Count of Range Sum
    LeetCode 158. Read N Characters Given Read4 II
    LeetCode 157. Read N Characters Given Read4
    LeetCode 317. Shortest Distance from All Buildings
    LeetCode Smallest Rectangle Enclosing Black Pixels
    LeetCode 315. Count of Smaller Numbers After Self
    LeetCode 332. Reconstruct Itinerary
    LeetCode 310. Minimum Height Trees
    LeetCode 163. Missing Ranges
    LeetCode Verify Preorder Serialization of a Binary Tree
  • 原文地址:https://www.cnblogs.com/stoneFang/p/6715289.html
Copyright © 2020-2023  润新知