Mongodb当limit写负数去请求数据的时候会发生什么?

来源:互联网 发布:网店数据化分析的内容 编辑:程序博客网 时间:2024/04/30 14:15
在我们的mongod日志里面查到有些慢请求返回的数据条数是超过1000,问题很奇怪。我们的应用已经限制了 
if(limit>500) return ERR_LIMIT; 
这是为什么呢?

偶然尝试了在mongodb做query的时候,把limit填负数,居然请求到数据了。当limit填-100时,返回了100条记录,当limit填-1000的时候,返回了1000条记录。
在mongo的文档里面有这么说明:
numberToReturn
Limits the number of documents in the first OP_REPLY message to the query. However, the database will still establish a cursor and return the cursorID to the client if there are more results than numberToReturn. If the client driver offers ‘limit’ functionality (like the SQL LIMIT keyword), then it is up to the client driver to ensure that no more than the specified number of document are returned to the calling application. If numberToReturn is 0, the db will use the default return size. If the number is negative, then the database will return that number and close the cursor. No futher results for that query can be fetched. IfnumberToReturn is 1 the server will treat it as -1 (closing the cursor automatically).

里面最重要的一句话:If the number is negative, then the database will return that number and close the cursor.
这句话怎么理解呢?先做个实验,然后再看一下源码。

做实验:
数据库里满足某个query有33000条结果,我们假设这个数据集27000条记录的大小是4M.
(mongodb client 里面 limit batchsize的值,默认为0,分别表示取全部和不限制batchsize)
1、limit = 0 batchsize = 0
先拿100条过来,消耗完,再去数据库取。接着每次取27000条(4M)的数据量,直到取完.
2、limit = 1000 batchsize = 0
直接从数据库拿1000条
3、limit = 30000 batchsize = 0
直接去27000条(4M),消耗完继续取
4、limit = 正数   batchsize = B
每次从数据库取B条,然后不够limit的值,再去取
5、limit = -30000 batchsize = 100
直接取30000条过来,然后关闭cursor(超过4M了)
6、limit = 负数   batchsize = 任何
这个就是所谓的hard limit 啦,获取之后会直接关闭cursor。不管batchsize是多少,把limit取反,然后一次从数据全部拿过来。不会分成每4M一次了。

看源码:
mongodb/db/ops/query.h class ParsedQuery : boost::noncopyable {   ...private:   void init( const BSONObj& q ) {    ...      uassert( 10105 , "bad skip value in query", _ntoskip >= 0);      if ( _ntoreturn < 0 ) {        /* _ntoreturn greater than zero is simply a hint on             how many objects to send back per "cursor batch".            A negative number indicates a hard limit.        */         _wantMore = false;         _ntoreturn = -_ntoreturn;       }      ...  }}
也就是说,当_ntoreturn是负数的时候,就会给它取反,并且把_wantMore置成false。


总结:
1、当limit传正数的时候,根据策略分批从db里面获取数据,只有在要求的数据获取完,才会关闭cursor
2、当limit传负数的时候,一次性从数据库里面获取满足要求的所有数据,并关闭cursor,不采用内部的优化策略(即:分批获取数据,较小网络传输开销)。
3、在做mongodb相关应用的时候,要注意对limit值做检查,万一传进来一个负数,很有可能产生慢查询。
另外还要注意,当limit的值传0的时候,是要获取全部数据的,要确信是否需要这么用。


参考:
http://docs.mongodb.org/meta-driver/latest/legacy/mongodb-wire-protocol/#MongoWireProtocol-OPQUERY
http://stackoverflow.com/questions/9833941/in-a-mongodb-query-what-does-a-negative-limit-mean
0 0