NoSQL反模式 - 文档数据库篇(4)
问题四 盯死应用的内联症状:应用可以非常好的运行在数据库上。但是当新的应用接入的时候会很麻烦。因为设计数据模型的时候考虑到了查询。所以当有新应用,新查询接入的时候,就会难于使用原有的模型。
坏处:
新应用接入难。当新的应用试图使用同一个数据库的时候,接入比较困难。因为查询时不同的,需要调整数据模型才能适应。但是调整模型又会影响原有应用。集成难。不同的关系型数据库可以集成在一起,共同使用。但是对于文档数据库,虽然功能上可以互补,但是由于内联数据结构的差异,也比较难于集成。ETL难。现在大部分的数据分析系统使用的是关系模型,就连Hadoop虽然不用关系模型,但是其上的Hive的常用工具也是按关系模型设计的。
解决方案:
使用范式设计数据库,即用引用代替内联。或者在使用内联的时候,给每个内联对象一个全局唯一的Key,保证其和关系模型直接可以存在映射关系,这样可以提高数据模型的灵活性。如Blog表:
Blog_id | content | Comment[] | …… |
0 | “…” | [{"id"=1,"content"=“NoSQL反模式是好文章”}, {"id"=2,"content"=“是啊”}…] | …… |
这样的设计既可以利用到内联的好处,又能将其和关系模型映射起来。确定是需要手动维护comment_id,保证其全局唯一性。
反模式四:在线计算
症状:有一些运行时间很长的Query,由于有聚合计算,索引也不能解决。随着数据量的增长,逐渐成为性能瓶颈。
坏处:
影响用户体验。在线业务中,如果一个查询大于4s,用户体验会急剧下降。按主键和按索引的查询都能满足要求。但是聚合操作往往需要扫描全表或者大量的数据,随着数据量的增加,查询时间会变长,用户不可容忍。影响数据库性能。长查询的坏处数不清。在线上应用中,如果出现长查询,可能会霸占数据的大部分资源,包括IO,连接,CPU等等。导致其他很好的查询,轻则性能也下降,重者无法使用数据库。长查询可以称之为DB杀手。
解决方案:首先要权衡,这个聚合操作是不是必要的,必须实时完成。如果没有必要实时完成的话,可以采取离线操作的方案。在夜深人静的时候,跑一个长查询,将结果缓存起来,给第二天使用。如果必须实时完成,则可以新建一个字段,用“incr”这样的操作,在运行的时候,实时聚合结果。而不是查询的时候执行一次长查询。如果逻辑比较复杂,或者觉得大量“incr”操作给数据库系统带来了压力,可以使用Storm之类的实时数据处理框架。总之,要慎用长查询。
反模式五:把内联Map对象的Key当作ID用
症状:文档数据库支持内联Map类型。将其中Map的Key当作数据库的主键来用。
Blog_id | content | Comment{} | …… |
0 | “…” | {"1"=“NoSQL反模式是好文章”, "2"=“是啊”} | …… |
坏处:
无法通过数据库做各种(><=)查询。对于关系型数据库来说,虽然数据结构可以很灵活,但查询的时候都是按层次的。比如comment.id,comment.content。也就是说其Map类型中的Key可以理解为属性名的,而不是用作ID。因此一旦这样使用,就脱离的数据库管制,无法使用各种查询功能。无法通过索引查询。文档数据可建立索引是需要列名的。比如comment.id。而这样的数据结构没有固定的列名,因此无法建立索引。
解决方案:使用数组+Map来解决。如: