Mongoid winningPlan 不使用复合索引

Mongoid winningPlan does not use compound index

我有一个复合索引如下。

  index({ account_id: 1, is_private: 1, visible_in_list: 1, sent_at: -1, user_id: 1, status: 1, type: 1, 'tracking.last_opened_at' => -1 }, {name: 'email_page_index'})

然后我用这些确切的字段进行查询,

selector:
{"account_id"=>BSON::ObjectId('id'), "is_private"=>false, "visible_in_list"=>{:$in=>[true, false]}, "status"=>{:$in=>["ok", "queued", "processing", "failed"]}, "sent_at"=>{"$lte"=>2021-03-22 15:29:18 UTC}, "tracking.last_opened_at"=>{"$gt"=>1921-03-22 15:29:18 UTC}, "user_id"=>BSON::ObjectId('id')}
options:  {:sort=>{"tracking.last_opened_at"=>-1}}

获胜方案如下

"inputStage": {
    "stage": "SORT_KEY_GENERATOR",
    "inputStage": {
      "stage": "FETCH",
      "filter": {
        "$and": [
          {
            "account_id": {
              "$eq": {
                "$oid": "objectid"
              }
            }
          },
          {
            "is_private": {
              "$eq": false
            }
          },
          {
            "sent_at": {
              "$lte": "2021-03-22T14:06:10.000Z"
            }
          },
          {
            "tracking.last_opened_at": {
              "$gt": "1921-03-22T14:06:10.716Z"
            }
          },
          {
            "status": {
              "$in": [
                "failed",
                "ok",
                "processing",
                "queued"
              ]
            }
          },
          {
            "visible_in_list": {
              "$in": [
                false,
                true
              ]
            }
          }
        ]
      },
      "inputStage": {
        "stage": "IXSCAN",
        "keyPattern": {
          "user_id": 1
        },
        "indexName": "user_id_1",
        "isMultiKey": false,
        "multiKeyPaths": {
          "user_id": []
        },.....

而被拒绝的计划有复合索引和形式如下

"rejectedPlans": [
  {
    "stage": "FETCH",
    "inputStage": {
      "stage": "SORT",
      "sortPattern": {
        "tracking.last_opened_at": -1
      },
      "inputStage": {
        "stage": "SORT_KEY_GENERATOR",
        "inputStage": {
          "stage": "IXSCAN",
          "keyPattern": {
            "account_id": 1,
            "is_private": 1,
            "visible_in_list": 1,
            "sent_at": -1,
            "user_id": 1,
            "status": 1,
            "type": 1,
            "tracking.last_opened_at": -1
          },
          "indexName": "email_page_index",
          "isMultiKey": false,
          "multiKeyPaths": {
            "account_id": [],
            "is_private": [],
            "visible_in_list": [],
            "sent_at": [],
            "user_id": [],
            "status": [],
            "type": [],
            "tracking.last_opened_at": []
          },
          "isUnique": false,

问题是winningPlan比较慢,mongoid选择复合索引不是更好吗?有没有办法强迫它? 另外,如何查看每个单独 STAGE 的执行时间?

我正在 post 获取一些有助于解决性能问题和使用适当索引的信息。请注意,这可能不是解决方案(该问题有待讨论)。

...Also, how can I see the execution time for each separate STAGE?

为此,使用 explain with the executionStats verbosity mode.

生成查询计划

The problem is that the winningPlan is slow, wouldn't be better if mongoid choose the compound index? Is there a way to force it?

因为 posted 计划显示 "stage": "SORT_KEY_GENERATOR",这意味着 sort 操作正在内存中执行(即不使用索引排序)。这将是性能缓慢的原因之一(或主要原因)。那么,如何让查询和排序使用索引呢?

单个复合索引可用于具有过滤+排序操作的查询。那将是一个有效的索引和查询。但是,它要求以某种方式定义复合索引——需要遵循一些规则。请参阅 Sort and Non-prefix Subset of an Index 上的此主题 - post 中的情况也是如此。我引用文档中的示例进行说明:

假设有一个复合索引:{ a: 1, b: 1, c: 1, d: 1 } 并且,所有字段都用于带有过滤器+排序的查询中。理想的查询是,有一个过滤器+排序如下:

db.test.find( { a: "val1", b: "val2", c: 1949 } ).sort( { d: 1 })

请注意,查询过滤器具有三个具有 equality 条件的字段(没有 $gt$lt 等)。然后查询的排序有索引的最后一个字段d。这是索引将用于查询筛选器和排序操作的理想情况。

在您的情况下,这不能从 posted 查询中应用。因此,要找到解决方案,您可能必须定义一个新索引,以便利用规则 Sort and Non-prefix Subset of an Index.

可能吗?这取决于您的应用程序和用例。我有这样的想法,它可能会有所帮助。像下面这样创建一个复合索引,看看它是如何工作的:

account_id: 1, 
is_private: 1
visible_in_list: 1,
status: 1,
user_id: 1, 
'tracking.last_opened_at': -1

我认为在查询过滤器中使用条件 "tracking.last_opened_at"=>{"$gt"=>1921-03-22 15:29:18 UTC}, 可能对索引的使用没有帮助。

此外,包括一些详细信息,例如 MongoDB 服务器的版本、集合的大小和一些平台详细信息。通常,查询性能取决于许多因素,包括索引、RAM 内存、数据的大小和类型以及对数据的操作类型。


ESR 规则: 当对具有多个过滤条件和排序的查询使用复合索引时,有时 Equality Sort Range 规则对于优化查询很有用。请参阅以下 post 这种情况: