我有一个网页,它使用 MongoDB 来存储和检索各种测量值。突然,在某些时候,我的网页变得如此缓慢以至于无法使用。原来,我的数据库是罪魁祸首。
我搜索并没有找到任何解决我的问题的方法,我深表歉意,因为我对 MongoDB 还很陌生,目前正在抓狂。
我使用的 MongoDB 版本是 2.4.6,在具有 20GB RAM 的 VM 机器上运行 Ubuntu 服务器 12.04。没有设置副本或分片。
首先,我将分析级别设置为 2,它显示了最慢的查询:
db.system.profile.find().sort({"millis":-1}).limit(1).pretty()
{
"op" : "query",
"ns" : "station.measurement",
"query" : {
"$query" : {
"e" : {
"$gte" : 0
},
"id" : "180"
},
"$orderby" : {
"t" : -1
}
},
"ntoreturn" : 1,
"ntoskip" : 0,
"nscanned" : 3295221,
"keyUpdates" : 0,
"numYield" : 6,
"lockStats" : {
"timeLockedMicros" : {
"r" : NumberLong(12184722),
"w" : NumberLong(0)
},
"timeAcquiringMicros" : {
"r" : NumberLong(5636351),
"w" : NumberLong(5)
}
},
"nreturned" : 0,
"responseLength" : 20,
"millis" : 6549,
"ts" : ISODate("2015-03-16T08:57:07.772Z"),
"client" : "127.0.0.1",
"allUsers" : [ ],
"user" : ""
}
我用 .explain() 运行了那个特定的查询,看起来它应该使用索引,但它需要的时间太长。我还在另一台性能较弱的服务器上运行了相同的查询,并在一秒钟内像冠军一样输出结果。
> db.measurement.find({"id":"180", "e":{$gte:0}}).sort({"t":-1}).explain()
{
"cursor" : "BtreeCursor id_1_t_-1_e_1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 0,
"nscanned" : 660385,
"nscannedObjectsAllPlans" : 1981098,
"nscannedAllPlans" : 3301849,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 7,
"nChunkSkips" : 0,
"millis" : 7243,
"indexBounds" : {
"id" : [
[
"180",
"180"
]
],
"t" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"e" : [
[
0,
1.7976931348623157e+308
]
]
},
"server" : "station:27017"
}
接下来,我查看了 measurement 集合的索引,我觉得它很好:
> db.measurement.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "station.measurement",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"t" : 1
},
"ns" : "station.measurement",
"name" : "t_1"
},
{
"v" : 1,
"key" : {
"id" : 1,
"d" : 1,
"_id" : -1
},
"ns" : "station.measurement",
"name" : "id_1_d_1__id_-1"
},
{
"v" : 1,
"key" : {
"id" : 1,
"t" : -1,
"e" : 1
},
"ns" : "station.measurement",
"name" : "id_1_t_-1_e_1"
},
{
"v" : 1,
"key" : {
"id" : 1,
"t" : -1,
"e" : -1
},
"ns" : "station.measurement",
"name" : "id_1_t_-1_e_-1"
}
]
这也是我收藏的其余信息:
> db.measurement.stats()
{
"ns" : "station.measurement",
"count" : 157835456,
"size" : 22377799512,
"avgObjSize" : 141.77929395027692,
"storageSize" : 26476834672,
"numExtents" : 33,
"nindexes" : 5,
"lastExtentSize" : 2146426864,
"paddingFactor" : 1.0000000000028617,
"systemFlags" : 0,
"userFlags" : 0,
"totalIndexSize" : 30996614096,
"indexSizes" : {
"_id_" : 6104250656,
"t_1" : 3971369360,
"id_1_d_1__id_-1" : 8397896640,
"id_1_t_-1_e_1" : 6261548720,
"id_1_t_-1_e_-1" : 6261548720
},
"ok" : 1
}
我尝试添加新索引,修复整个数据库,重新索引。我究竟做错了什么?我非常感谢任何帮助,因为我拼命地用完了想法。
更新 1:
我按照 Neil Lunn 的建议添加了两个索引,其中一些查询要快很多:
{
"v" : 1,
"key" : {
"id" : 1,
"e" : 1,
"t" : -1
},
"ns" : "station.measurement",
"name" : "id_1_e_1_t_-1",
"background" : true
},
{
"v" : 1,
"key" : {
"id" : 1,
"e" : -1,
"t" : -1
},
"ns" : "station.measurement",
"name" : "id_1_e_-1_t_-1",
"background" : true
}
我得到的结果很有趣(不确定它们是否相关)
接下来的两个查询只有“id”不同。请注意,每个查询使用不同的索引,为什么?我应该删除旧的吗?
> db.measurement.find({"id":"119", "e":{$gte:0}}).sort({"t":-1}).explain()
{
"cursor" : "BtreeCursor id_1_t_-1_e_1",
"isMultiKey" : false,
"n" : 840747,
"nscannedObjects" : 840747,
"nscanned" : 1047044,
"nscannedObjectsAllPlans" : 1056722,
"nscannedAllPlans" : 1311344,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 4,
"nChunkSkips" : 0,
"millis" : 3730,
"indexBounds" : {
"id" : [
[
"119",
"119"
]
],
"t" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"e" : [
[
0,
1.7976931348623157e+308
]
]
},
"server" : "station:27017"
}
> db.measurement.find({"id":"180", "e":{$gte:0}}).sort({"t":-1}).explain()
{
"cursor" : "BtreeCursor id_1_e_1_t_-1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 0,
"nscanned" : 0,
"nscannedObjectsAllPlans" : 0,
"nscannedAllPlans" : 45,
"scanAndOrder" : true,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"id" : [
[
"180",
"180"
]
],
"e" : [
[
0,
1.7976931348623157e+308
]
],
"t" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
]
},
"server" : "station:27017"
}
问题可能出在其他地方吗?什么会导致这种突然的“呆滞”?我还有其他几个集合,查询也突然变慢了。
哦,还有一件事。在我拥有的另一台服务器上,索引与添加新索引之前的索引相同。是的,集合有点小,但速度快了好几倍。
最佳答案
那么这里的重点是索引和查询排序选择。
如果您查看之前 .explain() 的输出,您会发现表达式中的“t”元素有一个“最小/最大”范围。通过“将其移至评估的末尾”,您可以允许对整体表达式更重要的其他过滤元素(确定不太可能的“e”匹配成为主要因素,然后在基本上“一切”中扫描“t” .
这有点 DBA,但在 NoSQL 世界中,我确实相信这会成为程序员的问题。
为了获得最有效的扫描,您基本上需要沿着选定的键构建“最短匹配路径”。这就是为什么更改后的结果执行得更快的原因。
关于MongoDB:慢查询,即使有索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29095010/
我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.
我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr
我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r
我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时
我发现自己需要这个。假设cart是一个包含用户列表的模型。defindex_of_itemcart.users.each_with_indexdo|u,i|ifu==current_userreturniendend获取此类关联索引的更简单方法是什么? 最佳答案 indexArray上的方法与您的index_of_item方法相同,例如cart.users.index(current_user)返回数组中第一个对象的索引==给obj。如果未找到匹配项,则返回nil。 关于ruby-on-
我花了几天时间尝试安装ruby1.9.2并让它与gems一起工作:-/我最终放弃了我的MacOSX10.6机器,下面是我的Ubuntu机器上的当前状态。任何建议将不胜感激!#rubytest.rb:29:in`require':nosuchfiletoload--mongo(LoadError)from:29:in`require'fromtest.rb:1:in`'#cattest.rbrequire'mongo'db=Mongo::Connection.new.db("mydb")#gemwhichmongo/usr/local/rvm/gems/ruby-1.9.2-p0/g
因此,当我遵循MichaelHartl的RubyonRails教程时,我注意到在用户表中,我们为:email属性添加了一个唯一索引,以提高find的效率方法,因此它不会逐行搜索。到目前为止,我们一直在根据情况使用find_by_email和find_by_id进行搜索。然而,我们从未为:id属性设置索引。:id是否自动索引,因为它在默认情况下是唯一的并且本质上是顺序的?或者情况并非如此,我应该为:id搜索添加索引吗? 最佳答案 大多数数据库(包括sqlite,这是RoR中的默认数据库)会自动索引主键,对于RailsMigration
我在Rails上使用带有ruby的solr。一切正常,我只需要知道是否有任何现有代码来清理用户输入,比如以?开头的查询。或* 最佳答案 我不知道执行此操作的任何代码,但理论上可以通过查看parsingcodeinLucene来完成并搜索thrownewParseException(只有16个匹配!)。在实践中,我认为您最好只捕获代码中的任何solr异常并显示“无效查询”消息或类似信息。编辑:这里有几个“sanitizer”:http://pivotallabs.com/users/zach/blog/articles/937-s
我正在为锦标赛开发一个Rails应用程序。我在这个查询中使用了三个模型:classPlayertruehas_and_belongs_to_many:tournamentsclassTournament:destroyclassPlayerMatch"Player",:foreign_key=>"player_one"belongs_to:player_two,:class_name=>"Player",:foreign_key=>"player_two"在tournaments_controller的显示操作中,我调用以下查询:Tournament.where(:id=>params
我想用sunspot重现以下原始solr查询q=exact_term_text:fooORterm_textv:foo*ORalternate_text:bar*但我无法通过标准的太阳黑子界面理解这是否可能以及如何实现,因为看起来:fulltext方法似乎不接受多个文本/搜索字段参数我不知道将什么参数作为第一个参数传递给fulltext,就好像我通过了"foo"或"bar"结果不匹配如果我传递一个空参数,我得到一个q=*:*范围过滤器(例如with(:term).starting_with('foo*')(顾名思义)作为过滤器查询应用,因此不参与评分。似乎可以手动编写字符串(或者可能使