模式
{
"_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个端口。
答案是一种组合吗?我是否应该使用日期时间的一部分,比如月或周?
发布于 2012-10-19 19:18:07
关于数组序列,是的,这是正确的。
如果您使用"port_number",它将具有足够高的基数,并且将意味着具有相同"port_number“的所有文档将驻留在相同的块中,但是如果查询到达一定范围的端口,那么它将命中多个分片。
正如您所猜到的,选择正确的分片密钥是非常重要和困难的。一个“完美”的分片键满足三个互斥的目标:
单个文档的
避免使用顺序分片键的原因之一是它将在插入时创建热点:在任何给定时间,单个分片将承担所有插入负载(它有利于查询隔离,但最终不利于性能-因此_id和"datetime“不是好的选择)。我可能会选择一个复合分片密钥。在Google Group上有一些关于这个话题的很好的讨论:
如果您选择{ array_serial :1,datetime :1},那么如果需要,"array_serial“的数据将被分成许多块(基于datetime),并分布在服务器上。使用完整的"datatime“值。
"array_serial“是如何决定的?取值范围是什么?我假设port_name会随着port_number的变化而变化?
考虑到你所说的,我可能会选择{ port_number : 1,datetime: 1},它不是完美的,但也不坏。
这对你来说是最好的选择吗?这真的取决于使用信息。
如果您主要要查询特定端口号范围内的特定名称,那么这可能是最适合您的关键字。
另一方面,如果您将主要执行基于日期时间的所有“名称”的查询,而不考虑端口号,那么您将每次执行分散/聚集查询,这将降低集群的整体性能。
另外,问问你自己
根据您的问题,我猜您已经阅读了choosing a shard key上的链接:)
下面是一些关于挑选一个好的分片密钥的进一步讨论,可能会对你有所帮助:
》
https://stackoverflow.com/questions/12961873
复制相似问题