模式
{
"_id" : ObjectId("5069d68700a2934015000000"),
"port_name" : "CL1-A",
"metric" : 340,
"port_number" : "0",
"datetime" : ISODate("2012-09-30T13:44:00Z"),
"array_serial" : "12345"
}
每个阵列有128个端口,每个文档是该指标的一分钟数据。由于基数较低,所以array_serial似乎不是分片键的好选择,也就是说,串行12345
的所有数据都必须保留在同一个分片上而不能分成块,正确?
port_number
似乎允许适度的基数,但它会使查询隔离失败,因为同一阵列上多个端口的单个查询将跨越多个分片。我预计用户不需要一次查询超过4-8个端口。
答案是一个组合吗?我应该使用一段日期时间,例如月份还是周?
答案 0 :(得分:7)
关于数组序列,是的,这是正确的。
如果你选择“port_number”,它将具有足够高的基数,并且意味着具有相同“port_number”的所有文档将驻留在同一块中,但如果查询到达一系列端口,那么它'会打多个分片。
正如您所猜测的那样,选择正确的分片键非常重要且很难。 “完美”分片键满足三个互斥目标:
避免连续分片键的一个原因是它会在插入上创建热点:在任何给定时间,单个分片将占用所有插入负载(它有利于查询隔离但最终不会影响性能 - 因此_id和“datetime”不是很好的选择)。我可能会去复合分片键。 Google集团就此主题进行了一些很好的讨论:
如果您选择{array_serial:1,datetime:1}之类的内容,那么“array_serial”的数据将根据需要分解为多个块(基于日期时间)并分布在服务器上。使用完整的“datatime”值。
“array_serial”是如何决定的?价值范围是多少?我假设port_name更改为port_number更改?
鉴于你所说的话,我可能会选择{port_number:1,datetime:1},它并不完美,但它还不错。
这是您的最佳选择吗?这实际上取决于使用信息。
如果您要在特定端口号范围内对特定名称进行查询,那么这可能是您的最佳选择。
另一方面,如果您将主要根据日期时间而不管端口号执行所有“名称”的查询,那么您每次都会进行分散/收集查询,这将降低整体性能你的集群。
另外,问问自己
单个分片可以处理所有插入吗?
范围查询性能对您来说真的很重要吗?
根据您的问题,我猜您已经阅读了choosing a shard key上的链接:)
以下是关于选择可能对您有用的好的分片键的进一步讨论: