DM6数据库中带有大对象字段的表构成的可更新视图在查询的时候导致数据库core的解决思路
场景故障还原简化脚本如下:
Create table B(b1 int, b2 char);
Create table A (a1 int, a2 text);
Create view V as select aa. from A aa where aa.a1 in (select b1 from B);
Select * from V;
可以正常查询出结果,但是把数据库重启后,再次执行
Select * from V;
数据库异常停止。
出现故障的主要原因是,系统对可更新视图涉及表的顺序未做正确排列处理,在涉及存在大字段的表时,利用了错误的条件,在结构转换及访问时出现错误,导致系统处理异常。具体原因分析分为两步:
(1)可更新视图与一般视图不同,只能有一个基表及若干关联表,以上简化脚本中V为可更新视图,A为其基表,B为其关联表。系统对于可更新视图处理时,会建立一个所依赖表的内存链,并要求基表A在链头,其他关联表在链头之后顺序排列。
数据库启动过程中,因为先创建的B表,然后才创建的A表,B表的id则比A表的小,视图V在构造所依赖表的内存链时,依据ID做顺序扫描,导致先找到的B表,然后才是A表,链表中顺序就是B表->A表,对于一般视图没影响,但对于可更新视图,此步处理存在错误(对于依赖的基表A应该单独判断并置于链头)。
处理完表关联后,需要继续处理列关联,系统加载列的处理流程如下:
视图中每一个列都需要找到其对应的依赖表的列,对于可更新视图V,其列都为基表的列,由于前面所依赖表的内存链顺序错误,导致每个列实际都依赖表A,而系统查找时都找到了表B,这样就找不到对应的依赖列,从而导致视图列的依赖列都被设置为空。
(2)由于视图中包含大字段列,为了处理大字段列,在对视图做查询的过程中,对大字段的列有特殊的判断要求,即如果该列是大对象字段,其依赖列为空,则认为该列所属的对象是表而不是视图,刚好此处由于前面内存链顺序错误导致依赖列被设置为空,系统认为该列所属为表而不是视图,但实际该列所属为视图,导致把视图结构当表结构来访问,所以导致数据库异常退出。
出现此故障需要有三个条件:
(1) 视图为可更新视图。
(2) 可更新视图的基表ID比其他一个多多个关联表的ID大。
(3) 视图中存在大字段列。
解决办法:
在创建视图的时候,如为可更新视图,系统在构造可更新视图所依赖的表的内存链时,在扫描过程中,若是关联表,在内存链中顺序排列;若是基表,则直接置于链头,确保可更新视图所依赖的表的内存链保持正确的顺序。