在使用 YashanDB 的物化视图功能进行查询优化时,有用户遇到如下困惑:
“我明明启用了查询重写,为什么语句还是没有命中物化视图?”
经过实际验证,问题出在一个细节——使用了 select * 创建物化视图。本文将带你分析问题原因,并给出规避建议。
一、问题现象
使用如下语句创建基础表与物化视图:
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;
均未触发查询重写!
但当我们使用带双引号的大写列名查询时:
select "TID", "TNAME" from test where tid = 66;
查询重写成功命中物化视图。
二、问题风险与影响
重写未命中 → 查询无法利用预聚合视图 → 性能大打折扣;
用户难以定位问题原因,误以为功能不可用;
查询优化效果严重依赖于使用者写 SQL 的“方式”。
三、问题根因剖析
目前 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)等价分析;
聚合字段、表达式规范化识别;
提升查询重写的智能化水平。
七、总结
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。