【问题标题】:Fast NOSQL queries when dealing with large datasets处理大型数据集时的快速 NOSQL 查询
【发布时间】:2013-12-29 05:31:40
【问题描述】:

我目前正试图说服管理层我们应该将一些数据从 MS SQL 转移到 NOSQL(可能是 MongoDB)。具体来说,我要转移的是我们的 WebStats 系统。目前我们在一个表中大约有 1.5 亿行,并且这个数据集一直在增长(我们存储了一年的统计数据。)

作为测试,我已经运行了 1.5 亿次以下查询:

db.test.insert({ SiteId:1, PageUrl:"/home/", Impressions:1, Date: new Date(), IsCrawler:假,LanguageId:2057,ClientIpAddress:“1.2.3.4”,DateTime:新日期( ), ReferralUrl: "http://www.google.com", UniqueUserGuid:1, BrowserName:"IE", Brow serVersion:11, BrowserAgent:"blah", IsAbcValid:true, hasChecked:true, 连接 速度:1,国家:“英国”,地区:“中部地区”,城市:“考文垂”})

然后我执行一次:

db.test.insert({ SiteId:1, PageUrl:"/home/", Impressions:1, Date: new Date(), IsCrawler:假,LanguageId:2057,ClientIpAddress:“1.2.3.4”,DateTime:新日期( ), ReferralUrl: "http://www.google.com", UniqueUserGuid:1, BrowserName:"IE", Brow serVersion:11, BrowserAgent:"blah", IsAbcValid:true, hasChecked:true, 连接 速度:1,国家:“US”,地区:“纽约”,城市:“纽约”})

接着是:

db.test.ensureIndex( { "PageUrl": 1, "Date": 1, "ClientIpAddress": 1 } )

索引完成后,我运行了以下搜索:

db.test.find({Country:/S/})

它最终找到了我添加的美国文档,但它比在 MS SQL 中花费的时间更长。我是否错误地索引了这个?我基本上只是试图展示可能的性能提升,所以如果有人能指出一个处理非常大数据集的示例,那么我很乐意使用它。

谢谢,

【问题讨论】:

    标签: mongodb nosql


    【解决方案1】:

    您必须按国家/地区编制索引才能按国家/地区进行搜索。如果您不想使用这样的正则表达式,则索引通常不会有帮助,除非它位于字符串的前面。

    db.test.find({Country:{$regex:"^US"}})
    

    【讨论】:

      【解决方案2】:

      如果您在 Country 上运行查询,您应该创建一个类似 db.test.ensureIndex({Country:1}) 的索引。

      【讨论】:

      • 对不起,我是个白痴。我打算查询 PageURL 然后改变主意。我今天早上没有。
      • 这很好,但不会对问题中的查询产生太大影响:)
      【解决方案3】:

      低效查询

      问题中的索引位于错误的字段中,但假设已更正,查询仍然会很慢。

      来自the docs

      $regex 只能在正则表达式在字符串的开头(即 ^)有一个锚点并且是区分大小写的匹配时才能有效地使用索引。

      这个查询:

      db.test.find({Country:/S/})

      不以固定字符串开头,因此无法有效地使用索引。使用explain,可以调查这种正则表达式查询的影响,例如:

      > db.test.find({Country:/S/}).explain();
      {
      "cursor" : "BtreeCursor Country_1 multi",
      "isMultiKey" : false,
      "n" : 1,
      "nscannedObjects" : 1,
      "nscanned" : 150000000,
      "nscannedObjectsAllPlans" : 1,
      "nscannedAllPlans" : 2,
      "scanAndOrder" : false,
      "indexOnly" : false,
      "nYields" : 0,
      "nChunkSkips" : 0,
      "millis" : 0,
      "indexBounds" : {
          "Country" : [
              [
                  "",
                  {
                      
                  }
              ],
              [
                  /S/,
                  /S/
              ]
          ]
      },
      "server" : "host.local:27017"
      }
      

      注意nscanned 的值是the total number of documents or index entries scanned during the database operation。使用了索引,但无论匹配对象的数量如何,都需要扫描整个索引。

      更好的办法是确定该字段的哪些值可以匹配,并明确搜索这些值:

      > db.test.find({Country:['US']}).explain();
      > #                      ^ derive this list
      {
      "cursor" : "BtreeCursor Country_1 multi",
      "isMultiKey" : false,
      "n" : 0,
      "nscannedObjects" : 1,
      "nscanned" : 1,
      "nscannedObjectsAllPlans" : 1,
      "nscannedAllPlans" : 1,
      "scanAndOrder" : false,
      "indexOnly" : false,
      "nYields" : 0,
      "nChunkSkips" : 0,
      "millis" : 0,
      "indexBounds" : {
          "Country" : [
              [
                  "US",
                  "US"
              ],
              [
                  [
                      "US"
                  ],
                  [
                      "US"
                  ]
              ]
          ]
      },
      "server" : "host.local:27017"
      }
      

      请注意,在这种情况下,nscanned 的值与 nscannedObjects 相同 - 表明索引的有效使用和可能快得多的查询。

      【讨论】:

      • 具体来说,未锚定的 $regex 的警告是它不能有效地使用索引。这是索引扫描而不是集合扫描。扫描 1.5 亿个索引条目仍然不如扫描 1.5 亿个文档密集(尽管肯定不理想)。
      • @Stennie 警告肯定是准确的,但未锚定的查询根本不会使用索引,除非有提示。
      • 我相信你错了。你测试过这个吗?我确保在未锚定的正则表达式上的 Country 和 explain() 上的索引显示使用的索引:“BtreeCursor Country_1 multi”。我签入了 2.0.9、2.2.6 和 2.4.8 .. 都报告相同。 nscanned(索引条目)随着集合的大小而增加,但 nscannedobjects 不会。
      • You're right 太棒了——我很确定早期版本不是这种情况,the docs 仍然是Queries that specify regular expressions [...] cannot use an index with one exception. Queries that specify regular expression with anchors at the beginning of a string can use an index.。无论如何,感谢您的澄清。
      • 感谢您指向文档参考;将得到澄清。仅供参考,$regex command 文档有更准确的解释。出于好奇,我尝试使用 MongoDB 1.8.5(可追溯到 2011 年 3 月),但它仍然具有相同的行为:)。虽然对这些查询使用索引很有帮助(至少比没有索引的集合扫描更有帮助),但如果有人想经常运行这类查询,则绝对推荐使用不同的数据模型方法。跨度>
      猜你喜欢
      • 1970-01-01
      • 2011-09-30
      • 2018-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      相关资源
      最近更新 更多