oracle SQL优化之高效的函数调用

原文地址:https://oracle-base.com/articles/misc/efficient-function-calls-from-sql

     http://www.oracle.com/technetwork/issue-archive/2011/11-sep/o51asktom-453438.html

1. 问题描述

  我们说一个function是确定性的(deterministic),当对于相同的输入总是返回相同的输出,oracle中的内置函数如abs,不管多少次调用,abs(-1)总是返回1。假设在sql中调用这种function,如果存在相同的输入数据,每次调用都要重新执行function的话就会产生性能浪费。 

create table func_test(id number);

--插入数据
INSERT INTO func_test
SELECT CASE
         WHEN level = 10 THEN 3
         WHEN MOD(level, 2) = 0 THEN 2
         ELSE 1
       END
FROM   dual
CONNECT BY level <= 10;
COMMIT;
create or replace function slow_function(
       p_in  number
) return number
  deterministic
is
begin
  sys.dbms_lock.sleep(1);
  return p_in;
end;
SQL> set timing on;
SQL> select slow_function(id) from func_test;
SLOW_FUNCTION(ID)
-----------------
                1
                2
                1
                2
                1
                2
                1
                2
                1
                3
10 rows selected
Executed in 10.046 seconds

上述SQL执行时间为10.046秒,说明对于每一行数据,都执行了slow_function方法。由于slow_function是确定性的:对于slow_function(1)用于返回1,所以上述SQL对于造成了性能浪费。

2. 标量子查询缓存(scalar subquery caching)

 标量子查询缓存会通过缓存结果减少sql对function的调用次数,改用标量子查询的sql仅仅用时3.057秒,即SQL对于slow_function的调用只发生了三次。

SQL> select (select slow_function(id) from dual) from func_test;
(SELECTSLOW_FUNCTION(ID)FROMDU
------------------------------
                             1
                             2
                             1
                             2
                             1
                             2
                             1
                             2
                             1
                             3
10 rows selected
Executed in 3.057 seconds

当使用标量子查询的时候,oracle会在内存中建立一个很小的hash table用于缓存子查询结果,对多可以缓存255个子查询结果:

select (select slow_function(id) from dual) from func_test;
 
  id slow_function(id)

当第一次查询slow_function(1)的时候,由于hash table没有缓存,所以需要执行slow_function;当第二次查询slow_function(1)的时候可以直接从hash table拿出结果,而不用再次调用slow_function。即便有可能发生hash冲突,而且hash table只支持255个bucket,标量子查询对于性能提高总是好的。

3. DETERMINISTIC

  oracle通过关键字DETERMINISTIC来表名一个function是确定性的,确定性函数可以用于创建基于函数的索引。

create or replace function slow_function(
       p_in  number
) return number
deterministic
is
begin
  sys.dbms_lock.sleep(1);
  return p_in;
end;

deterministic缓存受限于每次从服务器fetch多少数据,缓存仅在当前fetch的生命周期内有效,而标量子查询是当前查询内有效。

假设set arraysize 1 DETERMINISTIC关键字不会对性能起到任何帮助,set arraysize 15,也仅仅是每15条数据的缓存结果可以重用。

4. RESULT_CACHE

  oracle通过关键字RESULT_CACHE对函数返回的结果进行缓存,缓存结果可以被session共享。

create or replace function slow_function(p_in number)
return number
result_cache
is
begin
  sys.dbms_lock.sleep(1);
  return p_in;
end;

通过关键字result_cache的函数在执行过以后,速度会大幅提升。

5. 即便通过deterministic和result_cache可以提高,但我们总是应该使用标量子查询,因为deterinisitic和result_cache仅仅是缓存结果,并不能减少SQL和PLSQL上下文质检的切换,即总是会发生SQL引擎和PLSQL引擎的交互,并不会减少对CPU的消耗。

 标量子查询也可以作用于where子句以提高查询性能。

6. 函数调用中的读一致性问题

  在sql中调用function,假设function中也有sql的话,在隔离级别为read committed的情况下,有可能会发生不可重复读和幻想读。可以通过dbms_flashback保证读一致性。

EXEC DBMS_FLASHBACK.enable_at_time(SYSTIMESTAMP);
SELECT slow_function(id)
FROM   func_test;
EXEC DBMS_FLASHBACK.disable;

  

时间: 2024-12-17 15:10:28

oracle SQL优化之高效的函数调用的相关文章

【重磅干货】看了此文,Oracle SQL优化文章不必再看!

听“俊”一席话,胜读十年书.看了这篇由DBA+社群联合发起人丁俊大师(网名:dingjun123)分享的SQL优化大作,其他Oracle SQL优化文章都不必再看了! 专家简介 丁俊 网名:dingjun123 DBA+社群联合发起人 性能优化专家,Oracle ACEA,ITPUB开发版资深版主.8年电信行业从业经验,在某大型电信系统提供商工作7年,任资深工程师,从事过系统开发与维护.业务架构和数据分析.系统优化等工作.擅长基于ORACLE的系统优化,精通SQL.PL/SQL.JAVA等.电子

oracle sql优化技巧

数据库方面一直是自己的薄弱项,现在以本文慢慢积累总结oracle sql优化的一些技巧. 1.首先大家很容易想到的一切优化技巧--索引,索引有啥用?索引在表数据量很大时添加索引确实能加快查询速度,通过索引查询能很好地避免全表扫描. 但应该也要注意的时这是在数据量较大的时候.同时数据较小时,反而浪费索引空间.另外,添加索引之后数据的插入,更新反而会变慢,在插入或修改记录 时需要新建索引并排序. 索引创建语句: create [unique] index xxx on A(column 1,colu

oracle sql优化

第一掌 避免对列的操作 任何对列的操作都可能导致全表扫描,这里所谓的操作包括数据库函数.计算表达式等等,查询时要尽可能将操作移至等式的右边,甚至去掉函数. 例1:下列SQL条件语句中的列都建有恰当的索引,但30万行数据情况下执行速度却非常慢: select * from record where  substrb(CardNo,1,4)='5378'(13秒) select * from record where  amount/30< 1000(11秒) select * from recor

Oracle SQL优化一(常见方法)

1.表访问方式优化: a)普通表优先“Index Lookup 索引扫描”,避免全表扫描 大多数场景下,通过“Index Lookup 索引扫描”要比“Full Table Scan (FTS) 全表扫描”效率要高的多.在编写SQL时,为了保证查询能够使用索引,需要避免出现如下场景: is null 和 is not null 在oracle中null是不能够作为索引的,如果某列数据中有“null”,不要在该列上创建索引,即使创建,也不会提高查询性能. 而在SQL语句中,如果使用is null和

Oracle SQL 优化规则

一.问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用 系统提交实际应用后,随着数据库中数据的增加,系统的响应速度就成为目前系统需要解决的最主要的问题之一.系统优化中一个很重要的方面就是SQL语句的优 化.对于海量数据,劣质SQL语句和优质SQL语句之间的速度差别可以达到上百倍,可见对于一个系统不是简单地能实现其功能就可,而是要写出高质量的 SQL语句,提高系统的可用性. 在多数情况下,Oracle

oracle sql优化笔记

oracle优化一般分为:1.sql优化(现在oracle都会根据sql语句先进行必要的优化处理,这种应该用户不大了,但是像关联和嵌套查询肯定是和影响性能的) A.oracle的sql语句的条件是从右往左执行的,如下语句:select * from t_user where nation='回族' and age > 20.oracle首先是查询年龄大于20岁的,再查询民族为回族的,最后汇总两次得到的结果. B.根据A中说的sql语句执行特点,上面的语句是可以进行优化的.A中的sql语句查询条件

Oracle SQl优化总结

连续两个公司都作为外派人员到客户方工作,缺少归属感的同时,对数据库技术的热爱是我唯一的安慰,毕竟这是自己喜欢的事情,还可以做下去. 因为客户项目的需要,我又开始接触Oracle,大部分工作在工作流的优化和业务数据的排查上.为了更好的做这份工作,我有参考过oracle达人,Oracle.10g性能分析与优化思路,基于海量数据的数据库设计与优化等书籍,以及案例学习SQL优化的视频等.基本上我工作中接触的主要是Oracle SQl的优化,基于长时间做SQL优化工作,现在对Oracle的SQL优化做一下

Oracle sql优化必知——表的访问

<访问数据的方法> 访问表中的数据有两种:1.直接访问表   2.先访问索引,再回表 1.直接访问表的两种方法: ①.全表扫描 全表扫描是指Oracle在访问目标表的数据时,会从该表所占用的第一个区(extent)的第一个块(block)开始扫描,一直扫描到该表的高水位线,这段范围内的所有数据库都必须读到,当然如果目标sql的where中指定的过滤条件,最后只返回满足条件的数据即可:(有时候全表扫描的效率还是非常高的,但是随着表的数据增多 资源消耗也会在逐步增加) ②.rowid扫描 rowi

好记性不如烂笔头之Oracle SQL优化(2)

*sql优化基于oracle11gR2读书笔记* 三.Oracle里的Cursor Oracle中的Cursor是Oracle数据库中SQL解析和执行的载体,是c语言的一种数据结构(oracle是用c写的). Oracle数据库中的Cursor分为两种:一种是Shared Cursor,另外一种是Session Cursor. 1.Shared Cursor 先来了解一下什么是库缓存.库缓存对象. 我们知道Oracle中有一个全局内存区域SGA,而SGA又可以分为java池.大池.共享池.空池等