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

简介: [20150610]sql的谓词中使用函数.txt --程序开发经常可以看到如下的代码: -- trunc(dd_date)=trunc(sysdate),结果导致必须建立函数索引。

[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如何计算出来的,估计比较复杂放弃。

目录
相关文章
|
4月前
|
SQL Oracle 关系型数据库
SQL优化-使用联合索引和函数索引
在一次例行巡检中,发现一条使用 `to_char` 函数将日期转换为字符串的 SQL 语句 CPU 利用率很高。为了优化该语句,首先分析了 where 条件中各列的选择性,并创建了不同类型的索引,包括普通索引、函数索引和虚拟列索引。通过对比不同索引的执行计划,最终确定了使用复合索引(包含函数表达式)能够显著降低查询成本,提高执行效率。
|
4月前
|
SQL 数据库 数据库管理
数据库SQL函数应用技巧与方法
在数据库管理中,SQL函数是处理和分析数据的强大工具
|
4月前
|
SQL 数据库 索引
SQL中COUNT函数结合条件使用的技巧与方法
在SQL查询中,COUNT函数是一个非常常用的聚合函数,用于计算表中满足特定条件的记录数
1045 5
|
4月前
|
SQL 关系型数据库 MySQL
SQL日期函数
SQL日期函数
|
6月前
|
SQL 数据库
|
6月前
|
SQL 数据采集 数据处理
如何在 SQL Server 中使用 LEN 函数
【8月更文挑战第9天】
237 1
如何在 SQL Server 中使用 LEN 函数
|
5月前
|
SQL 关系型数据库 C语言
PostgreSQL SQL扩展 ---- C语言函数(三)
可以用C(或者与C兼容,比如C++)语言编写用户自定义函数(User-defined functions)。这些函数被编译到动态可加载目标文件(也称为共享库)中并被守护进程加载到服务中。“C语言函数”与“内部函数”的区别就在于动态加载这个特性,二者的实际编码约定本质上是相同的(因此,标准的内部函数库为用户自定义C语言函数提供了丰富的示例代码)
|
6月前
|
SQL 数据处理 数据库
SQL中的函数有哪些类型
【8月更文挑战第20天】SQL中的函数有哪些类型
74 1
|
6月前
|
SQL 监控 索引
如何在 SQL Server 中使用 `PATINDEX` 函数
【8月更文挑战第8天】
612 9
|
6月前
|
SQL 数据处理 数据库