[20150610]sql的谓词中使用函数.txt

[20150610]sql的谓词中使用函数.txt

--程序开发经常可以看到如下的代码:
-- trunc(dd_date)=trunc(sysdate),结果导致必须建立函数索引。实际上类似的错误还有很多。
-- to_char(dd_date,'yyyymmdd') = '20150610' 等等。

-- 以前我给新来的讲课都讲这些例子,可惜可惜不知道对方不长记忆还是需要多次提到,总之在实际的开发中一直出现相似的问题。

-- 还是通过一个例子来说明:

1.建立测试环境:

SCOTT@test> @ver1
PORT_STRING                    VERSION        BANNER
------------------------------ -------------- --------------------------------------------------------------------------------
x86_64/Linux 2.4.xx            11.2.0.3.0     Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production

create table t as
with a as (select rownum from dual connect by levelselect rownum id ,sysdate-rownum/1440 dd_date from a,a ;

exec sys.dbms_stats.gather_table_stats ( OwnName => user,TabName => 't',Estimate_Percent => NULL,Method_Opt => 'FOR ALL COLUMNS SIZE 1 ',Cascade => True ,No_Invalidate => false);

SCOTT@test> select owner, num_rows, blocks, last_analyzed from dba_tables where owner=user and table_name ='T';
OWNER    NUM_ROWS     BLOCKS LAST_ANALYZED
------ ---------- ---------- -------------------
SCOTT     9000000      23693 2015-06-10 09:43:12

-- 23693*8/1024=185.1015625,不到190M。

2.开始测试:
SCOTT@test> show sga
Total System Global Area 1603411968 bytes
Fixed Size                  2228784 bytes
Variable Size             973082064 bytes
Database Buffers          620756992 bytes
Redo Buffers                7344128 bytes

SCOTT@test> select count(*) from t where trunc(dd_date)=trunc(sysdate+10);
  COUNT(*)
----------
         0
Elapsed: 00:00:05.68

--注意要测试多次,这样可以缓存数据到内存中,最后几次执行以上语句测试需要5,6秒完成。

--而执行如下呢?
SCOTT@test> select count(*) from t where dd_date between trunc(sysdate+10) and trunc(sysdate+10)-1/86400;
  COUNT(*)
----------
         0
Elapsed: 00:00:00.00

--执行计划肯定都是全表扫描,因为没有任何索引,但是查询条件是trunc(dd_date)=trunc(sysdate+10)的语句,相当于trunc(dd_date)
--调用函数9e6次,可以看出5.XX秒基本都耗在这个上面。而第2次查询没有这个调用trunc函数,差距是如此的悬殊。
--另外注意后面的常量如(trunc(sysdate+10))仅仅需要计算1次。

--当然实际应用调用函数次数可能没有多,至少说明在谓词中使用函数要注意,希望这些引起开发注意。

3.使用explain plan看看cpu cost。

explain plan set statement_id='x1' for  select count(*) from t where trunc(dd_date)=trunc(sysdate+10);
explain plan set statement_id='x2' for  select count(*) from t where dd_date between trunc(sysdate+10) and trunc(sysdate+10)-1/86400;

SCOTT@test> set numw 12
SCOTT@test> select STATEMENT_ID,OPERATION, OPTIONS, COST, CPU_COST, IO_COST, TIME from plan_table where options='FULL';
STATEMENT_ OPERATION                      OPTIONS            COST     CPU_COST      IO_COST         TIME
---------- ------------------------------ ---------- ------------ ------------ ------------ ------------
x1         TABLE ACCESS                   FULL               7192  15198728278         6419            1
x2         TABLE ACCESS                   FULL               6849   8448729226         6419            1

--很明显第一个cpu cost消耗高。
--另外补充cpu_cost转化cost的计算:
--计算公式如下:
CPU Cost = ROUND(#CPUCycles / cpuspeednw / 1000 / sreadtim)

SCOTT@test> Select * from sys.aux_stats$;
SNAME                          PNAME                       PVAL1 PVAL2
------------------------------ -------------------- ------------ --------------------
SYSSTATS_INFO                  STATUS                            COMPLETED
SYSSTATS_INFO                  DSTART                            05-27-2015 09:43
SYSSTATS_INFO                  DSTOP                             05-27-2015 09:43
SYSSTATS_INFO                  FLAGS                           0
SYSSTATS_MAIN                  CPUSPEEDNW                   1639
SYSSTATS_MAIN                  IOSEEKTIM                      10
SYSSTATS_MAIN                  IOTFRSPEED                   4096
SYSSTATS_MAIN                  SREADTIM
SYSSTATS_MAIN                  MREADTIM
SYSSTATS_MAIN                  CPUSPEED
SYSSTATS_MAIN                  MBRC
SYSSTATS_MAIN                  MAXTHR
SYSSTATS_MAIN                  SLAVETHR
13 rows selected.

SCOTT@test> show parameter db_file_multiblock_read_count
NAME                                 TYPE     VALUE
------------------------------------ -------- --------
db_file_multiblock_read_count        integer  8

--根据以上数据,计算如下:
--sreadtim
10+8192/4096=12
--mreadtim
10+8*8192/4096=26

15198728278/1639/1000/12=772.7643013016066773418
773+6419=7192

8448729226/1639/1000/12=429.56727811673784828147
430+6419=6849

--正好与上面的测试结果一致。至于这里的cpu_cost如何计算出来的,估计比较复杂放弃。

时间: 2024-07-31 09:19:49

[20150610]sql的谓词中使用函数.txt的相关文章

MS SQL基础教程:用户自定义函数

除了使用系统提供的函数外,用户还可以根据需要自定义函数.用户自定义函数(User Defined Functions)是SQL Server 2000 新增的数据库对象,是SQL Server 的一大改进. 用户自定义函数不能用于执行一系列改变数据库状态的操作,但它可以像系统函数一样在查询或存储过程等的程序段中使用,也可以像存储过程一样通过EXECUTE 命令来执行.用户自定义函数中存储了一个Transact-SQL 例程,可以返回一定的值. 在SQL Server 2000 中根据函数返回值形

操作-分高悬赏答案!!sql server 2008 r2中怎样存储txt文件?

问题描述 分高悬赏答案!!sql server 2008 r2中怎样存储txt文件? 客户要求将大量TXT文件原封不动存入sql数据库,使用pb开发程序,通过pb可以实现文件的下载和上传,目前的问题就是,怎么才能将txt文件存入数据库?有几种方法?那种方法最简单易实现?具体操作怎么来?分高悬赏 解决方案 简单得很,先用编辑软件把字段之间用ascii码的t分隔,也就是tab那个键按出来的空白. 然后复制到excel,数据就从文本变成了表格形式.然后excel里面有拼接函数 那就拼接成一个inser

SQL SERVER 2000 中的标识值获取函数

server|函数 IDENTITY(标识)列,也有很多人称之为自增列,在SQL Server 2000中,标识列通过IDENTITY来定义,下面是与获取最后插入记录的标识值有关的函数的一个示例说明     SQL Server 中,可以使用 SCOPE_IDENTITY(). @@IDENTITY . IDENT_CURRENT() 来取得最后插入记录的值值,它们的区别在于:SCOPE_IDENTITY() 返回插入到同一作用域中的 IDENTITY 列内的最后一个 IDENTITY 值.一个

在 SQL Server 2005 中使用表值函数来实现空间数据库

server|函数|数据|数据库 Gyorgy Fekete 和 Alex Szalay约翰霍普金丝大学 Jim GrayMicrosoft(联系作者) 适用于Microsoft SQL Server 2005 摘要:本文说明了如何使用 C# 和表值函数将空间搜索函数("邻近点的点"和"多边形内的点")添加到 Microsoft SQL Server 2005.使用此库可以在不编写任何特殊代码的情况下向应用程序中添加空间搜索.此库实现了来自约翰霍普金丝大学的公共域

在SQL Server数据库中拆分字符串函数

SQL Server数据库中拆分字符串函数的具体方法: CREATE FUNCTION uf_StrSplit '1.1.2.50','.' (@origStr varchar(7000), --待拆分的字符串 @markStr varchar(100)) --拆分 标记,如',' RETURNS @splittable table ( str_id varchar(4000) NOT NULL, --编号ID string varchar(2000) NOT NULL --拆分后的字符串 )

sql语句多表查询中聚合函数的使用问题

问题描述 sql语句多表查询中聚合函数的使用问题 表A,B,C. A表中有title,code, b表中为code,media_code;(均不为主键,code会有重复) c表中有media_code,shrink (media_code为主键) 我的目的为取出A表中的title和c表中的shrink 联立:A.code→B.code, B.media_code→C.media_code 代码如下 select title,shrink from tableA,tableC where medi

PL/SQL --> 动态SQL调用包中函数或过程

      动态SQL主要是用于针对不同的条件或查询任务来生成不同的SQL语句.最常用的方法是直接使用EXECUTE IMMEDIATE来执行动态SQL语句字符串或字符串变量.但是对于系统自定义的包或用户自定的包其下的函数或过程,不能等同于DDL以及DML的调用,其方式稍有差异.如下见本文的描述.       有关动态SQL的描述,请参考:           PL/SQL --> 动态SQL           PL/SQL --> 动态SQL的常见错误   1.动态SQL调用包中过程不正确

sql中CONCAT函数使用

 SQL CONCAT函数实例代码教程 - SQL CONCAT函数用于将两个字符串连接起来,形成一个单一的字符串. SQL CONCAT函数用于将两个字符串连接起来,形成一个单一的字符串.试试下面的例子: SQL> SELECT CONCAT('FIRST ', 'SECOND'); +----------------------------+ | CONCAT('FIRST ', 'SECOND') | +----------------------------+ | FIRST SEC

php中addslashes函数与sql防注入_php技巧

本文实例讲述了php中addslashes函数与sql防注入.分享给大家供大家参考.具体分析如下: addslashes可会自动给单引号,双引号增加\\\\\\,这样我们就可以安全的把数据存入数据库中而不黑客利用,参数'a..z'界定所有大小写字母均被转义,代码如下: 复制代码 代码如下: echo addcslashes('foo[ ]','a..z'); //输出:foo[ ] $str="is your name o'reilly?"; //定义字符串,其中包括需要转义的字符 e