Django与MongoDB会让迁移成为过去吗?
因为MongoDB没有固定的结构,这是不是意味着我们在更改模型时就不需要进行数据迁移了呢?
在没有关系型数据库的情况下,数据迁移的过程是怎样的呢?
3 个回答
非关系型数据库的迁移过程是什么样的?
这要看你是否需要更新所有现有的数据。
在很多情况下,你可能不需要动旧数据,比如说你要添加一个新的可选字段。如果这个字段还有默认值,那么如果你的应用程序能正确处理缺失的字段,你也许就不需要更新旧的文档。不过,如果你想在这个新字段上建立索引,以便能够搜索、过滤或排序,那么你就需要把默认值加回到旧文档里。
像重命名字段这样的操作(在关系型数据库中很简单,因为只需要更新目录,不用动任何数据)在MongoDB中却是一项大工程(你需要重写所有文档)。
如果你需要更新现有的数据,通常你得写一个迁移函数,逐个遍历所有文档并更新它们(虽然这个过程可以共享并行运行)。对于大数据集来说,这可能会花费很多时间(和空间),而且你可能会错过一些事务(如果迁移过程中出现故障,导致只完成了一半)。
没有一种万能的解决方案。对于非关系型数据库来说,添加或删除字段比较简单(只要不使用不需要的字段,或者使用新的字段就行),而重命名字段在传统数据库中更容易(如果在无模式数据库中重命名字段,通常需要更改很多数据)。数据迁移的难度差不多,这要看具体的任务。
我觉得这个问题非常好,但根据你使用的库和对“迁移”的期望,答案可能会有些分散。
我们来看看一些常见的迁移操作:
- 添加一个字段:在Mongo中,这个操作非常简单。只需添加一个字段就可以了。
- 删除一个字段:理论上,你并不一定要遵循你的模式,所以这里的“删除”是相对的。如果你移除了这个“属性”,并且不再加载这个字段,那么这个字段在数据中是否存在就无所谓了。所以如果你不在意“清理”数据库,那么删除一个字段不会影响数据库。如果你在意清理数据库,你基本上需要对数据库运行一个巨大的循环。
- 修改字段名称:这个问题也比较复杂。当你重命名一个字段时,“在哪里”重命名呢?如果你希望数据库反映新的字段名称,那么你基本上需要在数据库上执行一个巨大的循环。为了安全起见,你可能需要“添加”数据,然后推送代码,再“取消设置”旧字段。
一些复杂情况
不过,字段名称和ActiveRecord对象的概念有点偏差。ActiveRecord对象实际上是将对象属性映射到实际数据库字段的。
在典型的关系数据库中,字段名称的“大小”并不重要。然而,在Mongo中,字段名称实际上占用数据空间,这在性能上会有很大影响。
现在,如果你使用某种“数据对象”,比如ActiveRecord,为什么要尝试在数据中存储完整的字段名称呢?数据库可能应该以字母顺序存储所有字段,并在对象端进行映射。所以一个文档可能有8个字段/属性,数据库名称可能是“a”、“b”...“j”,但对象名称则是可读的,比如“名称”、“价格”、“数量”。
我提到这个是因为它给修改字段名称增加了另一个复杂因素。如果你在实现映射,那么修改字段名称实际上并不会导致迁移。
更多复杂情况
如果你确实想在删除时实施迁移,那么你必须在部署后进行。你还需要意识到,这样做并不会节省任何当前的磁盘空间。
Mongo会预先分配空间,除非你进行数据库修复,否则它并不会“归还”空间。所以如果你在文档中删除了很多字段,这些文档仍然会占用相同的磁盘空间。如果文档稍后被移动,那么你可能会回收空间,但文档只有在增长时才会移动。
如果你从很多文档中移除一个大字段,你会想要进行修复,或者查看新的就地compact
命令。