The important thing in life is to have a great aim , and the determination

常用链接

统计

IT技术链接

保险相关

友情链接

基金知识

生活相关

最新评论

SQL语句优化技术分析

操作符优化

IN 操作符

IN 写出来的 SQL 的优点是比较容易写及清晰易懂,这比较适合现代软件开发的风格。

但是用 IN SQL 性能总是比较低的,从 ORACLE 执行的步骤来分析用 IN SQL 与不用 IN SQL 有以下区别:

       ORACLE 试图将其转换成多个表的连接,如果转换不成功则先执行 IN 里面的子查询,再查询外层的表记录,如果转换成功则直接采用多个表的连接方式查询。由此可见用 IN SQL 至少多了一个转换的过程。一般的 SQL 都可以转换成功,但对于含有分组统计等方面的 SQL 就不能转换了。

       推荐方案:在业务密集的 SQL 当中尽量不采用 IN 操作符。

NOT IN操作符

       此操作是强列推荐不使用的,因为它不能应用表的索引。

       推荐方案:用 NOT EXISTS 或(外连接 + 判断为空)方案代替

<> 操作符(不等于)

       不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。

推荐方案:用其它相同功能的操作运算代替,如

       a<>0 改为 a>0 or a<0

       a<>’’ 改为 a>’’

IS NULL IS NOT NULL操作(判断字段是否为空)

       判断字段是否为空一般是不会应用索引的,因为 B 树索引是不索引空值的。

       推荐方案:

用其它相同功能的操作运算代替,如

       a is not null 改为 a>0 a>’’ 等。

       不允许字段为空,而用一个缺省值代替空值,如业扩申请中状态字段不允许为空,缺省为申请。

       建立位图索引(有分区的表不能建,位图索引比较难控制,如字段值太多索引会使性能下降,多人更新操作会增加数据块锁的现象)

> < 操作符(大于或小于操作符)

       大于或小于操作符一般情况下是不用调整的,因为它有索引就会采用索引查找,但有的情况下可以对它进行优化,如一个表有 100 万记录,一个数值型字段 A 30 万记录的 A=0 30 万记录的 A=1 39 万记录的 A=2 1 万记录的 A=3 。那么执行 A>2 A>=3 的效果就有很大的区别了,因为 A>2 ORACLE 会先找出为 2 的记录索引再进行比较,而 A>=3 ORACLE 则直接找到 =3 的记录索引。

LIKE操作符

LIKE 操作符可以应用通配符查询,里面的通配符组合可能达到几乎是任意的查询,但是如果用得不好则会产生性能上的问题,如 LIKE ‘%5400%’ 这种查询不会引用索引,而 LIKE ‘X5400%’ 则会引用范围索引。一个实际例子:用 YW_YHJBQK 表中营业编号后面的户标识号可来查询营业编号 YY_BH LIKE ‘%5400%’ 这个条件会产生全表扫描,如果改成 YY_BH LIKE ’X5400%’ OR YY_BH LIKE ’B5400%’ 则会利用 YY_BH 的索引进行两个范围的查询,性能肯定大大提高。

UNION操作符

UNION 在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录,最常见的是过程表与历史表 UNION 。如:

select * from gc_dfys

union

select * from ls_jg_dfys

这个 SQL 在运行时先取出两个表的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。

推荐方案:采用 UNION ALL 操作符替代 UNION ,因为 UNION ALL 操作只是简单的将两个结果合并后就返回。

select * from gc_dfys

union all

select * from ls_jg_dfys

SQL 书写的影响

同一功能同一性能不同写法 SQL的影响

如一个 SQL A 程序员写的为

       Select * from zl_yhjbqk

B 程序员写的为

       Select * from dlyx.zl_yhjbqk (带表所有者的前缀)

C 程序员写的为

       Select * from DLYX.ZLYHJBQK (大写表名)

D 程序员写的为

       Select *  from DLYX.ZLYHJBQK (中间多了空格)

以上四个 SQL ORACLE 分析整理之后产生的结果及执行的时间是一样的,但是从 ORACLE 共享内存 SGA 的原理,可以得出 ORACLE 对每个 SQL 都会对其进行一次分析,并且占用共享内存,如果将 SQL 的字符串及格式写得完全相同则 ORACLE 只会分析一次,共享内存也只会留下一次的分析结果,这不仅可以减少分析 SQL 的时间,而且可以减少共享内存重复的信息, ORACLE 也可以准确统计 SQL 的执行频率。

WHERE后面的条件顺序影响

WHERE 子句后面的条件顺序对大数据量表的查询会产生直接的影响,如

Select * from zl_yhjbqk where dy_dj = '1KV以下' and xh_bz=1

Select * from zl_yhjbqk where xh_bz=1  and dy_dj = '1KV以下'

以上两个 SQL dy_dj (电压等级)及xh_bz(销户标志)两个字段都没进行索引,所以执行的时候都是全表扫描,第一条SQLdy_dj = '1KV以下'条件在记录集内比率为99%,而xh_bz=1的比率只为0.5%,在进行第一条SQL的时候99%条记录都进行dy_dj及xh_bz的比较,而在进行第二条SQL的时候0.5%条记录都进行dy_dj及xh_bz 的比较,以此可以得出第二条SQLCPU占用率明显比第一条低。

查询表顺序的影响

FROM 后面的表中的列表顺序会对 SQL 执行性能影响,在没有索引及 ORACLE 没有对表进行统计分析的情况下 ORACLE 会按表出现的顺序进行链接,由此因为表的顺序不对会产生十分耗服务器资源的数据交叉。(注:如果对表进行了统计分析, ORACLE 会自动先进小表的链接,再进行大表的链接)

SQL语句索引的利用

对操作符的优化(见上节)

对条件字段的一些优化

采用函数处理的字段不能利用索引,如:

substr(hbs_bh,1,4)=’5400’ ,优化处理: hbs_bh like ‘5400%’

trunc(sk_rq)=trunc(sysdate) , 优化处理:

sk_rq>=trunc(sysdate) and sk_rq<trunc(sysdate+1)

进行了显式或隐式的运算的字段不能进行索引,如:

ss_df+20>50 ,优化处理: ss_df>30

‘X’||hbs_bh>’X5400021452’ ,优化处理: hbs_bh>’5400021542’

sk_rq+5=sysdate ,优化处理: sk_rq=sysdate-5

hbs_bh=5401002554 ,优化处理: hbs_bh=’ 5401002554’ 注:此条件对hbs_bh 进行隐式的 to_number 转换,因为 hbs_bh 字段是字符型。

条件内包括了多个本表的字段运算时不能进行索引,如:

ys_df>cx_df ,无法进行优化

qc_bh||kh_bh=’5400250000’ ,优化处理: qc_bh=’5400’ and kh_bh=’250000’

应用 ORACLE HINT(提示)处理

提示处理是在 ORACLE 产生的 SQL 分析执行路径不满意的情况下要用到的。它可以对 SQL 进行以下方面的提示

目标方面的提示:

COST (按成本优化)

RULE (按规则优化)

CHOOSE (缺省)( ORACLE 自动选择成本或规则进行优化)

ALL_ROWS (所有的行尽快返回)

FIRST_ROWS (第一行数据尽快返回)

执行方法的提示:

USE_NL (使用 NESTED LOOPS 方式联合)

USE_MERGE (使用 MERGE JOIN 方式联合)

USE_HASH (使用 HASH JOIN 方式联合)

索引提示:

INDEX TABLE INDEX )(使用提示的表索引进行查询)

其它高级提示(如并行处理等等)

ORACLE 的提示功能是比较强的功能,也是比较复杂的应用,并且提示只是给 ORACLE 执行的一个建议,有时如果出于成本方面的考虑 ORACLE 也可能不会按提示进行。根据实践应用,一般不建议开发人员应用 ORACLE 提示,因为各个数据库及服务器性能情况不一样,很可能一个地方性能提升了,但另一个地方却下降了, ORACLE SQL 执行分析方面已经比较成熟,如果分析执行的路径不对首先应在数据库结构(主要是索引)、服务器当前性能(共享内存、磁盘文件碎片)、数据库对象(表、索引)统计信息是否正确这几方面分析。

操作符优化

IN 操作符

IN 写出来的 SQL 的优点是比较容易写及清晰易懂,这比较适合现代软件开发的风格。

但是用 IN SQL 性能总是比较低的,从 ORACLE 执行的步骤来分析用 IN SQL 与不用 IN SQL 有以下区别:

       ORACLE 试图将其转换成多个表的连接,如果转换不成功则先执行 IN 里面的子查询,再查询外层的表记录,如果转换成功则直接采用多个表的连接方式查询。由此可见用 IN SQL 至少多了一个转换的过程。一般的 SQL 都可以转换成功,但对于含有分组统计等方面的 SQL 就不能转换了。

       推荐方案:在业务密集的 SQL 当中尽量不采用 IN 操作符。

NOT IN操作符

       此操作是强列推荐不使用的,因为它不能应用表的索引。

       推荐方案:用 NOT EXISTS 或(外连接 + 判断为空)方案代替

<> 操作符(不等于)

       不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。

推荐方案:用其它相同功能的操作运算代替,如

       a<>0 改为 a>0 or a<0

       a<>’’ 改为 a>’’

IS NULL IS NOT NULL操作(判断字段是否为空)

       判断字段是否为空一般是不会应用索引的,因为 B 树索引是不索引空值的。

       推荐方案:

用其它相同功能的操作运算代替,如

       a is not null 改为 a>0 a>’’ 等。

       不允许字段为空,而用一个缺省值代替空值,如业扩申请中状态字段不允许为空,缺省为申请。

       建立位图索引(有分区的表不能建,位图索引比较难控制,如字段值太多索引会使性能下降,多人更新操作会增加数据块锁的现象)

> < 操作符(大于或小于操作符)

       大于或小于操作符一般情况下是不用调整的,因为它有索引就会采用索引查找,但有的情况下可以对它进行优化,如一个表有 100 万记录,一个数值型字段 A 30 万记录的 A=0 30 万记录的 A=1 39 万记录的 A=2 1 万记录的 A=3 。那么执行 A>2 A>=3 的效果就有很大的区别了,因为 A>2 ORACLE 会先找出为 2 的记录索引再进行比较,而 A>=3 ORACLE 则直接找到 =3 的记录索引。

LIKE操作符

LIKE 操作符可以应用通配符查询,里面的通配符组合可能达到几乎是任意的查询,但是如果用得不好则会产生性能上的问题,如 LIKE ‘%5400%’ 这种查询不会引用索引,而 LIKE ‘X5400%’ 则会引用范围索引。一个实际例子:用 YW_YHJBQK 表中营业编号后面的户标识号可来查询营业编号 YY_BH LIKE ‘%5400%’ 这个条件会产生全表扫描,如果改成 YY_BH LIKE ’X5400%’ OR YY_BH LIKE ’B5400%’ 则会利用 YY_BH 的索引进行两个范围的查询,性能肯定大大提高。

UNION操作符

UNION 在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录,最常见的是过程表与历史表 UNION 。如:

select * from gc_dfys

union

select * from ls_jg_dfys

这个 SQL 在运行时先取出两个表的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。

推荐方案:采用 UNION ALL 操作符替代 UNION ,因为 UNION ALL 操作只是简单的将两个结果合并后就返回。

select * from gc_dfys

union all

select * from ls_jg_dfys

SQL 书写的影响

同一功能同一性能不同写法 SQL的影响

如一个 SQL A 程序员写的为

       Select * from zl_yhjbqk

B 程序员写的为

       Select * from dlyx.zl_yhjbqk (带表所有者的前缀)

C 程序员写的为

       Select * from DLYX.ZLYHJBQK (大写表名)

D 程序员写的为

       Select *  from DLYX.ZLYHJBQK (中间多了空格)

以上四个 SQL ORACLE 分析整理之后产生的结果及执行的时间是一样的,但是从 ORACLE 共享内存 SGA 的原理,可以得出 ORACLE 对每个 SQL 都会对其进行一次分析,并且占用共享内存,如果将 SQL 的字符串及格式写得完全相同则 ORACLE 只会分析一次,共享内存也只会留下一次的分析结果,这不仅可以减少分析 SQL 的时间,而且可以减少共享内存重复的信息, ORACLE 也可以准确统计 SQL 的执行频率。

WHERE后面的条件顺序影响

WHERE 子句后面的条件顺序对大数据量表的查询会产生直接的影响,如

Select * from zl_yhjbqk where dy_dj = '1KV以下' and xh_bz=1

Select * from zl_yhjbqk where xh_bz=1  and dy_dj = '1KV以下'

以上两个 SQL dy_dj (电压等级)及xh_bz(销户标志)两个字段都没进行索引,所以执行的时候都是全表扫描,第一条SQLdy_dj = '1KV以下'条件在记录集内比率为99%,而xh_bz=1的比率只为0.5%,在进行第一条SQL的时候99%条记录都进行dy_dj及xh_bz的比较,而在进行第二条SQL的时候0.5%条记录都进行dy_dj及xh_bz 的比较,以此可以得出第二条SQLCPU占用率明显比第一条低。

查询表顺序的影响

FROM 后面的表中的列表顺序会对 SQL 执行性能影响,在没有索引及 ORACLE 没有对表进行统计分析的情况下 ORACLE 会按表出现的顺序进行链接,由此因为表的顺序不对会产生十分耗服务器资源的数据交叉。(注:如果对表进行了统计分析, ORACLE 会自动先进小表的链接,再进行大表的链接)

SQL语句索引的利用

对操作符的优化(见上节)

对条件字段的一些优化

采用函数处理的字段不能利用索引,如:

substr(hbs_bh,1,4)=’5400’ ,优化处理: hbs_bh like ‘5400%’

trunc(sk_rq)=trunc(sysdate) , 优化处理:

sk_rq>=trunc(sysdate) and sk_rq<trunc(sysdate+1)

进行了显式或隐式的运算的字段不能进行索引,如:

ss_df+20>50 ,优化处理: ss_df>30

‘X’||hbs_bh>’X5400021452’ ,优化处理: hbs_bh>’5400021542’

sk_rq+5=sysdate ,优化处理: sk_rq=sysdate-5

hbs_bh=5401002554 ,优化处理: hbs_bh=’ 5401002554’ 注:此条件对hbs_bh 进行隐式的 to_number 转换,因为 hbs_bh 字段是字符型。

条件内包括了多个本表的字段运算时不能进行索引,如:

ys_df>cx_df ,无法进行优化

qc_bh||kh_bh=’5400250000’ ,优化处理: qc_bh=’5400’ and kh_bh=’250000’

应用 ORACLE HINT(提示)处理

提示处理是在 ORACLE 产生的 SQL 分析执行路径不满意的情况下要用到的。它可以对 SQL 进行以下方面的提示

目标方面的提示:

COST (按成本优化)

RULE (按规则优化)

CHOOSE (缺省)( ORACLE 自动选择成本或规则进行优化)

ALL_ROWS (所有的行尽快返回)

FIRST_ROWS (第一行数据尽快返回)

执行方法的提示:

USE_NL (使用 NESTED LOOPS 方式联合)

USE_MERGE (使用 MERGE JOIN 方式联合)

USE_HASH (使用 HASH JOIN 方式联合)

索引提示:

INDEX TABLE INDEX )(使用提示的表索引进行查询)

其它高级提示(如并行处理等等)

ORACLE 的提示功能是比较强的功能,也是比较复杂的应用,并且提示只是给 ORACLE 执行的一个建议,有时如果出于成本方面的考虑 ORACLE 也可能不会按提示进行。根据实践应用,一般不建议开发人员应用 ORACLE 提示,因为各个数据库及服务器性能情况不一样,很可能一个地方性能提升了,但另一个地方却下降了, ORACLE SQL 执行分析方面已经比较成熟,如果分析执行的路径不对首先应在数据库结构(主要是索引)、服务器当前性能(共享内存、磁盘文件碎片)、数据库对象(表、索引)统计信息是否正确这几方面分析。

posted on 2007-02-05 18:40 鸿雁 阅读(203) 评论(0)  编辑  收藏