MongoDB 查询 lte 比 gte 快

Posted

技术标签:

【中文标题】MongoDB 查询 lte 比 gte 快【英文标题】:MongoDB query faster lte than gte 【发布时间】:2016-11-17 17:53:02 【问题描述】:

这个问题快把我逼疯了。我有一个收藏:

var ethTransactionSchema = new mongoose.Schema(
    blockNumber: Number,
    blockHash: String,
    hash: String,
    transactionIndex: Number,
    from: String,
    to: String,
    value: String
);
ethTransactionSchema.index( hash: 1 ,  unique: true );
ethTransactionSchema.index( from: 1 );
ethTransactionSchema.index( to: 1 );
ethTransactionSchema.index( blockNumber: 1, transactionIndex: 1 );

ethTransactionSchema.index( from: 1, to: 1, blockNumber: 1, transactionIndex: 1 );
ethTransactionSchema.index( from: 1, blockNumber: 1, transactionIndex: 1);

ethTransactionSchema.index( to: 1, blockNumber: 1, transactionIndex: 1 );
ethTransactionSchema.index( to: 1, blockNumber: 1 );

ethTransactionSchema.index( from: 1, blockNumber: 1 );
ethTransactionSchema.index( from: 1, to: 1, blockNumber: 1 );
ethTransactionSchema.index( blockNumber: 1 );
ethTransactionSchema.index( transactionIndex: 1 );

ethTransactionSchema.index( blockNumber: -1 );
ethTransactionSchema.index( to: 1, blockNumber: -1 );
ethTransactionSchema.index( from: 1, blockNumber: -1 );
ethTransactionSchema.index( from: 1, to: 1, blockNumber: -1 );

ethTransactionSchema.index( from: 1, to: 1, blockNumber: -1, transactionIndex: -1 );
ethTransactionSchema.index( from: 1, blockNumber: -1, transactionIndex: -1 );
ethTransactionSchema.index( to: 1, blockNumber: -1, transactionIndex: -1 );

当我执行这个查询时:

  find("$and":[ "$or": [ "from":"0x120a270bbc009644e35f0bb6ab13f95b8199c4ad",
                      "to":"0x120a270bbc009644e35f0bb6ab13f95b8199c4ad"
                    ],
            "blockNumber":"$gte":1289597
          ]
  ).sort( blockNumber: -1, transactionIndex: -1 )

它比使用 lte 的相同查询多 3 到 6 倍:

  find("$and":[ "$or": [ "from":"0x120a270bbc009644e35f0bb6ab13f95b8199c4ad",
                      "to":"0x120a270bbc009644e35f0bb6ab13f95b8199c4ad"
                    ],
            "blockNumber":"$lte":1289597
          ]
  ).sort( blockNumber: -1, transactionIndex: -1 )

您可以看到我已经尝试了很多索引组合,只是为了测试我是否可以使用强力解决问题,但我可能遗漏了一些东西。出于这个原因,我即将放弃 MongoDB。 快速查询平均需要 56 毫秒,慢速查询平均需要 167 毫秒。

谁能找出问题所在或帮我找到它?

【问题讨论】:

【参考方案1】:

您正在尝试执行的操作存在一些问题:

    $or 查询使用不同的索引

    要使$or 查询能够使用索引,$or 查询的所有 项必须具有索引。否则,查询将是集合扫描。这在https://docs.mongodb.com/manual/reference/operator/query/or/#or-clauses-and-indexes中有描述

    集合中的索引过多

    集合中的索引过多会以多种方式影响性能,例如,插入性能会受到影响,因为您将一个插入操作转换为多个(即为集合插入一个,为您的每个索引添加一个额外的插入)收藏)。太多看起来相似的索引也对查询计划器不利,因为它需要从许多相似的索引中选择一个索引,而关于哪个索引性能更高的信息很少。

    检查mongo shell 中的explain() 输出

    mongo shell 中的explain() 输出是发现查询将使用哪个索引的最佳工具。通常,您希望避免任何COLLSCAN 阶段(这意味着收集扫描)和SORT_KEY_GENERATOR 阶段(这意味着 MongoDB 正在使用限制为 32MB 的内存排序,请参阅https://docs.mongodb.com/manual/tutorial/sort-results-with-indexes/)。详情请见Explain Results。

您可能想查看这些有关索引和查询性能的相关页面:

Analyze Query Performance Use Indexes to Sort Query Results Indexing Strategies

话虽如此,我使用您的示例快速检查了mongo shell (MongoDB 3.2.8)。您可以尝试在您的集合中添加这两个索引:

blockNumber:1,transactionIndex:1,from:1
blockNumber:1,transactionIndex:1,to:1

并且删除集合中的所有其他索引。这两个索引应该能够在您的两个示例查询中使用。

【讨论】:

使用这些索引效果更差。我认为问题在于某些查询返回大量文档并且排序需要时间。我真的不明白解释如何帮助我,它看起来像汇编语言。如果结果是 67000,那么排序很慢。我曾经使用 Cassandra,您可以在其中指定表的默认顺序,这在您需要始终以特定顺序检索结果时非常有用。看起来 Mongo 缺少我需要的这个功能。

以上是关于MongoDB 查询 lte 比 gte 快的主要内容,如果未能解决你的问题,请参考以下文章

$match 与 $gte 和 $lte 不适用于 mongodb 中的数组? [复制]

$match 与 $gte 和 $lte 不适用于 mongodb 中的数组? [复制]

[转]mongodb 查询条件:关系运算符"$lt", "$lte", "$gt", "$gte", "$ne

MongoDB $关键字 关系比较符号 $lt $lte $gt $gte $ne

$gte 和 $lte 在 Mongoose/MongoDB 中没有按预期工作

包含greaterThanEqual(gte)或lessThanEqual(lte)的Squeryl查询给出错误/无结果