代码之家  ›  专栏  ›  技术社区  ›  Lazar Ljubenović

为什么增加指数会恶化绩效?

  •  1
  • Lazar Ljubenović  · 技术社区  · 6 年前

    我正在评估以下查询的性能。

    db.products_old.find({ regularPrice: { $lte: 200 } })
    

    这个集合有超过一百万个文档,总计约0.15GB。


    无索引

    这是意料之中的。必须进行全列扫描

    "executionTimeMillis" : 1019,
    

    "winningPlan" : {
        "stage" : "COLLSCAN",
        "filter" : {
            "regularPrice" : {
                "$lte" : 200
            }
        },
        "direction" : "forward"
    },
    

    指数{regularPrice:1}

    "executionTimeMillis" : 2842,
    

    "winningPlan" : {
        "stage" : "FETCH",
        "inputStage" : {
            "stage" : "IXSCAN",
            "keyPattern" : {
                "regularPrice" : 1
            },
            "indexName" : "regularPrice_1",
            "isMultiKey" : false,
            "multiKeyPaths" : {
                "regularPrice" : [ ]
            },
            "isUnique" : false,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 2,
            "direction" : "forward",
            "indexBounds" : {
                "regularPrice" : [
                    "[-inf.0, 200.0]"
                ]
            }
        }
    },
    

    现在它使用索引,但执行时间明显变差了。

    为什么蒙哥不用 COLLSCAN 相反 rejectedPlans 是空的,这意味着没有考虑其他计划。为什么?


    Here's allPlansExecution 输出。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Pritilender    6 年前

    在做的时候 COLLSCAN ,MongoDB正在从存储驱动器读取匹配的文档,并将其存储在RAM中以供以后直接使用。另一方面, IXSCAN 读取存储索引数据的索引以及指向其在存储驱动器上位置的指针。( Here's a nice visualisation

    集合中有很多文档,但索引中也有很多匹配的文档。存储在存储驱动器上的数据并不是以最佳方式从中读取的(就像在索引中一样),因此 返回为您的查询找到的220k+个文档的指针, FETCH 需要以随机访问方式从存储驱动器读取220k+次。这很慢。另一方面,我认为 科尔斯坎 是进行顺序读取,可能是逐页读取,比 阅读。

    舞台。如果您想继续使用这个索引并且有更快的查询执行时间,那么使用 .select('-_id regularPrice') 这只会增加一个快速 PROJECTION _id ,然后添加索引 {regularPrice: 1, _id: 1} .

    关于这个部分 为什么? Mongo是否使用索引,即使它知道集合扫描更快:我认为,如果它看到索引,它将使用它。但你可以 force it to use collection scan 通过使用 hint {natural: 1} 传递给它。