在使用 YashanDB 的物化视图功能进行查询优化时,有用户遇到如下困惑:

“我明明启用了查询重写,为什么语句还是没有命中物化视图?”

经过实际验证,问题出在一个细节——使用了 select * 创建物化视图。本文将带你分析问题原因,并给出规避建议。

image.png
一、问题现象

使用如下语句创建基础表与物化视图:

alter system set query_rewrite_enabled = force scope=both;
create table test(tid number, tname varchar2(30));
begin
for i in 1..100000 loop
insert into test values(i, i || 'abcd');
end loop;
end;
/
commit;
create materialized view mv_1 as
select * from test where tid = 66;
alter materialized view mv_1 enable query rewrite;

之后执行以下查询:

select * from test where tid = 66;
select tid, tname from test where tid = 66;

image.png
均未触发查询重写!

但当我们使用带双引号的大写列名查询时:

select "TID", "TNAME" from test where tid = 66;

查询重写成功命中物化视图。

二、问题风险与影响

重写未命中 → 查询无法利用预聚合视图 → 性能大打折扣;

用户难以定位问题原因,误以为功能不可用;

查询优化效果严重依赖于使用者写 SQL 的“方式”。

image.png
三、问题根因剖析

目前 YashanDB 的物化视图重写机制,是通过文本列名匹配来判断是否可以重写的,而不是基于语义或查询逻辑。

具体机制:

使用 select * 创建物化视图时,系统会将其展开为:
`
select "TID", "TNAME" ...`
但当查询语句写为:
`
select tid, tname from test ...`
或者

select * from test ...
则匹配机制无法识别为等价表达,重写失败。

哪怕是写成:
`
select TID, TNAME ...`
由于未加双引号,也不会与 "TID", "TNAME" 匹配成功。

四、影响版本

目前所有 YashanDB 版本均存在该问题。

五、规避建议与解决方法

建议一:创建物化视图时避免使用select *

改为显式列名 + 大写 + 加双引号,例如:

create materialized view mv_1 as
select "TID", "TNAME" from test where tid = 66;

建议二:查询时也保持格式一致

查询时尽量写为:

select "TID", "TNAME" from test where tid = 66;

这样最容易命中已存在的物化视图。

建议三:统一命名规范

在数据库设计与开发中统一约定使用大写列名,并强制加双引号,是当前阶段下提升查询重写命中率的有效手段。

六、改进建议

当前 YashanDB 的物化视图重写功能仍处于初级阶段,建议未来版本从“语义等价”角度进行匹配,而不是依赖列名文本比较。

比如参考 Oracle 的方式,可通过:

查询逻辑结构比对;

抽象语法树(AST)等价分析;

聚合字段、表达式规范化识别;

提升查询重写的智能化水平。

七、总结

image.png


数据库砖家
1 声望0 粉丝