【问题标题】:Mongo multi-field filter query and sort - optimizationMongo多字段过滤器查询和排序-优化
【发布时间】:2019-09-01 03:18:00
【问题描述】:

我有一个记录集合,其中包含 primary_id(唯一)、secondary_id、status 字段等。 ID 是字母数字字段(例如“ABCD0000”),状态是数字 (1 - 5)。 经常使用的查询之一是按 id(相等或范围)和状态进行过滤。

例子:

  1. primary_id 介于 'ABCD0000' - 'ABCN0000' 之间且状态为 2 或 3 的记录,按 primary_id 排序。
  2. 在“ABCD0000”-“ABCD0000”之间的secondary_id 和状态为2 或3 的记录,按primary_id(或secondary_id,如果有帮助)排序。

过滤器中的状态主要是((2,3)中的状态)。

最初我们在每个字段上都有一个索引。但是当范围很大时查询会超时。我尝试添加多个索引(单个和复合)并使用不同的方式编写过滤器,但无法获得不错的性能。现在我有了这些索引:

[
{primary_id: 1},
{secondary_id: 1},
{status: 1},
{primary_id: 1, status: 1},
{status: 1, primary_id: 1},
{status: 1, secondary_id: 1}
]

此查询(对 primary_id 进行排序或不排序)

{ $and: [ 
{ primary_id: { $gte: 'ABCD0000' } }, 
{ primary_id: { $lte: 'ABCN0000' } }, 
{status: { $in: [2,3] } } 
] }

使用以下计划:

...
"winningPlan" : {
    "stage" : "FETCH",
    "filter" : {
            "status" : {
                    "$in" : [
                            2,
                            3
                    ]
            }
    },
    "inputStage" : {
            "stage" : "IXSCAN",
            "keyPattern" : {
                    "primary_id" : 1
            },
            "indexName" : "primary_idx",
            "isMultiKey" : false,
            "multiKeyPaths" : {
                    "primary_id" : [ ]
            },
            "isUnique" : true,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 2,
            "direction" : "forward",
            "indexBounds" : {
                    "primary_id" : [
                            "[\"ABCD0000\", \"ABCN0000\"]"
                    ]
            }
    }
},

因此,如果返回的行数很大,则 FETCH 步骤似乎需要很长时间。令人惊讶的是,在运行初始状态测试时,primary_id 复合索引有时被选为获胜计划,而且速度非常快(几秒钟)。但由于某种原因,它不再被 Mongo 选中。我猜当查询需要按 primary_id 排序时,不会选择这个复合索引,正如我从 Mongo 文档中理解的那样

如果查询没有在排序规范之前或重叠的索引前缀上指定相等条件,则操作将无法有效地使用索引。

我尝试将查询更改如下,但仍未优化

{$or: [
{ $and: [ { primary_id: { $gte: 'ABCD0000' } }, { primary_id: { $lte: 'ABCN0000' } }, { status: 2 } ]},
{ $and: [ { primary_id: { $gte: 'ABCD0000' } }, { primary_id: { $lte: 'ABCN0000' } }, { status: 3 } ]}
]}

关于什么是更好的索引或查询策略有什么建议吗?

【问题讨论】:

    标签: mongodb mongo-java mongodb-indexes


    【解决方案1】:

    我会尝试使用 2 个索引

    primary_id,状态和secondary_id,状态。

    如果仍然发生超时,您可以增加查询超时值吗? - 考虑到您尝试从中读取的大型数据集。

    如果这些索引没有帮助并且期望有良好的响应时间,那么您应该查看硬件限制 - 您的硬件是否足够好(阅读 mongodb 的工作集大小)。如果性能确实是一个问题并且您的数据大小将会增长,则可以扩展服务器/硬件或查看分片。

    或 - 将状态 2 和 3 存储在单独的集合中,以在查询时减少“工作集大小”。

    【讨论】:

      猜你喜欢
      • 2018-05-11
      • 1970-01-01
      • 1970-01-01
      • 2017-10-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多