ITPub博客

首页 > 数据库 > 数据库开发技术 > 通用SQL优化经典等价改写【五】——避免函数调用

通用SQL优化经典等价改写【五】——避免函数调用

原创 数据库开发技术 作者:梁敬彬 时间:2025-05-01 16:47:42 0 删除 编辑


   往期回顾:


1. 引言

在编写 SQL 时,我们通常要尽量避免在 SQL 中使用函数。可考虑将函数的写法转化为表连接的写法。这是因为在 SQL 里使用函数,会产生大量的递归调用。一般而言,表中有多少条记录,函数就会被调用多少次,这会导致性能急剧下降。

2. 构造测试环境

为了更直观地展示这种性能差异,我们先构造一个测试环境。以下是具体的 SQL 代码:

-- 删除原有的测试表
drop table people purge;
drop table sex purge;
-- 创建people表
create table people (first_name varchar2(200),last_name varchar2(200),sex_id number);
-- 创建sex表
create table sex (name varchar2(20), sex_id number);
-- 向people表插入数据
insert into people (first_name,last_name,sex_id) select object_name,object_type,1 from dba_objects;
-- 向sex表插入数据
insert into sex (name,sex_id) values ('男',1);
insert into sex (name,sex_id) values ('女',2);
insert into sex (name,sex_id) values ('不详',3);
-- 提交事务
commit;
-- 创建函数get_sex_name
create or replace function get_sex_name(p_id sex.sex_id%type) return sex.name%type is
    v_name sex.name%type;
begin
    select name
    into v_name
    from sex
    where sex_id=p_id;
    return v_name;
end;
/

3. 两种等价 SQL 写法

以下两种写法都是为了查询people表信息,同时通过sex表获取人员的性别信息。

写法 1:调用函数

select sex_id,
       first_name||' '||last_name full_name,
       get_sex_name(sex_id) gender
from people;


写法 2:直接两表连接

select p.sex_id,
       p.first_name||' '||p.last_name full_name,
       sex.name
from people p, sex
where sex.sex_id=p.sex_id;

4. 性能对比

我们使用autotrace来比较这两种写法的性能。
调用函数写法的性能统计

set autotrace traceonly  statistics
select sex_id,
       first_name||' '||last_name full_name,
       get_sex_name(sex_id) gender
from people;


执行结果显示已选择 111120 行,以下是详细的统计信息:

统计信息
--------
     111120  recursive calls
          0  db block gets
     785917  consistent gets
          0  physical reads
          0  redo size
    3974937  bytes sent via SQL*Net to client
      81893  bytes received via SQL*Net from client
       7409  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
     111120  rows processed


表连接写法的性能统计

select p.sex_id,
       p.first_name||' '||p.last_name full_name,
       sex.name
from people p, sex
where sex.sex_id=p.sex_id;


执行结果同样显示已选择 111120 行,统计信息如下:

统计信息
--------
          0  recursive calls
          0  db block gets
       8084  consistent gets
          0  physical reads
          0  redo size
    3974935  bytes sent via SQL*Net to client
      81893  bytes received via SQL*Net from client
       7409  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
     111120  rows processed

函数调用写法产生 111120次递归调用 和 785917次逻辑读,而表连接写法 0递归调用 且逻辑读仅 8084,估算执行时间相差 超100倍。如下图所示:
在这里插入图片描述

5. 结论

从上述性能统计可以明显看出,两种写法在性能上存在巨大差异。函数写法中过多的函数调用严重影响了性能。因此,在编写 SQL 时,我们应尽量避免使用函数,优先考虑使用表连接的方式来实现相同的功能。

希望通过本文的介绍,能让大家对 SQL 中函数调用的性能问题有更深刻的认识,并在实际工作中加以应用,提升 SQL 的执行效率。

在这里插入图片描述

未完待续...

SQL优化经典等价改写6——减少函数调用


公众号:收获不止数据库

微信:ljbyxl1213

系列回顾








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

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

注册时间:2024-02-06

  • 博文量
    162
  • 访问量
    198194