目录搜索
oracle知识ORACLE的数据类型Oracle技术网—DBMS_Job包的用法Oracle技术网—Oracle for NT系统实用工具介绍Oracle技术网—Oracle常见错误代码Oracle技术网—Oracle常用ScriptOracle技术网—Oracle常用数据字典Oracle技术网—ORACLE数据库简介Oracle技术网—Oracle特殊包Oracle技术网—Oracle相关站点Oracle技术网—哪些初始化参数最影响Oracle系统性能PL/SQLDBAOracle7 7.3.2.2Oracle技术网—listener.log的内容增长很快,是否可以删除重建Oracle技术网—ORACLE表空间恢复方案Oracle技术网—Oracle常用系统文件有哪些Oracle技术网—ORACLE回滚段管理(上)Oracle技术网—ORACLE回滚段管理(下)Oracle技术网—Oracle如何决定使用哪个回退段Oracle技术网—Oracle数据库的空间管理技巧Oracle技术网—Oracle数据库碎片整理Oracle技术网—Oracle数据库有哪几种关闭方式Oracle技术网—Oracle数据库有哪几种启动方式Oracle技术网—Oracle预定义角色有哪些Oracle技术网—ROLLBACK不能回滚的命令Oracle技术网—查看哪些session正在使用哪些回滚段Oracle技术网—存储参数(storage子句)含义及设置技巧Oracle技术网—和权限有关的表有哪些Oracle技术网—漫谈数据库的启动和关闭Oracle技术网—哪些初始化参数最影响Oracle系统性能Oracle技术网—如何备份控制文件Oracle技术网—如何查出前台正在发出的sql语句Oracle技术网—如何查看Oracle版本及安装了哪些选项Oracle技术网—如何查看Oracle数据表的建表语句Oracle技术网—如何查看SGA区剩余可用内存Oracle技术网—如何查看各个表空间占用磁盘情况Oracle技术网—如何查看后台进程Oracle技术网—如何查看什么时间有哪些数据库对象结构被修改过Oracle技术网—如何查看数据库的各种数据文件Oracle技术网—如何查看数据库的字符集Oracle技术网—如何查看数据文件是否自动扩展Oracle技术网—如何查看数据文件所在的路径Oracle技术网—如何查看用户表上的约束内容Oracle技术网—如何查看用户表所占空间的大小Oracle技术网—如何查询出primary key和forgen key的关系表Oracle技术网—如何改变当前联机日志文件的大小Oracle技术网—如何利用DBMS_SQL包和游标计算当前用户下所有表的行数Oracle技术网—如何启动ARCHIVELOG模式Oracle技术网—如何取出某一用户的密码,再原封不动的改回去Oracle技术网—如何设置BLOCK_SIZE大于2K,如:4K、16KOracle技术网—如何手工指定使用哪个回退段Oracle技术网—如何修改internal的口令Oracle技术网—如何移动控制文件到新的目录中Oracle技术网—如何移数据库文件Oracle技术网—如何增加表空间的大小Oracle技术网—怎样查看init.ora文件Oracle技术网—怎样查看SGA值Oracle技术网—怎样查看哪些用户拥有SYSDBA、SYSOPER权限?Oracle技术网—怎样快速查出Oracle 数据库中的锁等待Oracle技术网—怎样识别IO竞争和负载平衡Exp vs ImpOracle技术网—EXP、IMP 命令详解Oracle技术网—Exp/Imp大量数据Oracle技术网—Export/Import 使用技巧与常见错误Oracle技术网—Oracle数据库的备份与恢复Oracle技术网—如何把数据exp到Sql loader里Oracle技术网—如何单独备份一个或多个表Oracle技术网—如何单独备份一个或多个用户Oracle技术网—如何导入指定表Oracle技术网—如何建立一个与现存数据库相同,但不包含数据的空库Oracle技术网—如何在oracle7和oracle8之间exp/imp数据Oracle技术网—提高ORACLE数据库系统import性能Oracle技术网—为何我的导出文件只有500KOracle技术网—自动备份Oracle数据库Oracle技术网—作Export或Import时,如何记录LOG信息?SQL技巧Oracle技术网—LONG数据类型使用上的一些说明Oracle技术网—Oracle8 PL/SQL编程风格与系统性能的提高Oracle技术网—Oracle8中用户名、表名、列名、索引名...可以用中文命名吗Oracle技术网—Oracle中如何实现某一字段自动增加1Oracle技术网—SQL(Structured Query Language)语句分哪几类Oracle技术网—SQL*PLUS常用命令列表Oracle技术网—SQL*Plus系统环境变量有哪些?如何修改?Oracle技术网—SQL*Plus中缓冲区命令列表Oracle技术网—SQL*Plus中能运行哪几种命令Oracle技术网—SQLPlus中的复制和粘贴技巧Oracle技术网—查看本用户下的各种对象的SQL脚本Oracle技术网—查找a表中有,而在b表中没有的记录Oracle技术网—利用PL/SQL打印ASCII表Oracle技术网—如何查找、删除表中重复的记录Oracle技术网—如何对CLOB行字段执行全文检索Oracle技术网—如何对CLOB字段进行全文检索?Oracle技术网—如何改变表中列的名字Oracle技术网—如何改变一个字段初始定义的Check范围Oracle技术网—如何给表、列加注释Oracle技术网—如何将 primary key 建在其它的表空间上Oracle技术网—如何删除表中的列Oracle技术网—如何使‘CREATE TABLE AS SELECT’能支持ORDER BY ?Oracle技术网—如何通过 SQL*PLUS 将符号 & 、'号(单引号) 插入Oracle数据库的表中Oracle技术网—如何用SQL生成SQL批处理文件Oracle技术网—如何在PL_SQL中读写文件Oracle技术网—如何自动生成一个含有20000101至20500101共50年日期的表Oracle技术网—如何自动生成一个含有2000年01月至2050年01月共50年月份的表Oracle技术网—删除a表中和b表相同的数据Oracle技术网—在Oracle快速进行数据行存在性检查Oracle技术网—怎样查看表的结构Oracle技术网—怎样改变SQL*Plus启动时默认路径Oracle技术网—怎样计算表中的记录数Oracle技术网—怎样在SQL*Plus中使用 '&' 来实现自定义参数变量?Oracle技术网—怎样在查询记录时给记录加锁Oracle错误Oracle7 7.3.2.2Oracle技术网—Oracle 816中如何启动Enterprise ManagerOracle技术网—Oracle Enterprise Manager(OEM)工具中如何以SYSOPER、SYSDBA方式登录Oracle技术网—ORACLE数据库应用开发常见问题及排除Oracle技术网—监听器错误Oracle技术网—联机热备份失败后,如何打开数据库Oracle技术网—没有备份、只有归档日志,如何恢复数据文件Oracle技术网—某个数据文件损坏,如何打开数据库Oracle技术网—如何使用归档日志进行完全恢复Oracle技术网—如何正确建立TYPE、partition(分区)Oracle技术网—一个控制文件被损坏,如何启动Oracle技术网—在SQL*Plus中insert进的都是中文的,为什么一存入服务器后,再select出的就是???了Oracle技术网—重装Oracle服务器后,以前的数据可以恢复吗Oracle初学者入门Oracle技术网—Oracle 8.1.6 for Win2000 系统文件解释Oracle技术网—Oracle 基本知识Oracle技术网—Oracle8 数据类型Oracle技术网—what is sql?Oracle技术网—安装、配置后,SQL*Plus操作初步Oracle技术网—安装Oracle后,经常使用的修改表空间的SQL代码Oracle安装、删除Oracle技术网—Oradim工具的用法Oracle技术网—WINDOWS NT上,如何删除ORACLE SERVICEOracle技术网—如何连接两台Oracle服务器Oracle技术网—如何在Windows 2000下将Oracle完全卸载Oracle技术网—如何在WINDOWS NT上删除所有的Oracle安装?Oracle技术网—手工安装数据库时需要安装那些系统包Oracle技术网—手工创建数据库的全部脚本及说明Oracle安全性问题Oracle技术网—Linux ORACLE 8.1.5漏洞Oracle技术网—Oracle 8.1.6的oidldapd中的漏洞Oracle技术网—Oracle8的不安全因素及几点说明Oracle技术网—Oracle数据库的安全策略Oracle技术网—Oracle数据库密码文件的使用和维护Oracle技术网—提高Oracle数据库应用系统安全的举例与分析数据库安全性策略Oracle系统设置、优化、连接《Oracle8 优化技术》摘录 (第一章 安装)《Oracle8 优化技术》摘录 (第二章 内存/CPU)《Oracle8 优化技术》摘录 (第三章 输入/输出)Oracle技术网—ASP 中通过OLEDB访问 Oracle 的代码Oracle技术网—Delphi5 企业版使用BDE访问 Oracle方法Oracle技术网—oracle database access objectOracle技术网—Oracle基于Client/Server的性能调整Oracle技术网—PB7 连接 Oracle 的配置方法Oracle技术网—PB内置Oracle数据库接口的使用方法Oracle技术网—PHP+Oracle(OCI) 初步Oracle技术网—PHP4连接Oracle 8i的方法(转译)Oracle技术网—多个数据库时,如何设置默认数据库Oracle技术网—如何备份Oracle设置Oracle技术网—如何让你的SQL运行得更快Oracle技术网—如何修改 SQL*Plus 的启动参数Oracle技术网—如何在Windosws 2000中安装JSP并访问OracleOracle技术网—如何在Windosws 2000中安装perl并访问OracleOracle技术网—如何在Windosws 2000中安装PHP4并访问OracleOracle技术网—如何在Windosws NT中使用批处理命令自动启动或关闭Oracle ServicesOracle技术网—如何在客户端省略输入数据库串,而只输入用户名、密码即可Oracle技术网—使用Database Configuration Assistant安装第二个数据库Oracle技术网—修改Oracle7数据库maxdatafiles参数的方法索引、序列、快照、数据库链路、触发器Oracle技术网—触发器的几种应用Oracle技术网—建立触发器时最容易忽略的两个地方Oracle技术网—快照和触发子结合使用的例子Oracle技术网—能否通过视图更新表中的数据Oracle技术网—如何创建一个简单的JAVA存储过程?Oracle技术网—如何创建隐藏IP地址的最后一项的函数?Oracle技术网—如何加密Oracle中的存储过程Oracle技术网—为什么有时ORACLE数据库不用索引来查找数据Oracle技术网—我的数据库链路为什么不工作Oracle技术网—一个建立快照的简单例子Oracle技术网—怎样创建一个简单的自定义过程并引用Oracle技术网—怎样手工刷新快照oracle与其他数据库的比较MySQL 测试Oracle技术网—Oracle 和 mysql 的一些简单命令对比参照Oracle技术网—Oracle8i和Microsoft SQL Server7.0比较Oracle技术网—比较SQL Server与Oracle、DB2Oracle技术网—各种数据类型的比较Oracle技术网—戏说SQL—几种SQL 服务器的比较关键任务      在Internet上运作公司是一项艰苦的任务其它知识OEM常见问题及其解决办法Oracle 8 资料库函式库Oracle 资料库函式库Oracle技术网—Decode()函数使用技巧(NT+IIS+ASP+ORACLE)Oracle技术网—Dual伪列Oracle技术网—NULL 使用详解Oracle技术网—OLAP及其多维数据分析Oracle技术网—Oracle for NT系统实用工具介绍Oracle技术网—ORACLE 用户的规范化管理Oracle技术网—user、uid伪列Oracle技术网—大型数据库设计原则Oracle技术网—留言簿(带Oracle数据库分页的显示功能)Oracle技术网—漫谈oracle中的空值Oracle技术网—如何正确利用Rownum来限制查询所返回的行数Oracle技术网—什么是ROWID,为什么需要它Oracle技术网—数据库技术考试大纲(中级)Oracle技术网—数据库行业的现状和展望Oracle技术网—在客户端处理Oracle的数据行加锁问题如何对CLOB行字段执行全文检索Developer 2000Oracle技术网—Developer/2000中各键盘触发子所对应的“按键”Oracle技术网—FORM调用REPORT时,如何去掉report serverOracle技术网—FORM中,Exception(例外)都有哪些,如何书写Oracle技术网—FORM中,FORM中,如何引入图像Oracle技术网—FORM中,WINDOW标题的设置Oracle技术网—FORM中,常用快捷键有哪些Oracle技术网—FORM中,触发子exit_form的两种功能是什么Oracle技术网—FORM中,当光标走到块的最后一项时,如何让按“enter回车”键时,光标自动走到下一条记录的第一项?Oracle技术网—FORM中,当用鼠标点击标签画布的某一“标签页”时,如何判断点击的是哪一页Oracle技术网—FORM中,如何屏蔽默认的功能键Oracle技术网—FORM中,如何实现屏幕同步刷新?Oracle技术网—FORM中,如何使用警告Oracle技术网—FORM中,如何通过 ODBC 访问 Acress 数据?Oracle技术网—FORM中Oracle技术网—FORM中,设置应用特性(光标类型)Oracle技术网—FORM中,怎样创建动态下拉列表ListOracle技术网—FORM中如何存取声音Oracle技术网—FORM中如何存取图象?如何把图象从一个表中导到另一个表中?Oracle技术网—MIS中的图像应用技术Oracle技术网—MIS中的图像应用技术Oracle技术网—从FORM中调用REPORT时,如何使打印结果直接输出到打印机上Oracle技术网—如何从FORM中调用REPORT程序Oracle技术网—如何改变FORM(FMX模块)运行时的title?Oracle技术网—如何在FORM运行中,使定制菜单中的“窗口(W)”菜单项不显示Oracle技术网—如何在启动FORM程序时直接登录到Oracle数据库上?Oracle技术网—运行FORM时,如何使按钮变灰(即无效)Oracle技术网—运行FORM时,如何使窗口(runtime窗口、画布窗口)自动变成最大化、最小化?Oracle技术网—在Developer/2000中如何读写文本型操作系统文件Oracle技术网—在Oracle中实现报表的定长输出linux vs UnixHow To Install Oracle 8.0.5 onto RedHat Linux 6HOWTO: OAS for Linux on FreeBSDHOWTO: Oracle for Linux on FreeBSDOracle 7.3.4 Enterprise Edition for SCO UNIX 安装步骤Oracle技术网—Oracle .com 套件在TurboLinux上的安装Oracle技术网—ORACLE 7.3 Enterprise在SCO OPEN SERVER 5.02 及 5.04 的安装过程Oracle技术网—ORACLE 7.3.4.2 for SCO Unix 安装说明Oracle技术网—Oracle 8 for solaris 2.6 安装步骤Oracle技术网—Oracle 8(8.0.5)标准版安装指南Oracle技术网—Oracle 8i(8.1.5)企业版安装指南Oracle技术网—ORACLE FOR SUN SOLARIS 安装手册Oracle技术网—ORACLE FOR SUN SOLARIS 维护手册Oracle技术网—ORACLE V.7.3.4.3 FOR AIX 安装说明Oracle技术网—ORACLE8I FOR SUN SOLARIS2.7 安装说明Oracle技术网—RedHat 6.1 Step-by-step Install notes for Oracle 8iOracle技术网—RedHat Linux 6.0 上 Oracle 8(8.0.5)标准版 安装实例Oracle技术网—RedHat Linux 6.0 上 Oracle 8i R2 (8.1.6) 企业版安装实例Oracle技术网—如何集成Linux/Apache/PHP4/FastCGI/Oracle/MySQL环境Oracle技术网—如何在你的Linux机器上安装运行OracleOracle技术网—为Linux配备Oracle 8Oracle技术网—在RedHat 6.0上安装Oracle 8i(全攻略)
文字

如何让你的SQL运行得更快

摘自计算机日报

交通银行长春分行电脑部
任亮

  人们在使用SQL时往往会陷入一个误区,即太关注于所得的结果是否正确,而忽略了不同的实现方法之间可能存在的性能差异,这种性能差异在大型的或是复杂的数据库环境中(如联机事务处理OLTP或决策支持系统DSS)中表现得尤为明显。笔者在工作实践中发现,不良的SQL往往来自于不恰当的索引设计、不充份的连接条件和不可优化的where子句。在对它们进行适当的优化后,其运行速度有了明显地提高!下面我将从这三个方面分别进行总结:

  为了更直观地说明问题,所有实例中的SQL运行时间均经过测试,不超过1秒的均表示为(< 1秒)。

  测试环境--
  主机:HP LH II
  主频:330MHZ
  内存:128兆
  操作系统:Operserver5.0.4
  数据库:Sybase11.0.3

一、不合理的索引设计

  例:表record有620000行,试看在不同的索引下,下面几个 SQL的运行情况:

  1.在date上建有一非个群集索引

select count(*) from record where date >
'19991201' and date <  '19991214'and amount > 
2000 (25秒)
select date,sum(amount) from record group by date
(55秒) 
select count(*) from record where date >
'19990901' and place in ('BJ','SH') (27秒)
  分析:

  date上有大量的重复值,在非群集索引下,数据在物理上随机存放在数据页上,在范围查找时,必须执行一次表扫描才能找到这一范围内的全部行。

  2.在date上的一个群集索引

select count(*) from record where date > 
'19991201' and date < '19991214' and amount >
2000 (14秒)
select date,sum(amount) from record group by date
(28秒)
select count(*) from record where date >
'19990901' and place in ('BJ','SH')(14秒)
  分析:

  在群集索引下,数据在物理上按顺序在数据页上,重复值也排列在一起,因而在范围查找时,可以先找到这个范围的起末点,且只在这个范围内扫描数据页,避免了大范围扫描,提高了查询速度。

  3.在place,date,amount上的组合索引

select count(*) from record where date >
'19991201' and date < '19991214' and amount >
2000 (26秒)
select date,sum(amount) from record group by date
(27秒)
select count(*) from record where date >
'19990901' and place in ('BJ, 'SH')(< 1秒)
  分析:

  这是一个不很合理的组合索引,因为它的前导列是place,第一和第二条SQL没有引用place,因此也没有利用上索引;第三个SQL使用了place,且引用的所有列都包含在组合索引中,形成了索引覆盖,所以它的速度是非常快的。

  4.在date,place,amount上的组合索引

select count(*) from record where date > 
'19991201' and date < '19991214' and amount >
2000(< 1秒)
select date,sum(amount) from record group by date
(11秒)
select count(*) from record where date >
'19990901' and place in ('BJ','SH')(< 1秒)
  分析:

  这是一个合理的组合索引。它将date作为前导列,使每个SQL都可以利用索引,并且在第一和第三个SQL中形成了索引覆盖,因而性能达到了最优。

  5.总结:

  缺省情况下建立的索引是非群集索引,但有时它并不是最佳的;合理的索引设计要建立在对各种查询的分析和预测上。一般来说:

  ①.有大量重复值、且经常有范围查询

(between, >,< ,>=,< =)和order by
、group by发生的列,可考虑建立群集索引;

  ②.经常同时存取多列,且每列都含有重复值可考虑建立组合索引;

  ③.组合索引要尽量使关键查询形成索引覆盖,其前导列一定是使用最频繁的列。

二、不充份的连接条件:

  例:表card有7896行,在card_no上有一个非聚集索引,表account有191122行,在 account_no上有一个非聚集索引,试看在不同的表连接条件下,两个SQL的执行情况:

select sum(a.amount) from account a,
card b where a.card_no = b.card_no(20秒)
  将SQL改为:
select sum(a.amount) from account a,
card b where a.card_no = b.card_no and a.
account_no=b.account_no(< 1秒)
  分析:

  在第一个连接条件下,最佳查询方案是将account作外层表,card作内层表,利用card上的索引,其I/O次数可由以下公式估算为:

  外层表account上的22541页+(外层表account的191122行*内层表card上对应外层表第一行所要查找的3页)=595907次I/O

  在第二个连接条件下,最佳查询方案是将card作外层表,account作内层表,利用account上的索引,其I/O次数可由以下公式估算为:

  外层表card上的1944页+(外层表card的7896行*内层表account上对应外层表每一行所要查找的4页)= 33528次I/O

  可见,只有充份的连接条件,真正的最佳方案才会被执行。

  总结:

  1.多表操作在被实际执行前,查询优化器会根据连接条件,列出几组可能的连接方案并从中找出系统开销最小的最佳方案。连接条件要充份考虑带有索引的表、行数多的表;内外表的选择可由公式:外层表中的匹配行数*内层表中每一次查找的次数确定,乘积最小为最佳方案。

  2.查看执行方案的方法-- 用set showplanon,打开showplan选项,就可以看到连接顺序、使用何种索引的信息;想看更详细的信息,需用sa角色执行dbcc(3604,310,302)。

三、不可优化的where子句

  1.例:下列SQL条件语句中的列都建有恰当的索引,但执行速度却非常慢:

select * from record where 
substring(card_no,1,4)='5378'(13秒)
select * from record where
amount/30< 1000(11秒)
select * from record where 
convert(char(10),date,112)='19991201'(10秒)
  分析:

  where子句中对列的任何操作结果都是在SQL运行时逐列计算得到的,因此它不得不进行表搜索,而没有使用该列上面的索引;如果这些结果在查询编译时就能得到,那么就可以被SQL优化器优化,使用索引,避免表搜索,因此将SQL重写成下面这样:

select * from record where card_no like
'5378%'(< 1秒)
select * from record where amount
< 1000*30(< 1秒)
select * from record where date= '1999/12/01'
(< 1秒)

  你会发现SQL明显快起来!

  2.例:表stuff有200000行,id_no上有非群集索引,请看下面这个SQL:

select count(*) from stuff where id_no in('0','1') 
(23秒)
  分析:

  where条件中的'in'在逻辑上相当于'or',所以语法分析器会将in ('0','1')转化为id_no ='0' or id_no='1'来执行。我们期望它会根据每个or子句分别查找,再将结果相加,这样可以利用id_no上的索引;但实际上(根据showplan),它却采用了"OR策略",即先取出满足每个or子句的行,存入临时数据库的工作表中,再建立唯一索引以去掉重复行,最后从这个临时表中计算结果。因此,实际过程没有利用id_no上索引,并且完成时间还要受tempdb数据库性能的影响。

  实践证明,表的行数越多,工作表的性能就越差,当stuff有620000行时,执行时间竟达到220秒!还不如将or子句分开:

select count(*) from stuff where id_no='0'
select count(*) from stuff where id_no='1'
  得到两个结果,再作一次加法合算。因为每句都使用了索引,执行时间只有3秒,在620000行下,时间也只有4秒。或者,用更好的方法,写一个简单的存储过程:
create proc count_stuff as
declare @a int
declare @b int
declare @c int
declare @d char(10)
begin
select @a=count(*) from stuff where id_no='0'
select @b=count(*) from stuff where id_no='1'
end
select @c=@a+@b
select @d=convert(char(10),@c)
print @d
  直接算出结果,执行时间同上面一样快!

  总结:

  可见,所谓优化即where子句利用了索引,不可优化即发生了表扫描或额外开销。

  1.任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。

  2.in、or子句常会使用工作表,使索引失效;如果不产生大量重复值,可以考虑把子句拆开;拆开的子句中应该包含索引。

  3.要善于使用存储过程,它使SQL变得更加灵活和高效。

  从以上这些例子可以看出,SQL优化的实质就是在结果正确的前提下,用优化器可以识别的语句,充份利用索引,减少表扫描的I/O次数,尽量避免表搜索的发生。其实SQL的性能优化是一个复杂的过程,上述这些只是在应用层次的一种体现,深入研究还会涉及数据库层的资源配置、网络层的流量控制以及操作系统层的总体设计。

返回

上一篇:下一篇: