mongodb 中的"坑"系列 --- 单个文档16M大小限制

   习惯了使用mongodb中文档(document)存储方式, 可以灵活的将大量数据存入一个集合中的一条文档中, 这样可以减少大量的数据冗余, 不会出现关系性数据库, 如myslq中表的某一列的数据冗余. 不过这样存储虽好, 但其实也会存在一定的问题, 也就是mongodb中的大小限制, 即单个文档大小不能超过16M. 


    对遇到过这个问题的人来说, 这个16M的'概念'很好理解, 而对于还未意识到这个问题的人来说, 这个'坑' 可能会让你花时间都难以发现, 因为这又要牵扯到mongodb的另一个存储机制 ---- 无返回码. 在 < mongodb 权威指南> 一书中, 作者称之为离弦之箭. 什么意思呢, 就是mongodb的插入,删除等操作, 客户端向数据库发出请求之后, 是不需要等待数据库返回操作是否成功的返回结果. 这也是mongodb插入,更新等操作速度快的原因. 这就导致, 当单个文件超过16M之后, 程序并不会报错, 但此时, 数据已经无法插入数据库了.

上代码说明问题:

__author__ = 'ray'

import pymongo
import codecs

def mongo_test():

    fin = codecs.open('test_data.txt', 'r', encoding='UTF-8')   # test_data是一个测试文件, 文件大小为1.1M
    count = 0  
    test.insert({'name': 'test', 'max': 0})   
    line = fin.readline()
    try:
        while count < 20:
            test.update({'name': 'test'}, {'$set': {str(count): line}})   # 循环中每次插入1.1M的数据
            test.update({'name': 'test'}, {'$inc': {'max': 1}}, True)    
            count += 1
    except Exception as e:
        print count, e
    fin.close()


if __name__ == '__main__':
    client = pymongo.Connection('localhost', 27017)
    conn = client.db_wallpaper
    test = conn.test
    mongo_test()
程序输出结果为: 
/usr/bin/python2.7 /home/ray/test/mongo_test.py
Process finished with exit code 0

程序并无异常, 此时查看数据库结果如下:

mongodb 中的

其实只插入了14条记录, 这种隐形的错误很难被发现. 


有一种策略可以及时发现这个错误, 那就是使用安全验证, 代码很简单, 把

client = pymongo.Connection('localhost', 27017)  ==>> client = pymongo.Connection('localhost', 27017,safe=True)

这样就会有安全验证, 每一次插入会等待上一次的返回结果, 后果就是牺牲mongodb的操作性能. 更新后的结果如下:

mongodb 中的

而在数据库中, max的值显示为15, 也就是后续的操作就终止了. 


===========================分割线==================================

 很多使用了mongodb的程序员会对此表示不满, 认为这样的设计非常不方便, 因为我们早已经进入了用G, T来衡量数据的时代, 这16M能干什么.  不过按照mongodb的设计思路来看, 这样的限制其实是有助于我们更改不良的数据库结构设计, 因为笔者在shell中做查询时, 面对16M的文档, 查询起来相当慢, 这样的速度是不能够忍受的. 

解决办法:

1: 更改数据表结构, 避免单个文档超过16M, 将数据分开存储, 反正mongodb也比较适合用冗余换取效率. 不妨在同一个集合中多建立几个文档, 分开存储信息

2: 使用GridFS存储大数据量信息, 具体怎么做, 下次再说.


如有问题, 欢迎讨论指正.

你可能感兴趣的:(Python,mongodb)