MySql 中的结构(为了紧凑起见,我使用简化的符号)
表示法:表名->[列 1(键或索引), 列 2, ...]
documents->[doc_id(primary key), title, description]
elements->[element_id(primary key), doc_id(index), title, description]
每个文档可以包含大量元素(介于 1 和 100k+ 之间)
我们有两个关键要求:
- 快速加载给定doc_id的所有元素
- 通过他的element_id快速更新单个元素的值
卡桑德拉的结构
第一个解决方案
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:从 doc_id='id' 的文档中选择 *
加载具有给定 id 的所有元素:选择 * FROM element_id in 的元素(从查询 a 加载的 ID)
更新元素将由其主键完成。
第二个解决方案
documents->[doc_id(primary key), title, description]
elements->[element_id(primary key), doc_id(secondary index), title, description]
要加载文档,我们需要:
- 从 doc_id='id' 的元素中选择 *
更新元素将由其主键完成。
关于我们解决方案的问题:
第一:在元素表中查询100k+主键会有效吗?
SELECT * FROM elements WHERE element_id IN (element_id1,.... element_id100K+)?
2nd:仅通过二级索引查询是否有效?
谁能给出任何建议,我们将如何为我们的用例创建一个模型?
对于 cassandra,一切都与访问模式有关(我希望我理解正确,如果没有,请发表评论)
第一
文档不应使用 SETS,因为 Set 限制为 65,535 个元素,每次进行更改时都必须完整地阅读和更新。由于您需要100k +,因此这不是您想要的。您可以使用冻结集合等,但话又说回来,每次读取内存中的所有内容肯定会很慢。
第二
二级索引,嗯,小基数数据可能没问题 但据我了解,每个文档有 100k,这甚至可能很好,但话又说回来,这不是最佳做法。我会简单地在你的具体案例中尝试一下。
第三 - 磁盘是便宜的方法 - 始终以您将要读取的方式写入数据 - 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 ...),然后在客户端合并结果 - 这将明显更快。
一个棘手的部分是,您不会进入存储在文档中的元素ID的每个存储桶......当我考虑它时,最好使用两个底座作为桶。在您的情况下,16 将是理想的...然后,当您要更新特定元素时,只需使用一些您已知的简单哈希函数并使用最后 4 位。
现在,当我考虑一下,如果您始终知道元素id + doc id,您甚至可能根本不需要元素表。
希望这有帮助
根据 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';