NoSQL反模式 - 文档数据库篇(5)
Blog_id | content | Comment[] | …… |
0 | “…” | [{"id"=1,"content"=“NoSQL反模式是好文章”}, {"id"=2,"content"=“是啊”}…] | …… |
反模式六:不合理的ID
症状:使用String甚至更复杂数据结构作为的ID,或者全部使用数据库提供的自生成ID。如:
id(该ID系系统自生成) | Blog_id | content | …… |
0 | 0 | ... | …… |
ID混乱。如果使用数据库提供的自生成ID,同时表中还有一个类似有主键含义的Blog_id,这样很不好,容易造成逻辑混乱。由于文档数据库不支持ID的重命名,习惯关系数据库做法的人可能会再建立一个自己的逻辑ID字段。这是没有必要的。索引庞大,性能低下。ID是数据库的非常重要的部分。ID的长度将决定索引(包括主键的索引)的大小,直接影响到数据库性能。如果索引比内存小,性能会很好。但一旦索引大小超过内存,出现数据交换,性能会急剧下降。一个Long占8字节,一个20个字符的UTF8 String占用约60个字节。相差10倍之巨,不能不考虑。
解决方案:尽量使用有一定意义的字段做ID,并且不在其他字段中重复出现。不使用复杂的数据类型做ID,只使用int,long或者系统提供的主键类型做ID。
文档数据库的反模式总结
阐述了这么多的反模式,下面有个一览表,涵盖了上面所有的反模式。这个一览表,是按照文档数据库模型建立的。是个文档数据库模型的例子。
ID | 反模式名 | 问题 |
0 | 存在描述多对多的关系表 | [{ID:00 症状:文档数据库中存储在有纯粹的关系表 坏处:[破坏数据完备性,索引过多] 解决方案:加入一个List字段 },{ ID:01 症状:关系模型不区分“一对多”和“多对一” 坏处:额外索引 解决方案:合理的安排字段的位置 }] |
1 | 处处引用客户端Join | [{ ID:10 症状:查询的时候需要大量的手动Join操作 坏处:[手动Join,多次查询, 事务处理繁琐] 解决方案:适当使用内联数据结构。 }] |
2 | 滥用内联后患无穷 | [{ ID:20 症状:频繁查询一些内联字段,丢弃其他字段 坏处:[无ID约束,索引泛滥, 性能浪费] 解决方案:使用引用代替内联了,允许重复数据 },{ ID:21 症状:List,Map类型的内联字段不断膨胀,而且没有限制 坏处:[插入失败, 性能拖油瓶] 解决方案:设定最大数目或者使用引用。 },{ ID:22 症状:DBA想单独维护内联字段,但无法做到 坏处:[权限管理难, 切表难, 备份难] 解决方案:设计数据库模型的时候需要考量之后的维护操作 },{ ID:23 症状:应用可以非常好的运行在数据库上。但是当新的应用接入的时候会很麻烦。内联盯死了应用 坏处:[新应用接入难, 集成难, ETL难] 解决方案:使用范式设计数据库,即用引用代替内联。保证其和关系模型直接可以存在映射关系 }] |
3 | 在线计算 | [{ ID:30 症状:有一些运行时间很长的Query, 逐渐成为性能瓶颈。 坏处:[影响用户体验,影响数据库性能] 解决方案:取消不必要的聚合操作. 运行的时候,实时聚合结果.使用第三方实时或非实时工具。如Hadoop,Storm. }] |
4 | 把内联Map对象的Key当作ID用 | [{ ID:40 症状:文档数据库支持内联Map类型。将其中Map的Key当作数据库的主键来用。 坏处:[无法通过数据库做各种(><""" =)查询,无法通过索引查询] 解决方案:使用数组+Map来解决。 }] |
5 | 不合理的ID | [{ ID:50 症状:用String甚至更复杂数据结构作为的ID,或者全部使用数据库提供的自生成ID。 坏处:[ID混乱,索引庞大] 解决方案:尽量使用有一定意义的字段做ID。不使用复杂的数据类型做ID。 }] |