先用下面的方式写入1000条数据:
for(var i=0;i<1000;i++)db.test.insert({_id:i,a:‘1’})
然后你分别使用下面命令按_id和natural排序取出前一条结果: db.test.find().sort({_id:1}).limit(1) db.test.find().sort({natural:1}).limit(1)
你得到的结果会是一样的。
这时候你进行一次update操作,将第一条记录的长度变长:
db.test.update({_id:1},{a:‘12’})
再通过上面两种不同的排序方式取第一条,你会发现取到的结果还是一样的。
然后你再将第一条记录变长:
db.test.update({_id:1},{a:‘123’})
再通过上面两种不同的排序方式取第一条,这时候你会看到,通过_id排序查到的还是原来那一条,而通过$natural查到的已经变成了第二条。这是什么原因?
_id是按数据插入时间排序,而natural是按数据在磁盘上的组织顺序排序。 当你执行insert操作的时候,通过Object.bsonsize(db.test.findOne());命令我们可以知道每条记录的长度为31 当你把a的值update时,a的长度在逐步增加,分别为31、32、33.因为MongoDB在记录长度变化后,发现当前记录所在空间后面没有空余的空间可供其变长。那么这条记录就会被删除然后移动到数据集的最后,所以导致natural最后排序的结果和之前不一样。因为MongoDB每一条记录都会做4字节的内存对齐。所以在你刚插入的时候,记录长度虽然只有31字节,但是MongoDB会为它分配32字节(8*4)的空间。这时候在其末尾就有一字节的空闲,当你增长一字节的时候,这一字节的空闲正好可以用上。所以就不需要移动位置了。而第二次从32字节变成33字节,原有的空间已经不能装下了,所以会造成数据的移动。