ITPub博客

首页 > 数据库 > 数据库开发技术 > 通用SQL优化经典等价改写【四】——只取所需列

通用SQL优化经典等价改写【四】——只取所需列

原创 数据库开发技术 作者:梁敬彬 时间:2025-04-30 20:24:12 0 删除 编辑


  往期回顾:



1. 引言

在SQL优化中,"只取所需列"是一个简单却常被忽视的优化技巧。许多开发人员习惯性使用SELECT *从表或视图中获取所有列,然后在应用层面过滤出需要的列。这种做法看似方便,却可能导致数据库执行不必要的表连接和列读取,极大影响查询性能。

本文将通过一个令人惊讶的案例,展示"只取所需列"如何彻底改变查询的执行计划,甚至减少访问的表数量,从而显著提升性能。

2. 案例场景

2.1 测试环境准备

首先,我们准备测试环境,创建两个测试表并构建一个连接视图:

-- 创建测试表
drop table t1 cascade constraints purge;
drop table t2 cascade constraints purge;
create table t1 as select * from dba_objects;
create table t2 as select * from dba_objects where rownum<=10000;
-- 更新数据,确保主键值
update t1 set object_id=rownum;
update t2 set object_id=rownum;
commit;
-- 创建连接视图
create or replace view v_t1_join_t2 
as select t2.object_id, t2.object_name,
       t1.object_type, t1.owner 
from t1, t2 
where t1.object_id = t2.object_id;
-- 创建主外键约束关系
alter table T1 add constraint
  pk_object_id primary key (OBJECT_ID);
  
alter table T2 add constraint 
  fk_objecdt_id foreign key (OBJECT_ID) references t1 (OBJECT_ID);

上述脚本完成了以下工作:

创建两个测试表T1和T2,数据来源于数据字典视图DBA_OBJECTS
为表T1和T2的OBJECT_ID列设置连续的主键值
创建一个连接视图v_t1_join_t2,包含来自两个表的四个列
在T1和T2之间建立主外键关系,T1.OBJECT_ID为主键,T2.OBJECT_ID为外键

2.2 场景一:查询所有列

我们首先查询视图的所有列,看看执行计划:

SQL> set autotrace traceonly
SQL> set linesize 1000
SQL> select * from v_t1_join_t2;
执行计划如下:
Plan hash value: 2959412835
---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |  7996 |   937K|   335   (1)| 00:00:05 |
|*  1 |  HASH JOIN         |      |  7996 |   937K|   335   (1)| 00:00:05 |
|   2 |   TABLE ACCESS FULL| T2   |  7996 |   616K|    27   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| T1   |   110K|  4406K|   307   (1)| 00:00:04 |
---------------------------------------------------------------------------

分析执行计划我们可以看到:

  • 查询需要访问T1和T2两个表
  • 使用了HASH JOIN连接两个表
  • 估计耗时为5秒
  • 估计返回7996行数据
  • 总成本为335

这个执行计划完全符合预期,查询视图中的所有列必然需要访问这些列所在的所有表。

2.3 场景二:只查询部分列

现在,我们只查询视图中的部分列,看看执行计划会有什么变化:

SQL> select object_id, object_name from v_t1_join_t2;
执行计划如下:
Plan hash value: 1513984157
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  7996 |   616K|    27   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T2   |  7996 |   616K|    27   (0)| 00:00:01 |
--------------------------------------------------------------------------


这个执行计划令人惊讶!分析可以发现:

查询只访问了T2表,完全没有访问T1表
估计耗时仅为1秒,比场景一快了5倍
总成本从335降至27,降低了约92%
不再需要表连接操作

3. 优化原理分析

为什么只选择特定列就能避免访问其他表?这种奇妙的优化基于以下几个关键因素:

3.1 查询列来源分析

在场景二中,我们只查询了object_id和object_name两列,查看视图定义可以发现,这两列都来自T2表:

create or replace view v_t1_join_t2 
as select t2.object_id, t2.object_name,  -- 来自T2表
       t1.object_type, t1.owner          -- 来自T1表
from t1, t2 
where t1.object_id = t2.object_id;


3.2 主外键约束的作用

T1和T2表之间的主外键关系确保了T2表中的每个OBJECT_ID都在T1表中存在对应记录。因此,当我们只需要T2表中的列时,Oracle优化器知道:

  • 连接条件必然成立(由外键约束保证)
  • 不需要检索T1表中的任何数据
  • 可以安全地消除连接操作

3.3 Oracle优化器的智能判断

Oracle优化器在制定执行计划时,会分析查询所需的具体列,并结合数据库的约束信息,确定最优的访问路径。当发现可以安全地消除连接操作时,优化器会自动进行这种优化,从而大大提升查询性能。

4. 应用场景与最佳实践

4.1 适用场景

"只取所需列"优化技术特别适用于以下场景:

  • 查询大型视图时只需少量列(特别是当这些列来自同一个表)
  • 表之间存在约束关系(主外键约束、唯一键约束)
  • 复杂报表查询优化
  • 微服务架构中的查询优化

4.2 最佳实践

为充分利用这种优化技术,建议遵循以下最佳实践:

  • **避免使用SELECT ***:明确指定需要的列名
  • 建立适当的表约束:主外键约束不仅保证数据完整性,还有助于查询优化
  • 定期审查应用查询:检查是否有不必要的列查询
  • 考虑使用物化视图:对于频繁使用的特定列组合

5. 注意事项与总结

5.1 注意事项

  • 视图定义变更的影响:视图结构变化可能影响优化效果
  • 约束删除的风险:删除主外键约束可能导致执行计划变化
  • 统计信息的准确性:确保表统计信息是最新的

5.2 总结

"只取所需列"是一种简单却强大的SQL优化技术,通过减少不必要的列和表访问,可以显著提升查询性能。在本案例中,我们看到了这种优化如何将查询成本降低92%,并完全消除了表连接操作。

这种优化特别依赖于数据库中正确设置的约束关系,尤其是主外键约束。Oracle优化器能够利用这些约束信息,在确保结果正确的前提下,大胆消除不必要的表访问。

在实际应用中,开发人员应当培养精确指定查询列的习惯,避免使用SELECT *。同时,DBA应当确保数据库中有适当的约束定义,为优化器提供足够的信息做出最佳决策。

通过"只取所需列"这一简单改变,可以在不修改表结构、不增加索引的情况下,获得显著的性能提升,是成本最低、收益最高的SQL优化技术之一。

在这里插入图片描述


未完待续...

      SQL优化经典等价改写5——避免函数调用


公众号:收获不止数据库

微信:ljbyxl1213

系列回顾



来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/9091385/viewspace-3083089/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
历任中电福富研究院副理事长、中盾安信研究院副院长、宁德时代技术顾问等职务,受聘电信集团专家和国家十四五课题负责人,著有《收获,不止Oracle》《收获,不止SQL优化》等多本畅销数据库技术书籍。

注册时间:2024-02-06

  • 博文量
    162
  • 访问量
    198104