Oracle视图过滤设置疑问:外层视图执行耗时未减半
为啥OUTER_VIEW耗时和BASE_VIEW差不多?
这事儿我碰到过好几次,你直觉上觉得返回一半数据耗时也该减半,但数据库的实际执行逻辑和咱们想的不太一样,主要有这几个原因:
1. 优化器会直接合并视图逻辑
你可能以为数据库是先执行BASE_VIEW全表查询,再在结果里过滤出一半数据,但大多数现代数据库的优化器会合并视图的SQL逻辑,把两个视图的查询整合成一个:
SELECT * FROM MYTABLE where SomeField = 'something'
和BASE_VIEW的SELECT * FROM MYTABLE相比,两者都需要扫描整个MYTABLE(如果没索引的话),只是最后返回的行数少了,但最耗时的全表扫描开销是完全一样的,所以总耗时自然没差多少。
2. 全表扫描的开销占大头
如果MYTABLE没有针对SomeField建立索引,不管加不加WHERE条件,数据库都得把整个表的数据块从头到尾扫一遍。扫描磁盘数据的IO开销是查询耗时的主要部分,而过滤掉一半数据的CPU开销相比之下几乎可以忽略,所以总耗时不会明显减少。
3. 过滤条件没真的减少数据处理量
如果SomeField满足以下情况,过滤操作根本没帮你省多少事:
SomeField是通过函数计算出来的(比如SUBSTRING(xxx,1,5)),数据库没法提前过滤,得先计算每一行的值再判断;- 数据分布极不均匀,比如
SomeField = 'something'的行其实占了90%,那过滤后还是要处理几乎全表的数据。
4. 数据库统计信息过时
如果MYTABLE的统计信息很久没更新,优化器不知道SomeField = 'something'只会返回一半数据,它可能还是按照全表扫描的逻辑生成执行计划,不会做任何优化,导致耗时和全表查询一样。
给你几个排查方向:
- 看执行计划:用
EXPLAIN ANALYZE(PostgreSQL)或EXPLAIN(MySQL/Oracle)对比两个视图的执行计划,看看是不是都做了全表扫描; - 给
SomeField建索引:如果这个过滤条件常用,建个索引能让数据库直接定位到符合条件的行,不用扫全表,耗时会大幅下降; - 更新统计信息:比如执行
ANALYZE MYTABLE(PostgreSQL)或ANALYZE TABLE MYTABLE(MySQL),让优化器拿到准确的数据分布,生成更优的计划。
内容的提问来源于stack exchange,提问作者cooper_milton
相关产品推荐
相关产品推荐

