【问题标题】:Migrate data model from MySQL to Cassandra将数据模型从 MySQL 迁移到 Cassandra
【发布时间】:2017-08-19 09:51:33
【问题描述】:

MySql 中的结构(为了紧凑,我使用简化的符号)

表示法:表名->[column1(key or index), column2, ...]

documents->[doc_id(primary key), title, description]
elements->[element_id(primary key), doc_id(index), title, description]

每个文档可以包含大量元素(1 到 100k+ 之间)

我们有两个关键要求:

  • 快速加载给定 doc_id 的所有元素
  • 通过 element_id 快速更新单个元素的值

Cassandra 中的结构

第一种解决方案

documents->[doc_id(primary key), title, description, elements] (elements could be a SET or a TEXT, each time new elements are added (they are never removed) we would append it to this column)
elements->[element_id(primary key), title, description]

要加载我们需要的文档:

  • 使用给定加载文档并获取所有元素 ID:SELECT * from documents where doc_id='id'

  • 加载具有给定 ID 的所有元素:SELECT * FROM elements where element_id IN(从查询 a 加载的 ID)

更新元素将通过它们的主键来完成。

第二个解决方案

documents->[doc_id(primary key), title, description]
elements->[element_id(primary key), doc_id(secondary index), title, description]

要加载我们需要的文档:

  • SELECT * from elements where doc_id='id'

更新元素将通过它们的主键来完成。

关于我们的解决方案的问题:

  • 1st:在elements表中查询100k+个主键会不会很高效?

    SELECT * FROM elements WHERE element_id IN (element_id1,.... element_id100K+)?
    
  • 第二个:仅通过二级索引进行查询是否有效?

谁能给我们如何为我们的用例创建模型的建议?

【问题讨论】:

    标签: mysql cassandra


    【解决方案1】:

    对于 cassandra,一切都与访问模式有关(希望我理解正确,如果没有请评论)

    第一个

    文档不应该使用集合,因为集合被限制为 65 535 个元素,并且必须在每次更改时都被读取和更新。因为你需要 100k+ 这不是你想要的。您可以使用冻结的集合等,但话又说回来,每次读取内存中的所有内容都会很慢。

    第二次

    二级索引,好吧,小的基数数据可能没问题但是据我了解,每个文档有 100k,这甚至可能没问题,但话又说回来,这不是最佳实践。我会在你的具体案例中尝试一下。

    3rd - 磁盘是便宜的方法 - 始终以您将要读取的方式写入数据 - cassandra 的写入非常便宜,因此在写入时准备视图,

    这个满足读取所有属于doc_id的元素

    documents->[doc_id(primary key), title_doc (static), description_doc(static), element_id(clustering key), title, description]
    

    元素几乎保持原样:

    elements->[element_id(primary key), doc_id, title, description]
    

    进行更新时,您在文档和元素中更新它(为了保持一致性,您可以使用批处理操作 - 如果您需要它)如果有 element_id,您可以在获得它的文档 ID 后快速发出另一个查询。 根据您的更新需要 documentId 也可以是一组。 (我可能没有正确理解这部分,因为不确定更新元素时​​有哪些可用数据您是否也有 doc_id 以及一个元素是否可以在更多文档中?)

    另外,由于在单个分区中有 100k+ 元素并不是最好的,因为检索(所有请求都将转到一个节点)我建议使用复合分区键(桶)我认为在你的情况下一个简单的固定int 就好了。所以每次你去检索你刚刚发出的元素时,选择 documentid + (1, 2, 3, 4 ...) 然后在客户端合并结果 - 这会明显更快。

    一个棘手的部分是,您不会进入存储在文档中的每个存储桶中的 elementid ......当我想到它时,最好使用以两个为基数的存储桶。在你的情况下,16 是理想的......然后当你想要更新特定元素时,只需使用一些你知道的简单哈希函数并使用最后 4 位。

    现在我想,如果元素 id + doc id 始终为您所知,您甚至可能根本不需要元素表。

    希望对你有帮助

    【讨论】:

    • 您的解决方案(第 3 个)需要按 doc_id 和 element_id 查询文档,对吗?据我了解,您需要在 WHERE 子句中同时写入 partition_key 和集群键,不幸的是,在加载文档时我们不会预先知道所有元素 ID。我们只会知道 document_guid。我编辑了我的问题。谢谢。
    • 不只是分区键很好,你不需要提供所有的集群列驱动程序可以毫无问题地迭代它。我会用一些额外的提示更新我的答案。您还需要将 10 万个元素分配到存储桶中,以提高检索效率。
    【解决方案2】:

    根据Marko的建议,我们的解决方案是:

    CREATE TABLE documents (
       doc_id uuid,    
       description text,    
       title text,    
       PRIMARY KEY (doc_id)
     );
    
    CREATE TABLE nodes (
       doc_id uuid,
       element_id uuid,
       title text,
       PRIMARY KEY (doc_id, element_id)
    );
    

    我们可以通过以下查询检索所有元素:

    SELECT * FROM elements WHERE doc_id='id'
    

    并更新元素:

    UPDATE elements SET title='Hello' WHERE doc_id='id' AND element_id='id';
    

    【讨论】:

      猜你喜欢
      • 2013-11-28
      • 2017-01-07
      • 2011-08-31
      • 1970-01-01
      • 1970-01-01
      • 2015-01-29
      • 2020-11-18
      • 1970-01-01
      • 2015-10-21
      相关资源
      最近更新 更多