楼主: nyfor

[精华] 很少受关注的SQL中一些函数调用秘密

[复制链接]
论坛徽章:
281
2015年新春福章
日期:2015-03-06 11:57:312012新春纪念徽章
日期:2012-02-13 15:12:252012新春纪念徽章
日期:2012-01-04 11:51:22蛋疼蛋
日期:2011-12-29 07:37:22迷宫蛋
日期:2011-12-26 14:19:41茶鸡蛋
日期:2011-11-17 09:20:52茶鸡蛋
日期:2011-11-10 22:42:38ITPUB十周年纪念徽章
日期:2011-11-01 16:21:15茶鸡蛋
日期:2011-10-24 09:48:48ITPUB十周年纪念徽章
日期:2011-09-27 16:30:47
21#
发表于 2008-9-9 09:19 | 只看该作者
原帖由 nyfor 于 2008-9-8 16:23 发表
以上出现在 order by, group by 表达式中的函数调用与出现在 where 中的还有一个不同就是后者的函数调用表达式不论是否与表数据有关, 均对每一行数据都调用一次(注意这是筛选之后的每一行)

5.
SQL> exec pkg.reset_n;

PL/SQL procedure successfully completed
SQL> select pkg.inc_n from t where pkg.inc_n = 1;

     INC_N
----------
         2
         3
         4
SQL> select pkg.get_n from dual;

     GET_N
----------
         4

SQL>
SQL> exec pkg.reset_n;

PL/SQL procedure successfully completed
SQL> select pkg.inc_n from t where pkg.inc_n = 2;

     INC_N
----------
SQL> select pkg.get_n from dual;

     GET_N
----------
         1

   以上两条结果似乎不是我们所想象的.
SQL> exec pkg.reset_n;

PL/SQL procedure successfully completed
SQL> select  * from (select pkg.inc_n n from t ) where n = 1;

         N
----------
         2
         3
         4
SQL> select pkg.get_n from dual;

     GET_N
----------
         4
SQL> exec pkg.reset_n;

PL/SQL procedure successfully completed
SQL> select  * from (select pkg.inc_n n from t ) where n = 2;

         N
----------
SQL> select pkg.get_n from dual;

     GET_N
----------
         1

这里我们发现Oracle对于复杂的查询做优化后导致执行结果不是我们想要的.
对于前两个SQL, Oracle 的执行路径已经转换为后面两个了. 那么我们有什么办法来防止这种情况发生呢, 禁止外层where谓词push 到内部查询, 但是Oracle好像又没有这样的 hint 可用. 目前我是没有找到什么好办法来阻止这种错误结果的发生.
这个简单:select  * from (select pkg.inc_n n,rownum rn from t ) where n = 1;即可

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
22#
 楼主| 发表于 2008-9-9 09:35 | 只看该作者
select  * from (select pkg.inc_n n,rownum rn from t ) where n = 1;
真是很奇怪啊, 加了个 Rownum 列它就正确了.

Oracle 好深奥哦...

个人觉得: 函数调用次数的不确定性, 以及某些SQL产生我们不期望的结果, 都归结于Oracle的优化器的优化原理.

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
23#
 楼主| 发表于 2008-9-9 09:41 | 只看该作者
newkid 讲的 DETERMINISTIC 函数, 以及函数返回值的 cache 策略, 其实都不太重要,
因为 DETERMINISTIC 函数的调用次数不确定并不会影响SQL查询的结果.
而非 DETERMINISTIC 函数就麻烦了, 极有可能影响SQL查询的结果.

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
24#
发表于 2008-9-9 10:17 | 只看该作者
呵呵,我是在你启发下做了些试验,知其然不知其所以然。
不知你们看了我#18的贴没有?用ROWNUM的效果我也是知道的,这是为了防止PUSH谓词,但我不知道NO_MERGE HINT怎么不起作用呢?你们用NO_MERGE试过没有?
要说这个研究成果,我认为有以下几点:
1.不要依赖于函数调用次数。在函数里不要有修改上下文相关的操作。
2.第1点做到之后,我们就要尽量减少函数调用,提高效率。
2.a 在你理解了DETERMINISTIC 函数的前提下,尽量用DETERMINISTIC 函数。典型的应用例子:代码转名称,名称转代码。
2.b 在非DETERMINISTIC 函数时,也要尽量让ORACLE CACHE住你的函数结果。可用技巧就是SCALAR SUBQUERY.

nyfor 你认为1000次调用和10次调用没有区别吗?哪个效率高?尽管结果都是一样的。

请继续讨论哈,明天我再来。

使用道具 举报

回复
论坛徽章:
3
ITPUB9周年纪念徽章
日期:2010-10-08 09:28:52ITPUB十周年纪念徽章
日期:2011-11-01 16:20:28ITPUB 11周年纪念徽章
日期:2012-10-10 13:11:14
25#
发表于 2008-9-9 10:24 | 只看该作者
虽然我是菜鸟,但感觉你的研究很无聊和没有必要性。一般很少有人会用dbms_random.value进行随机查询的。而且在dbms_random.value<dbms_random.value.这样的where条件,我想大概没有人会用到的,对于一个case来说,总有其明确的需求,则同样带来了明确的where条件。不会用dbms_random.value <dbms_random.value. 作为无聊的条件的. oracle的聚组函数其功用是固定的,唯一变化的只是随查询的数据的变化而变化,其值也只会返回唯一值.用户需求的也就是可以确定的期望值.在程序中如果多次调用,建议每次在调用之前给个初值,则无论调用多少次都不会带来错误的结果的.
个人浅见,仅供参考.

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
26#
 楼主| 发表于 2008-9-9 10:40 | 只看该作者
原帖由 newkid 于 2008-9-9 10:17 发表
呵呵,我是在你启发下做了些试验,知其然不知其所以然。
不知你们看了我#18的贴没有?用ROWNUM的效果我也是知道的,这是为了防止PUSH谓词,但我不知道NO_MERGE HINT怎么不起作用呢?你们用NO_MERGE试过没有?
要说这个研究成果,我认为有以下几点:
1.不要依赖于函数调用次数。在函数里不要有修改上下文相关的操作。
2.第1点做到之后,我们就要尽量减少函数调用,提高效率。
2.a 在你理解了DETERMINISTIC 函数的前提下,尽量用DETERMINISTIC 函数。典型的应用例子:代码转名称,名称转代码。
2.b 在非DETERMINISTIC 函数时,也要尽量让ORACLE CACHE住你的函数结果。可用技巧就是SCALAR SUBQUERY.

nyfor 你认为1000次调用和10次调用没有区别吗?哪个效率高?尽管结果都是一样的。

请继续讨论哈,明天我再来。

我看了你的那个帖子的. 也看到了使用 rownum 后的效果, 只是后来三思再次提起, 我就回复了一下.
no_merge 之前我没试过, 刚试了, 真的不行.
1000次调用和10次调用当然有性能上的区别, 我说的不太重要的原因是说 不会影响到结果的正确性, 也就是说至少不会让我们的代码出现BUG.

使用道具 举报

回复
论坛徽章:
281
2015年新春福章
日期:2015-03-06 11:57:312012新春纪念徽章
日期:2012-02-13 15:12:252012新春纪念徽章
日期:2012-01-04 11:51:22蛋疼蛋
日期:2011-12-29 07:37:22迷宫蛋
日期:2011-12-26 14:19:41茶鸡蛋
日期:2011-11-17 09:20:52茶鸡蛋
日期:2011-11-10 22:42:38ITPUB十周年纪念徽章
日期:2011-11-01 16:21:15茶鸡蛋
日期:2011-10-24 09:48:48ITPUB十周年纪念徽章
日期:2011-09-27 16:30:47
27#
发表于 2008-9-9 10:43 | 只看该作者
to:nf
不奇怪,rownum固化结果集,不好使才叫奇怪~~

to:newkid
no_merge不会有效,原因很简单,看看该语句的执行计划就明白了~

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
28#
 楼主| 发表于 2008-9-9 11:01 | 只看该作者
DETERMINISTIC 函数特性在 Oracle 10G 才得以实现.
9I 中还无效, 虽然可以定义这样的函数.

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
29#
 楼主| 发表于 2008-9-9 11:03 | 只看该作者
原帖由 junsansi 于 2008-9-9 10:43 发表
to:nf
不奇怪,rownum固化结果集,不好使才叫奇怪~~

嗯, 有道理.

使用道具 举报

回复
论坛徽章:
3
奥运会纪念徽章:铁人三项
日期:2008-08-14 11:45:20生肖徽章2007版:马
日期:2009-03-20 11:26:202010新春纪念徽章
日期:2010-03-01 11:19:07
30#
发表于 2008-9-9 11:19 | 只看该作者
先收藏

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表