图式

{
        "_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不是shard key的好选择,因为它的基数很低,也就是说,serial12345的所有数据都必须保持在同一个shard上,而不是分成块,对吗?
似乎port_number允许适度的基数,但是查询隔离会失败,因为同一数组上多个端口的单个查询将跨越多个碎片。我不认为用户一次需要查询超过4-8个端口。
答案是组合词吗?我应该使用一段日期时间,比如月还是周?

最佳答案

关于阵列序列,是的,这是正确的。
如果您选择“端口号”,它将具有足够高的基数,这意味着具有相同“端口号”的所有文档将位于同一块中,但如果查询到达一个端口范围,则它将命中多个碎片。
如您所料,选择正确的切分键是非常重要和困难的。“完美”切分键满足三个相互排斥的目标:
写入应该均匀地分布在碎片上
单个文档的查询应该均匀地分布在碎片上
范围查询和排序应该是有效的,这意味着序列中的元素都应该在同一个shard上。
避免顺序shard键的原因之一是它将在插入时创建热点:在任何给定的时间,单个shard将承担所有插入负载(这有利于查询隔离,但最终不利于性能—因此,id和datetime不是好的选择)。我可能要一把复合碎片钥匙。关于这个话题,谷歌集团有一些很好的讨论:
https://groups.google.com/forum/?fromgroups=#!topic/mongodb-user/yolfc6B3JL8
如果您选择类似{array_serial:1,datetime:1}的内容,那么如果需要,“array_serial”的数据将被分成许多块(基于datetime),并分布在服务器上。使用完整的“datatime”值。
“阵列序列”是如何确定的?值的范围是什么?我认为端口名会随着端口号的改变而改变?
考虑到你所说的,我可能会选择{port-number:1,datetime:1},这并不完美,但也不坏。
这是你最好的选择吗?它实际上取决于使用信息。
你最常见的问题是什么?
如果您主要要查询特定端口号范围内的特定名称,那么这可能是您的最佳键。
另一方面,如果您主要是基于日期时间执行所有“名称”的查询,而不管端口号是多少,那么您每次都将执行分散/聚集查询,这将降低集群的总体性能。
另外,问问你自己
一个碎片能处理你所有的插入物吗?
范围查询性能对您真的很重要吗?
基于您的问题,我猜您已经阅读了choosing a shard key上的链接:)
下面是一些关于选择一个好的切分键的进一步讨论,可能有助于您:
克里斯蒂娜·乔德罗的优秀著作《缩放MongoDB》
Kristina's blog post on shard keys
Tyler Brock's overview presentation on sharding
Antoine Girbal's presentation on Sharding Best Practices

10-01 13:55