草庐IT

performance - MongoDB 在计算空值时非常慢(或 {$exists : false})

coder 2023-05-05 原文

我有一个运行在具有 16GB 内存的 VPS 上的 Mongo 服务器(尽管使用磁盘的 IO 可能很慢)。

我收集了大约 3500 万条不适合主内存的记录(db.stats() 报告的 size 为 35GB, storageSize 为 14GB),但是为 totalIndexSize 报告的 1.7GB 应该很合适。

我正在查询的特定字段 bg 可以以值 true 存在或完全不存在(请不要讨论这是否是最佳数据表示 -我仍然认为 Mongo 的行为很奇怪)。该字段使用报告大小为 146MB 的非稀疏索引进行索引。

我正在使用带有默认缓存大小的 WiredTiger 存储引擎(因此它应该在 8GB 左右)。

我正在尝试计算缺少 bg 字段的记录数。

计数 true 值相当快(几秒钟):

> db.entities.find({bg: true}).count()
8300677

但是缺失值的查询非常慢(大约 5 分钟):

> db.entities.find({bg: null}).count()
27497706

在我看来,explain() 看起来不错:

> db.entities.find({bg: null}).explain()
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "testdb.entities",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "bg" : {
                "$eq" : null
            }
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "filter" : {
                "bg" : {
                    "$eq" : null
                }
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "bg" : 1
                },
                "indexName" : "bg_1",
                "isMultiKey" : false,
                "direction" : "forward",
                "indexBounds" : {
                    "bg" : [
                        "[null, null]"
                    ]
                }
            }
        },
        "rejectedPlans" : [ ]
    },
    "serverInfo" : {
        "host" : "mongo01",
        "port" : 27017,
        "version" : "3.0.3",
        "gitVersion" : "b40106b36eecd1b4407eb1ad1af6bc60593c6105"
    },
    "ok" : 1
}

但是,即使在重复调用之后,查询仍然很慢。其他不同值的计数查询很快:

> db.entities.find({bg: "foo"}).count()
0
> db.entities.find({}).count()
35798383

我觉得这种奇怪,因为我的理解是非稀疏索引中缺少的字段只是存储为null,所以带有null的count查询应该是类似于计算实际值(或者如果必须计算更多索引条目或其他东西,可能最多三倍于三倍的正值)。确实,this answer报告与涉及 null 值和 .count() 的类似查询相比,速度得到了极大的提高。我能想到的唯一区别点是 WiredTiger。

谁能解释为什么我的查询计算空值这么慢或者我可以做些什么来修复它(除了从总数中明显减去 true 计数,这会很好但不能满足我的好奇心)?

最佳答案

这是预期行为,请参阅:https://jira.mongodb.org/browse/SERVER-18653 .对我来说似乎是一个奇怪的电话,但你去吧,我敢肯定有比我更了解 MongoDB 的程序员负责。

您需要使用不同的值来表示 null。我想这将取决于您使用该字段的目的。在我的情况下,它是一个外部引用,所以我将开始使用 false 来表示 null。如果您使用它来存储 bool 值,那么您可能需要使用“null”、-1、0 等。

关于performance - MongoDB 在计算空值时非常慢(或 {$exists : false}),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30319805/

有关performance - MongoDB 在计算空值时非常慢(或 {$exists : false})的更多相关文章

  1. ruby - 默认情况下使选项为 false - 2

    这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

  2. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  3. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  4. ruby - 为什么 Integer.respond_to?( :even? ) 返回 false? - 2

    我一直在研究RubyKoans,我发现about_open_classes.rbkoan很有趣。特别是他们修改Integer#even?方法的最后一个测试。我想尝试一下这个概念,所以我打开了Irb并尝试运行Integer.respond_to?(:even?),但令我惊讶的是我得到了错误。然后我尝试了Fixnum.respond_to?(:even?)并得到了错误。我还尝试了Integer.respond_to?(:respond_to?)并得到了true,当我执行2.even?时,我也得到了true。我不知道发生了什么。谁能告诉我缺少什么? 最佳答案

  5. ruby-on-rails - 使用 HTTParty 的非常基本的 Rails 4.1 API 调用 - 2

    Rails相对较新。我正在尝试调用一个API,它应该向我返回一个唯一的URL。我的应用程序中捆绑了HTTParty。我已经创建了一个UniqueNumberController,并且我已经阅读了几个HTTParty指南,直到我想要什么,但也许我只是有点迷路,真的不知道该怎么做。基本上,我需要做的就是调用API,获取它返回的URL,然后将该URL插入到用户的数据库中。谁能给我指出正确的方向或与我分享一些代码? 最佳答案 假设API为JSON格式并返回如下数据:{"url":"http://example.com/unique-url"

  6. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  7. ruby - 使用 Ruby,计算 n x m 数组的每一列中有多少个 true 的简单方法是什么? - 2

    给定一个nxmbool数组:[[true,true,false],[false,true,true],[false,true,true]]有什么简单的方法可以返回“该列中有多少个true?”结果应该是[1,3,2] 最佳答案 使用转置得到一个数组,其中每个子数组代表一列,然后将每一列映射到其中的true数:arr.transpose.map{|subarr|subarr.count(true)}这是一个带有inject的版本,应该在1.8.6上运行,没有任何依赖:arr.transpose.map{|subarr|subarr.in

  8. ruby - 你会如何在 Ruby 中表达成语 "with this object, if it exists, do this"? - 2

    在Ruby(尤其是Rails)中,您经常需要检查某物是否存在,然后对其执行操作,例如:if@objects.any?puts"Wehavetheseobjects:"@objects.each{|o|puts"hello:#{o}"end这是最短的,一切都很好,但是如果你有@objects.some_association.something.hit_database.process而不是@objects呢?我将不得不在if表达式中重复两次,如果我不知道实现细节并且方法调用很昂贵怎么办?显而易见的选择是创建一个变量,然后测试它,然后处理它,但是你必须想出一个变量名(呃),它也会在内存中

  9. ruby-on-rails - Resque - 类的未定义方法 'perform' - 2

    我目前对后台队列不太满意。我正在尝试让Resque工作。我已经安装了redis和Resquegem。Redis正在运行。一个worker正在运行(rakeresque:workQUEUE=simple)。使用Web界面,我可以看到工作人员正在运行并等待工作。当我运行“rakeget_updates”时,作业已排队但失败了。我已经用defself.perform和defperform试过了。发条.raketask:get_updates=>:environmentdoResque.enqueue(GetUpdates)end类文件(app/workers/get_updates.rb)c

  10. arrays - 计算数组中的匹配元素 - 2

    给定两个大小相等的数组,如何找到不考虑位置的匹配元素的数量?例如:[0,0,5]和[0,5,5]将返回2的匹配项,因为有一个0和一个5共同;[1,0,0,3]和[0,0,1,4]将返回3的匹配项,因为0有两场,1有一场;[1,2,2,3]和[1,2,3,4]将返回3的匹配项。我尝试了很多想法,但它们都变得相当粗糙和令人费解。我猜想有一些不错的Ruby习惯用法,或者可能是一个正则表达式,可以很好地回答这个解决方案。 最佳答案 您可以使用count完成它:a.count{|e|index=b.index(e)andb.delete_at

随机推荐