sql server转换时间格式为YYYYMMDD - 我的异常网 当前位置:
&&&sql server转换时间格式为YYYYMMDD
sql server转换时间格式为YYYYMMDD
,网友分享于: 09:32:58&&&搜索量:145次
oracle字符转换时间SQL语句
数据库中的时间字段 都存成21 这种格式
要转换成 19:34:21 这种格式
update m_pd_log t set t.currtime=(substr(t.currtime,0,4
网友分享于: 17:43:43
ASP 转换时间存入SQL Server2000 数据库将字符串 &
& 转换成 & -19:00 &
& 转换成 & -6:00解决方案必须转成SQL SERVER认识的样子
网友分享于: 17:45:36
求2个转换时间的SQL写法?1、当前日期是字符串格式。比如:
,转换成 datetime格式 即: :6:00:00 ,每一个字符串日期都转换成这样的格式,比如
----》 06:00:00,2012
网友分享于: 17:32:09
C++中如何转换时间格式从这种格式 11:39:55 到这种格式Tue, 11 Oct :53 +0800
Tue怎么转换呢?C++中.& 当然,上面的时间不一致,就是举个例子.解决方案
CTimeCString.Format
网友分享于: 14:32:45
python转换时间戳和日期时间格式的转换[steven@txzxp2 seccenter]$ python
Python 2.7.5 (default, Jul &8 :59)&
[GCC 4.8.1
(Red Hat 4.8.1-1)] on
网友分享于: 13:42:18
SQL时间格式为“”,如何转换成普通日期格式数据库中时间日期存储格式为,。如何转化为普通时间日期格式解决方案
mysql& SELECT FROM_UNIXTIME();
| FROM_UNIXTIME
网友分享于: 09:55:54
GridView中转换时间格式,帮帮忙,急!我数据库里有个字段是smallDateTime类型,但是在GridView中显示时现实了长时间格式: & 0:00:00
我想在GridView中现实短的时间格式,我看了数据库里的数据也是短的时间格式,为什么现实出来就变成长的了呢?
网友分享于: 22:02:47
sql server将日期转换为指定格式,如“yyyymmdd”好像没有这个功能,只能使用日期格式代码?解决方案convert(需要转化成的类型,被转换的字段,格式(日期格式用不同的整形数字表示))
解决方案探讨好像没有这个功能,只能使用日期格式代码?
解决方案探讨引用:引用:好像没有这个功能,只能使用日期格式
网友分享于: 12:01:12
SQL 时间格式转换
SELECT CONVERT(varchar(100), cdate, 0):24 06 PMSELECT CONVERT(varchar(100), cdate, 1): 06/24/09SELECT CONVERT(varchar(100), cdate, 2
网友分享于: 09:43:05
SQL语句转换时间格式:
CONVERT(VARCHAR(10),[SubmitTime],105)
获得的形式为:30-09-2011
则可以进行比较。
该实例是求“今日访问数据总条数”。
网友分享于: 12:01:08
sql server 2005默认时间格式问题原先因操作系统时区设置错误,导致装完数据库后默认时间格式不对,操作系统的时区已纠正,但数据库里的表示格式还是不对,用print getdate()打印输出格式为:&07
1 AM&,我想把时间表示的默认格式改成"
网友分享于: 09:57:37
修改Oracle SQL Developer的时间格式
打开Oracle SQL Developer, 选择 Tools --& Preferences --& Database --& NLS--&Date Format,
把默认的格式:DD-MON-RR 改为你想要的格式:
网友分享于: 12:56:22
如何更改sql server 2005 的默认时间格式sql中默认的格式是月日年,而vs中得到的日期格式为年月日,
& System.DateTime.Now.ToString( & )
更新到sql中的日期型数据, & 日期就不对了.
请问,sql中该如何修改,才能
网友分享于: 09:13:51
常用SQL时间格式
SQL Server中文版的默认的日期字段datetime格式是yyyy-mm-dd Thh:mm:ss.mmm 例如:select getdate() 11:06:08.177这对于在要不同数据库间转移数据或者习惯oracle日期格式YYYY-MM-DD HH24
网友分享于: 10:24:33
在线等!怎么把SQL Server 2000中的timestamp类型的字段转换成时间格式显示出来...
DateFormat & df & = & new & java.text.SimpleDateFormat( &yyyy/MM/dd "
网友分享于: 22:12:57
各类解决方案WEB开发数据库移动开发企业软件/开发硬件/嵌入开发JAVA应用服务器软件工程/管理/测试.NETLinux/Unix多媒体开发语言/框架专题开发/技术/项目综合高性能开发硬件设备Windows培训认证 Copyright &sql server将日期转换为指定格式,如“yyyymmdd”
[问题点数:40分,结帖人athwind]
sql server将日期转换为指定格式,如“yyyymmdd”
[问题点数:40分,结帖人athwind]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
相关帖子推荐:
2014年4月 荣获微软MVP称号2013年4月 荣获微软MVP称号
2012年7月 MS-SQL Server大版内专家分月排行榜第一2012年6月 MS-SQL Server大版内专家分月排行榜第一2012年5月 MS-SQL Server大版内专家分月排行榜第一2012年4月 MS-SQL Server大版内专家分月排行榜第一
2008年 总版技术专家分年内排行榜第二
2010年 总版技术专家分年内排行榜第四2009年 总版技术专家分年内排行榜第五2007年 总版技术专家分年内排行榜第六
2014年7月荣获微软MVP称号2013年7月 荣获微软MVP称号2012年7月 荣获微软MVP称号2011年7月 荣获微软MVP称号
2012年2月 总版技术专家分月排行榜第三
2014年7月荣获微软MVP称号2013年7月 荣获微软MVP称号2012年7月 荣获微软MVP称号2011年7月 荣获微软MVP称号
2012年2月 总版技术专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。当前位置: >
> 高效SQL语句必杀技NoSQL,Nocost.SQL语句是造成数据库开销最大的部分。而不良SQL写
高效SQL语句必杀技NoSQL,Nocost.SQL语句是造成数据库开销最大的部分。而不良SQL写
tdjmcqw & at
高效SQL语句必杀技
No SQL,No cost. SQL语句是造成数据库开销最大的部分。而不良SQL写法直接导致数据库系统性能下降的情形比比皆是。那么如何才能称得上高效的SQL语句呢?一是查询优化器为当前的SQL语句生成最佳的执行计划,保证数据读写使用最佳路径;二是设置合理的物理存储结构,如表的类型,字段的顺序,字段的数据类型等。本文主要描述如何编写高效的SQL语句并给出示例。下面的描述主要分为三个部分,一是编写高效SQL语句,二是使用索引提高查询性能的部分,三是总结部分。
一、编写高效SQL语句
1) 选择最有效的表名顺序(仅适用于RBO模式)
ORACLE的解析器总是按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中最后的一个表将作为驱动表被优先处理。当FROM子句
存在多个表的时候,应当考虑将表上记录最少的那个表置于FROM的最右端作为基表。Oracle会首先扫描基表(FROM子句中最后的那个表)并对
记录进行排序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并。如
果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表,交叉表是指那个被其他表所引用的表。
下面的例子使用最常见的scott或hr模式下的表进行演示
表 EMP 有14条记录
表 DEPT 有4条记录
SELECT /*+ rule */ COUNT( * ) FROM emp, --高效的写法
scott@CNMMBO& set auto
scott@CNMMBO& SELECT /*+ rule */ COUNT( * ) FROM emp,
Elapsed: 00:00:00.14
Statistics
----------------------
1 recursive calls
0 db block gets
35 consistent gets
0 physical reads
0 redo size
515 bytes sent via SQL*Net to client
492 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SELECT /*+ rule */ COUNT( * ) FROM dept, --低效的写法
scott@CNMMBO& SELECT /*+ rule */ COUNT( * ) FROM dept,
Elapsed: 00:00:00.02
Statistics
----------------------
1 recursive calls
0 db block gets
105 consistent gets
0 physical reads
0 redo size
515 bytes sent via SQL*Net to client
492 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
2) select 查询中避免使用'*'
当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用 '*' 是一个方便的方法.不幸的是,这是一个非常低效的方法.实际
上,ORACLE在解析的过程中, 会将 '*' 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间。
注:本文中的例子出于简化演示而使用了select * ,生产环境应避免使用.
3) 减少访问数据库的次数
每当执行一条SQL语句,Oracle 需要完成大量的内部操作,象解析SQL语句,估算索引的利用率,绑定变量, 读数据块等等.由此可
见,减少访问数据库的次数,实际上是降低了数据库系统开销
--&下面通过3种方式来获得雇员编号为的相关信息
--&方式 1 (最低效):
select ename,job,sal from emp where empno=7788;
select ename,job,sal from emp where empno=7902;
--&方式 2 (次低效):
--&下面使用了参数游标来完成,每传递一次参数则需要对表emp访问一次,增加了I/O
CURSOR C1(E_NO NUMBER) IS
SELECT ename, job, sal
FROM emp
WHERE empno = E_NO;
OPEN C1 (7788);
FETCH C1 INTO …, …, …;
..
OPEN C1 (7902);
FETCH C1 INTO …, …, …;
CLOSE C1;
END;
--&方式 3 (最高效)
SELECT a.ename
, a.job
, a.sal
, b.ename
, b.job
, b.sal
FROM emp a, emp b
WHERE a.empno = 7788 OR b.empno = 7902;
注意:在SQL*Plus,SQL*Forms和Pro*C中重新设置ARRAYSIZE参数,可以增加每次数据库访问的检索数据量,建议值为200.
4) 使用DECODE函数来减少处理时间
--&使用decode函数可以避免重复扫描相同的行或重复连接相同的表
select count(*),sum(sal) from emp where deptno=20 and ename like 'SMITH%';
select count(*),sum(sal) from emp where deptno=30 and ename like 'SMITH%';
--&通过使用decode函数一次扫描即可完成所有满足条件记录的处理
SELECT COUNT( DECODE( deptno, 20, 'x', NULL ) ) d20_count
, COUNT( DECODE( deptno, 30, 'x', NULL ) ) d30_count
, SUM( DECODE( deptno, 20, sal, NULL ) ) d20_sal
, SUM( DECODE( deptno, 30, sal, NULL ) ) d30_sal
FROM emp
WHERE ename LIKE 'SMITH%';
类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中。
5) 整合简单,无关联的数据库访问
--&如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中以提高性能(即使它们之间没有关系)
--&整合前
SELECT name
FROM emp
WHERE empno = 1234;
SELECT name
FROM dept
WHERE deptno = 10;
SELECT name
FROM cat
WHERE cat_type = 'RD';
--&整合后
SELECT e.name, d.name, c.name
FROM cat c
, dpt d
, emp e
, dual x
WHERE NVL( 'X', x.dummy ) = NVL( 'X', e.ROWID(+) )
AND NVL( 'X', x.dummy ) = NVL( 'X', d.ROWID(+) )
AND NVL( 'X', x.dummy ) = NVL( 'X', c.ROWID(+) )
AND e.emp_no(+) = 1234
AND d.dept_no(+) = 10
AND c.cat_type(+) = 'RD';
--&从上面的SQL语句可以看出,尽管三条语句被整合为一条,性能得以提高,然可读性差,此时应权衡性能与代价
6) 删除重复记录
--&通过使用rowid来作为过滤条件,性能高效
DELETE FROM emp e
WHERE e.ROWID & (SELECT MIN( x.ROWID )
FROM emp x
WHERE x.empno = e.empno);
7) 使用truncate 代替 delete
--&通常情况下,任意记录的删除需要在回滚段构造删除前镜像以实现回滚(rollback).对于未提交的数据在执行rollback之后,Oracle会生成
--&等价SQL语句去恢复记录(如delete,则生成对应的insert语句;如insert则生成对应的如update,则是同时生成delete和insert
--&使用truncate命令则是执行DDL命令,不产生任何回滚信息,直接格式化并释放高水位线.故该语句性能高效.由于不能rollback,因此慎用.
8) 尽量多使用COMMIT(COMMIT应确保事务的完整性)
--&只要有可能,在程序中尽量多使用COMMIT,这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少
--&COMMIT所释放的资源:
--&1.回滚段上用于恢复数据的信息
--&2.释放语句处理期间所持有的锁
--&3.释放redo log buffer占用的空间(commit将redo log buffer中的entries 写入到联机重做日志文件)
--&4.ORACLE为管理上述3种资源中的内部开销
9) 计算记录条数
--&一般的情况下,count(*)比count(1)稍快.如果可以通过索引检索,对索引列的计数是最快的,因为直接扫描索引即可,例如COUNT(EMPNO)
--&实际情况是经测试上述三种情况并无明显差异.
10) 用Where子句替换HAVING子句
--&尽可能的避免having子句,因为HAVING 子句是对检索出所有记录之后再对结果集进行过滤。这个处理需要排序,总计等操作
--&通过WHERE子句则在分组之前即可过滤不必要的记录数目,从而减少聚合的开销
--&低效:
SELECT deptno, AVG( sal )
FROM emp
GROUP BY deptno
HAVING deptno = 20;
scott@CNMMBO& SELECT deptno, AVG( sal )
2 FROM emp
3 GROUP BY deptno
4 HAVING deptno= 20;
Statistics
----------------------
0 recursive calls
0 db block gets
7 consistent gets
0 physical reads
0 redo size
583 bytes sent via SQL*Net to client
492 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
--&高效:
SELECT deptno, AVG( sal )
FROM emp
WHERE deptno = 20
GROUP BY
scott@CNMMBO& SELECT deptno, AVG( sal )
2 FROM emp
3 WHERE deptno = 20
4 GROUP BY
Statistics
----------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
583 bytes sent via SQL*Net to client
492 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
11) 最小化表查询次数
--&在含有子查询的SQL语句中,要特别注意减少对表的查询
--&低效:
SELECT *
FROM employees
WHERE department_id = (SELECT department_id
FROM departments
WHERE department_name = 'Marketing')
AND manager_id = (SELECT manager_id
FROM departments
WHERE department_name = 'Marketing');
--&高效:
SELECT *
FROM employees
WHERE ( department_id, manager_id ) = (SELECT department_id, manager_id
FROM departments
WHERE department_name = 'Marketing')
--&类似更新多列的情形
--&低效:
UPDATE employees
SET job_id = ( SELECT MAX( job_id ) FROM jobs ), salary = ( SELECT AVG( min_salary ) FROM jobs )
WHERE department_id = 10;
--&高效:
UPDATE employees
SET ( job_id, salary ) = ( SELECT MAX( job_id ), AVG( min_salary ) FROM jobs )
WHERE department_id = 10;
12) 使用表别名
--&在多表查询时,为所返回列使用表别名作为前缀以减少解析时间以及那些相同列歧义引起的语法错误
13) 用EXISTS替代IN
在一些基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下,使用EXISTS(或NOT EXISTS)通常
将提高查询的效率.
--&低效:
SELECT *
FROM emp
WHERE sal & 1000
AND deptno IN (SELECT deptno
FROM dept
WHERE loc = 'DALLAS')
--&高效:
SELECT *
FROM emp
WHERE empno & 1000
AND EXISTS
(SELECT 1
FROM dept
WHERE deptno = emp.deptno AND loc = 'DALLAS')
14) 用NOT EXISTS替代NOT IN
在子查询中,NOT IN子句引起一个内部的排序与合并.因此,无论何时NOT IN子句都是最低效的,因为它对子查询中的表执行了一个全表
遍历.为避免该情形,应当将其改写成外部连接(OUTTER JOIN)或适用NOT EXISTS
--&低效:
SELECT *
FROM emp
WHERE deptno NOT IN (SELECT deptno
FROM dept
WHERE loc = 'DALLAS');
--&高效:
SELECT e.*
FROM emp e
WHERENOT EXISTS
(SELECT 1
FROM dept
WHERE deptno = e.deptno AND loc = 'DALLAS');
--&最高效(尽管下面的查询最高效,并不推荐使用,因为列loc使用了不等运算,当表dept数据量较大,且loc列存在索引的话,则此时索引失效)
SELECT e.*
FROM emp e LEFT JOIN dept d ON e.deptno = d.deptno
WHERE d.loc $<$ 'DALLAS'
15) 使用表连接替换EXISTS
一般情况下,使用表连接比EXISTS更高效
--&低效:
SELECT *
FROM employees e
WHERE EXISTS
(SELECT 1
FROM departments
WHERE department_id = e.department_id AND department_name = 'IT');
--&高效:
SELECT * --&经测试此写法SQLplus下比上面的写法多一次逻辑读,而在Toad下两者结果一致
FROM employees e INNER JOIN departments d ON d.department_id = e.department_id
WHERE d.department_name = 'IT';
16) 用EXISTS替换DISTINCT
对于一对多关系表信息查询时(如部门表和雇员表),应避免在select 子句中使用distinct,而使用exists来替换
--&低效:
SELECT DISTINCT e.department_id, department_name
FROM departments d INNER JOIN employees e ON d.department_id = e.department_
--&高效:
SELECT d.department_id,department_name
from departments d
WHERE EXISTS
(SELECT 1
FROM employees e
WHERE d.department_id=e.department_id);
EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果
--&经测试此写法SQLplus下比上面的写法多一次逻辑读,而在Toad下两者结果一致
17) 使用 UNION ALL 替换 UNION(如果有可能的话)
当SQL语句需要UNION两个查询结果集时,这两个结果集合会以UNION-ALL的方式被合并, 然后在输出最终结果前进行排序。
如果用UNION ALL替代UNION, 这样排序就不是必要了。 效率就会因此得到提高。
注意:
UNION ALL会输出所有的结果集,而UNION则过滤掉重复记录并对其进行排序.因此在使用时应考虑业务逻辑是否允许当前的结果集存在重复现象
寻找低效的SQL语句
--&下面的语句主要适用于从视图v$sqlarea中获得当前运行下且耗用buffer_gets较多的SQL语句
SELECT executions
, disk_reads
, buffer_gets
, ROUND( ( buffer_gets
- disk_reads )
/ buffer_gets, 2 )
hit_ratio
, ROUND( disk_reads / executions, 2 ) reads_per_run
, sql_text
FROM v$sqlarea
WHERE executions & 0
AND buffer_gets & 0
AND ( buffer_gets
- disk_reads )
/ buffer_gets & 0.80
ORDER BY 4 DESC;
18) 尽可能避免使用函数,函数会导致更多的 recursive calls
二、合理使用索引以提高性能
索引依赖于表而存在,是真实表的一个缩影,类似于一本书的目录,通过目录以更快获得所需的结果。Oracle使用了一个复杂的自平衡B数据结构。即任意记录的DML操作将打破索引的平衡,而定期重构索引使得索引重新获得平衡。通常,通过索引查找数据比全表扫描更高效。任意的DQL或DML操作,SQL优化引擎优先使用索引来计算当前操作的成本以生成最佳的执行计划。一旦使用索引操出参数optimizer_index_cost_adj设定的值才使用全表扫描。同样对于多表连接使用索引也可以提高效率。同时索引也提供主键(primary key)的唯一性验证。
除了那些LONG或LONG RAW数据类型,你可以索引几乎所有的列.通常,在大型表中使用索引特别有效.当然,你也会发现,在扫描小表时,使用索引同样能提高效率。
虽然使用索引能得到查询效率的提高,但是索引需要空间来存储,需要定期维护.尤其是在有大量DML操作的表上,任意的DML操作都将引起索引的变更这意味着每条记录的INSERT , DELETE , UPDATE将为此多付出4 , 5 次的磁盘I/O . 因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢。
DML操作使用索引上存在碎片而失去高度均衡,因此定期的重构索引是有必要的.
1) 避免基于索引列的计算
where 子句中的谓词上存在索引,而此时基于该列的计算将使得索引失效
--&低效:
SELECT employee_id, first_name
FROM employees
WHERE employee_id + 10 & 150; --&索引列上使用了计算,因此索引失效,走全表扫描方式
--&高效:
SELECT employee_id, first_name
FROM employees
WHERE employee_id & 160; --&走索引范围扫描方式
例外情形
上述规则不适用于SQL中的MIN和MAX函数
hr@CNMMBO& SELECT MAX( employee_id ) max_id
2 FROM employees
3 WHERE employee_id
4 + 10 & 150;
1 row selected.
Execution Plan
----------------------
Plan hash value:
---------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 4 | 1 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 4 | | |
| 2 | FIRST ROW | | 5 | 20 | 1 (0)| 00:00:01 |
|* 3 | INDEX FULL SCAN (MIN/MAX)| EMP_EMP_ID_PK | 5 | 20 | 1 (0)| 00:00:01 |
---------------------------------------------------------
2) 避免在索引列上使用NOT运算或不等于运算($<$,!=)
通常,我们要避免在索引列上使用NOT或$<$,两者会产生在和在索引列上使用函数相同的影响。 当ORACLE遇到NOT或不等运算时,他就会停止
使用索引转而执行全表扫描。
--&低效:
SELECT *
FROM emp
WHERENOT ( deptno = 20 ); --&实际上NOT ( deptno = 20 )等同于deptno $<$ 20,即deptno $<$同样会限制索引
--&高效:
SELECT *
FROM emp
WHERE deptno & 20 OR deptno & 20;
--&尽管此方式可以替换且实现上述结果,但依然走全表扫描,如果是单纯的 & 或 & 运算,则此时为索引范围扫描
需要注意的是,在某些时候, ORACLE优化器会自动将NOT转化成相对应的关系操作符
其次如果是下列运算符进行NOT运算,依然有可能选择走索引, 仅仅除了NOT = 之外,因为 NOT = 等价于 $<$
“NOT &” to &=
“NOT &=” to &
“NOT &” to &=
“NOT &=” to &
来看一个实际的例子
hr@CNMMBO& SELECT *
2 FROM employees
3 where not employee_id&100; --&索引列上使用了not,但是该查询返回了所有的记录,即107条,因此此时选择走全表扫描
107 rows selected.
Execution Plan
----------------------
Plan hash value:
-------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------
| 0 | SELECT STATEMENT | | 107 | 7276 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| EMPLOYEES | 107 | 7276 | 3 (0)| 00:00:01 | --&执行计划中使用了走全表扫描方式
-------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("EMPLOYEE_ID"&=100) --&查看这里的谓词信息被自动转换为 &= 运算符
hr@CNMMBO& SELECT *
2 FROM employees
3 where not employee_id&140; --&此例与上面的语句相同,仅仅是查询范围不同返回67条记录,而此时选择了索引范围扫描
67 rows selected.
Execution Plan
----------------------
Plan hash value:
---------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------
| 0 | SELECT STATEMENT | | 68 | 4624 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 68 | 4624 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 68 | | 1 (0)| 00:00:01 | --&索引范围扫描方式
---------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPLOYEE_ID"&=140)
3) 用UNION 替换OR(适用于索引列)
通常情况下,使用UNION 替换WHERE子句中的OR将会起到较好的效果.基于索引列使用OR使得优化器倾向于使用全表扫描,而不是扫描索引.
注意,以上规则仅适用于多个索引列有效。 如果有column没有被索引, 查询效率可能会因为你没有选择OR而降低。
--&低效:
SELECT deptno, dname
FROM dept
WHERE loc = 'DALLAS' OR deptno = 20;
--&高效:
SELECT deptno, dname
FROM dept
WHERE loc = 'DALLAS'
UNION
SELECT deptno, dname
FROM dept
WHERE deptno = 30
--&经测试,由于数据量较少,此时where子句中的谓词上都存在索引列时,两者性能相当.
--&假定where子句中存在两列
scott@CNMMBO& create table t6 as select object_id,owner,object_name from dba_objects where owner='SYS' and rownum&1001;
scott@CNMMBO& insert into t6 select object_id,owner,object_name from dba_objects where owner='SCOTT' and rownum&6;
scott@CNMMBO& create index i_t6_object_id on t6(object_id);
scott@CNMMBO& create index i_t6_owner on t6(owner);
scott@CNMMBO& insert into t6 select object_id,owner,object_name from dba_objects where owner='SYSTEM' and rownum&=300;
scott@CNMMBO&
scott@CNMMBO& exec dbms_stats.gather_table_stats('SCOTT','T6',cascade=&true);
scott@CNMMBO& select owner,count(*) from t6
OWNER COUNT(*)
-------------------- ----------
SCOTT 5
SYSTEM 300
SYS 1000
scott@CNMMBO& select * from t6 where owner='SCOTT' and rownum&2;
OBJECT_ID OWNER OBJECT_NAME
---------- -------------------- --------------------
69450 SCOTT T_TEST
scott@CNMMBO& select * from t6 where object_id=69450 or owner='SYSTEM';
301 rows selected.
Execution Plan
----------------------
Plan hash value:
-----------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------
| 0 | SELECT STATEMENT | | 300 | 7200 | 5 (0)| 00:00:01 |
| 1 | CONCATENATION | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| T6 | 1 | 24 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | I_T6_OBJECT_ID | 1 | | 1 (0)| 00:00:01 |
|* 4 | TABLE ACCESS BY INDEX ROWID| T6 | 299 | 7176 | 3 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | I_T6_OWNER | 300 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("OBJECT_ID"=69450)
4 - filter(LNNVL("OBJECT_ID"=69450))
5 - access("OWNER"='SYSTEM')
Statistics
----------------------
0 recursive calls
0 db block gets
46 consistent gets
0 physical reads
0 redo size
11383 bytes sent via SQL*Net to client
712 bytes received via SQL*Net from client
22 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
301 rows processed
scott@CNMMBO& select * from t6 where owner='SYSTEM' or object_id=69450;
301 rows selected.
Execution Plan
----------------------
Plan hash value:
-----------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------
| 0 | SELECT STATEMENT | | 300 | 7200 | 5 (0)| 00:00:01 |
| 1 | CONCATENATION | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| T6 | 1 | 24 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | I_T6_OBJECT_ID | 1 | | 1 (0)| 00:00:01 |
|* 4 | TABLE ACCESS BY INDEX ROWID| T6 | 299 | 7176 | 3 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | I_T6_OWNER | 300 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("OBJECT_ID"=69450)
4 - filter(LNNVL("OBJECT_ID"=69450))
5 - access("OWNER"='SYSTEM')
Statistics
----------------------
1 recursive calls
0 db block gets
46 consistent gets
0 physical reads
0 redo size
11383 bytes sent via SQL*Net to client
712 bytes received via SQL*Net from client
22 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
301 rows processed
scott@CNMMBO& select * from t6
2 where object_id=69450
3 union
4 select * from t6
5 where owner='SYSTEM';
301 rows selected.
Execution Plan
----------------------
Plan hash value:
------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------
| 0 | SELECT STATEMENT | | 301 | 7224 | 7 (72)| 00:00:01 |
| 1 | SORT UNIQUE | | 301 | 7224 | 7 (72)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| T6 | 1 | 24 | 2 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | I_T6_OBJECT_ID | 1 | | 1 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| T6 | 300 | 7200 | 3 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | I_T6_OWNER | 300 | | 1 (0)| 00:00:01 |
------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("OBJECT_ID"=69450)
6 - access("OWNER"='SYSTEM')
Statistics
----------------------
1 recursive calls
0 db block gets
7 consistent gets
0 physical reads
0 redo size
11383 bytes sent via SQL*Net to client
712 bytes received via SQL*Net from client
22 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
301 rows processed
--&从上面的统计信息可知,consistent gets由46下降为7,故当where子句中谓词上存在索引时,使用union替换or更高效
--&即使当列object_id与owner上不存在索引时,使用union仍然比or更高效(在Oracle 10g R2与Oracle 11g R2测试)
4) 避免索引列上使用函数
--&下面是一个来自实际生产环境的例子
--&表acc_pos_int_tbl上business_date列存在索引,由于使用了SUBSTR函数,此时索引失效,使用全表扫描
SELECT acc_num
, curr_cd
, DECODE( ''
, ( SELECT TO_CHAR( LAST_DAY( TO_DATE( '', 'YYYYMMDD' ) ), 'YYYYMMDD' ) FROM dual ), 0
, adj_credit_int_lv1_amt
+ adj_credit_int_lv2_amt
- adj_debit_int_lv1_amt
- adj_debit_int_lv2_amt )
AS interest
FROM acc_pos_int_tbl
WHERE SUBSTR( business_date, 1, 6 ) = SUBSTR( '', 1, 6 ) AND business_date &= '';
--&改进的办法
SELECT acc_num
, curr_cd
, DECODE( ''
, ( SELECT TO_CHAR( LAST_DAY( TO_DATE( '', 'YYYYMMDD' ) ), 'YYYYMMDD' ) FROM dual ), 0
, adj_credit_int_lv1_amt
+ adj_credit_int_lv2_amt
- adj_debit_int_lv1_amt
- adj_debit_int_lv2_amt )
AS interest
FROM acc_pos_int_tbl acc_pos_int_tbl
WHERE business_date &= TO_CHAR( LAST_DAY( ADD_MONTHS( TO_DATE( '', 'yyyymmdd' ), -1 ) )
+ 1, 'yyyymmdd' )
AND business_date &= '';
--&下面的例子虽然没有使用函数,但字符串连接同样导致索引失效
--&低效:
SELECT account_name, amount
FROM transaction
WHERE account_name
|| account_type = 'AMEXA';
--&高效:
SELECT account_name, amount
FROM transaction
WHERE account_name = 'AMEX' AND account_type = 'A';
5) 比较不匹配的数据类型
--&下面的查询中business_date列上存在索引,且为字符型,这种
--&低效:
SELECT *
FROM acc_pos_int_tbl
WHERE business_date = ;
Execution Plan
----------------------
Plan hash value:
-------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------
| 0 | SELECT STATEMENT | | 37516 | 2857K| 106K (1)| 00:21:17 |
|* 1 | TABLE ACCESS FULL| ACC_POS_INT_TBL | 37516 | 2857K| 106K (1)| 00:21:17 |
-------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_NUMBER("BUSINESS_DATE")=) --&这里可以看到产生了类型转换
--&高效:
SELECT *
FROM acc_pos_int_tbl
WHERE business_date = ''
6) 索引列上使用 NULL 值
IS NULL和IS NOT NULL会限制索引的使用,因为数据中没有值等于NULL值,即便是NULL值也不等于NULL值.且NULL值不存储在于索引之中
因此应尽可能避免在索引类上使用NULL值
SELECT acc_num
, pl_cd
, order_qty
, trade_date
FROM trade_client_tbl
WHERE input_date IS NOT NULL;
Execution Plan
----------------------
Plan hash value:
--------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 44 | 15 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TRADE_CLIENT_TBL | 1 | 44 | 15 (0)| 00:00:01 |
--------------------------------------------------
alter table trade_client_tbl modify (input_date not null);
不推荐使用的查询方式
SELECT * FROM table_name WHERE col IS NOT NULL
SELECT * FROM table_name WHERE col IS NULL
推荐使用的方式
SELECT * FROM table_name WHERE col &= 0 --尽可能的使用 =, &=, &=, like 等运算符
--&Author: Robinson Cheng
三、总结1、尽可能最小化基表数据以及中间结果集(通过过滤条件避免后续产生不必要的计算与聚合)2、为where子句中的谓词信息提供最佳的访问路径(rowid访问,索引访问)3、使用合理的SQL写法来避免过多的Oracle内部开销以提高性能4、合理的使用提示以提高表之间的连接来提高连接效率(如避免迪卡尔集,将不合理的嵌套连接改为hash连接等)
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&&&湘教QS2-164&&增值电信业务经营许可证湘B2-