除了分区键的基数和额外的存储要求,如果我使用多簇列方法,我应该注意什么?
这似乎是一个需要帮助的有趣问题,因此我构建了一些具有不同 PRIMARY KEY 结构和选项的 CQL 表。然后我使用http://geohash.org/提出了一些端点,并插入了它们。
aploetz@cqlsh:stackoverflow> SELECT g1, g2, g3, g4, g5, g6, g7, g8, geohash, pid, data FROm georecords3;
g1 | g2 | g3 | g4 | g5 | g6 | g7 | g8 | geohash | pid | data
----+----+----+----+----+----+----+----+--------------+------+---------------
d | p | 8 | 9 | v | c | n | e | dp89vcnem4n | 1001 | Beloit, WI
d | p | 8 | c | p | w | g | v | dp8cpwgv3 | 1003 | Harvard, IL
d | p | c | 8 | g | e | k | t | dpc8gektg8w7 | 1002 | Sheboygan, WI
9 | x | j | 6 | 5 | j | 5 | 1 | 9xj65j518 | 1004 | Denver, CO
(4 rows)
如您所知,Cassandra 旨在返回具有特定、精确键的数据。使用多个聚类列有助于该方法,因为您正在帮助 Cassandra 快速识别您希望检索的数据。
我唯一想改变的是,看看你是否可以在没有PRIMARY KEYgeohash
或pid
PRIMARY KEY 的情况下做。我的直觉说要摆脱pid
,因为它确实不是您要查询的任何东西。它提供的唯一价值是唯一性,如果您计划多次存储相同的地理哈希,您将需要它。
在您的 PRIMARY KEY 中包含pid
一个非键列,这允许您使用该WITH COMPACT STORAGE
指令。真正让您受益的唯一真正优势是节省磁盘空间,因为集群列名称不与值一起存储。从cassandra-cli
工具中查看表格时,这一点变得很明显:
没有紧凑存储:
[default@stackoverflow] list georecords3;
Using default limit of 100
Using default cell limit of 100
-------------------
RowKey: d
=> (name=p:8:9:v:c:n:e:dp89vcnem4n:1001:, value=, timestamp=1428766191314431)
=> (name=p:8:9:v:c:n:e:dp89vcnem4n:1001:data, value=42656c6f69742c205749, timestamp=1428766191314431)
=> (name=p:8:c:p:w:g:v:dp8cpwgv3:1003:, value=, timestamp=1428766191382903)
=> (name=p:8:c:p:w:g:v:dp8cpwgv3:1003:data, value=486172766172642c20494c, timestamp=1428766191382903)
=> (name=p:c:8:g:e:k:t:dpc8gektg8w7:1002:, value=, timestamp=1428766191276179)
=> (name=p:c:8:g:e:k:t:dpc8gektg8w7:1002:data, value=536865626f7967616e2c205749, timestamp=1428766191276179)
-------------------
RowKey: 9
=> (name=x:j:6:5:j:5:1:9xj65j518:1004:, value=, timestamp=1428766191424701)
=> (name=x:j:6:5:j:5:1:9xj65j518:1004:data, value=44656e7665722c20434f, timestamp=1428766191424701)
2 Rows Returned.
Elapsed time: 217 msec(s).
紧凑型存储:
[default@stackoverflow] list georecords2;
Using default limit of 100
Using default cell limit of 100
-------------------
RowKey: d
=> (name=p:8:9:v:c:n:e:dp89vcnem4n:1001, value=Beloit, WI, timestamp=1428765102994932)
=> (name=p:8:c:p:w:g:v:dp8cpwgv3:1003, value=Harvard, IL, timestamp=1428765717512832)
=> (name=p:c:8:g:e:k:t:dpc8gektg8w7:1002, value=Sheboygan, WI, timestamp=1428765102919171)
-------------------
RowKey: 9
=> (name=x:j:6:5:j:5:1:9xj65j518:1004, value=Denver, CO, timestamp=1428766022126266)
2 Rows Returned.
Elapsed time: 39 msec(s).
但是,我建议不要使用WITH COMPACT STORAGE
,原因如下:
- 创建表后不能添加或删除列。
- 它可以防止您在表中有多个非键列。
- 它真的打算用于旧的(已弃用)基于节俭的列族(表)建模方法,并且真的不应该再使用/需要了。
- 是的,它可以节省磁盘空间,但磁盘空间很便宜,所以我认为这是一个很小的好处。
我知道你说“除了分区键的基数”,但无论如何我还是要在这里提一下。您会在我的示例数据集中注意到,几乎所有行都与d
分区键值一起存储。如果我要为自己创建一个这样的应用程序,在威斯康星州/伊利诺伊州州线区域跟踪 geohashes,我肯定会遇到我的大部分数据存储在同一个分区中的问题(在我的集群中创建一个热点)。因此,了解我的用例和潜在数据后,我可能会将前三个左右的列组合成一个分区键。
将所有内容存储在同一个分区键中的另一个问题是,每个分区最多可以存储大约 20 亿列。因此,在您的数据是否会超越该标记的情况下添加一些内容也是有意义的。显然,分区键的基数越高,遇到此问题的可能性就越小。
通过查看您的问题,在我看来,您已经查看了您的数据并且您理解了这一点……明确的“加号”。分区键中的 30 个唯一值应提供足够的分布。我只是想花一些时间来说明一下这可能有多大的交易。
无论如何,我还想添加一个“做得很好”,因为听起来你在正确的轨道上。
编辑
对我来说,仍然没有解决的问题是哪种方法可以更好地扩展,在哪些情况下。
可扩展性更依赖于您在 N 个节点上拥有多少 R 个副本。随着Cassandra 线性扩展;您添加的节点越多,您的应用程序可以处理的事务就越多。纯粹从数据分布场景来看,您的第一个模型将具有更高的基数分区键,因此它将比第二个分布更均匀。然而,第一个模型在查询灵活性方面提出了一个更具限制性的模型。
此外,如果您在分区内进行范围查询(我相信您说过是这样),那么第二个模型将以非常高效的方式实现这一点。分区内的所有数据都存储在同一个节点上。因此,查询g1='d' AND g2='p'
...etc... 的多个结果将执行得非常好。
我可能只需要更多地使用数据并运行测试用例。
这是一个好主意。我想您会发现第二种模型是可行的方法(就查询灵活性和多行查询而言)。如果在单行查询方面两者之间存在性能差异,我怀疑它应该可以忽略不计。