查询优化
1. sql优化简介
sql的主要功能之一是不需要确切地告诉数据库如何获得请求的数据。只需要执行一个查询,指定想要的信息,然后数据库就会到最好的方法获得它。有时候,可以通过优化SQL语句改进性能。下面介绍技巧。
2. 使用where子句过滤行
检索表中所有行是非常浪费的,用where子句,检索那些需要的行。
3. 使用表连接而不是多个查询
多个相关表中检索数据时,执行表连接比使用多个多个查询效率更高。
查询中必须选择连接顺序,将行较少的表连接到后面。比如,要连接3个相关表tab1、tab2和tab3.假设tab1有1000行,tab2有100行,tab3有10行。首先应将tab2连接到tab1上,接着是tab2和tab3。
查询中应避免复杂的视图,因为这样会导致查询中首先执行的是视图,然后才是实际查询。相反地,使用表而不是视图编写查询。
4. 执行连接时使用完全限定的列引用
在查询中包含表别名,并为查询所引用的每列显示指定合适的别名(这称为完全限定的列引用)。这样,数据库不需要搜索查询所使用的表的每列。
上面的这个例子是可以运行,但是数据库不知道gskyrq、jyxm、zcdz是哪张表中,于是要搜索这两张表以后获得这三列,从而为了搜索浪费时间。下面是一个指定列的例子,不会为了搜索列名而浪费时间。
5. 使用case表达式而不是多个查询
当需要对一个表的相同行执行许多计算时,使用case表达式而不是多个查询。
Bad:用多个查询实现同行多次计算
  select count(1) csbh from nsr_zg_nsrxx n where n.djlx_dm = '0104';
  select count(1) fsbh from nsr_zg_nsrxx n where n.djlx_dm <> '0104';
  select count(1) syh from nsr_zg_nsrxx n where n.djlx_dm = '0104';
Good:通过case when 是同行多次查询
select count(case
              when n.djlx_dm = '0104' then
                1
              else
                null
            end) csbh,
      count(case
              when n.djlx_dm <> '0104' then
                1
              else
                null
            end) fsbh,
      count(1) syh
  from nsr_zg_nsrxx n;
注意:
当然,CASE表达式中可以使用重叠的范围和不同的函数。
6. 添加表索引
一般地,从一个包含许多行的表中检索少数行时,只需要为一列建立一个索引。一个成功的经验是,当单个查询检索的行数不大于表总行数的10%时,建立索引是有效的。这意味着索引的候选列应该用于存储范围广泛的值。好的索引候选列应该是对于每个记录包含惟一数字的列,差的索引候选列是只包含小范围数字代码的列,比如1,2,3或4。Oracle数据库自动为表的主键和包含在惟一约束中的列创建索引。
而且,当执行分级查询时,应该为start with和connect by 子句所引用的列添加索引。
7. 使用WHERE而不是HAVING
WHERE子句用于过滤行;HAVING子句用于过滤行组。因为行被分组之后(这需要一定时间),HAVING才可以过滤行组,所以应该尽量使用WHERE子句过滤行。这样首先避免了花费时间去分组已过滤的行。
Bad:Having的例子
select n.nsrsbh
  from nsr_zg_nsrxx n
having n.nsrsbh in ('642103198211191647', '640222197511050326')
group by n.nsrsbh;
Good:WHERE 子句过滤行
select n.nsrsbh
  from nsr_zg_nsrxx n
where n.nsrsbh in ('642103198211191647', '640222197511050326');
8. 使用UNION ALL 而不是UNION
UNION ALL 用于获得两个查询检索到的所有行,包括重复行;UNION用于获得查询检索到的所有不重复行。因为UNION删除了重复行(这需要一定时间),所以尽量使用UNION ALL。
9. 使用EXISTS 而不是 IN
IN用于检查一个值是否包含在列表中。EXISTS与IN不同:EXISTS只检查行的存在性,而IN检查实际的值。在子查询中,EXISTS提供的性能通常比IN提供的性能要好。因此,应该尽量使用EXISTS而不是IN。
Bad:IN而不是EXISTS
select kz.gskyrq,kz.jyxm,kz.zcdz
  from nsr_zg_nsrkzxx kz
where kz.nsr_id in
      (select n.id
          from nsr_zg_nsrxx n
        where n.nsrsbh in ('642103198211191647', '640222197511050326'));
Good:EXISTS提供性能
select kz.gskyrq, kz.jyxm, kz.zcdz
  from nsr_zg_nsrkzxx kz
wheresql优化的几种方式 exists
(select 1
          from nsr_zg_nsrxx n
        where kz.nsr_id = n.id
          and n.nsrsbh in ('642103198211191647', '640222197511050326'));
10. 使用EXISTS 而不是DISTINCT
DISTINCT用于禁止重复行的显示;EXISTS用于检查子查询返回的行的存在性。尽量使用EXISTS而不是DISTINCT,因为DISTINCT在禁止重复行之前要排序检索到行。
11. 使用绑定变量
Oracle数据库软件缓存已经执行的SQL语句;如果以后执行相同的语句,就复用缓存语句。复用语句会减少执行时间。但是,有一个规则:要复用缓存语句,SQL语句必须绝对相同。这表示:
所有字符必须相同
所有字母的大小写必须相同
语句中所使用的空格必须相同
如果需要在语句中提供不同的列值,可以使用绑定变量,而不是常量列值。
a) 不相同的sql语句
使用单独不相同的select检索条件
select * from nsr_zg_nsrxx n where n.id = 1;
select * from nsr_zg_nsrxx n where n.id = 2;
空格位置不同
select * from  nsr_zg_nsrxx n where n.id = 1;
select * from nsr_zg_nsrxx n where n.id = 1;
大小写不一样
select * from nsr_zg_nsrxx n where n.id = 1;
SELECT * FROM nsr_zg_nsrxx n where n.id = 1;
oracle 中,对于一个提交的sql语句,存在两种可选的解析过程, 一种叫做硬解析,一种叫做软解析.一个硬解析需要经解析,制定执行路径,优化访问计划等许多的步骤.硬解释不仅仅耗费大量的cpu,更重要的是会占据重要的们闩(latch)资源,严重的影响系统的规模的扩大(即限制了系统的并发行), 而且引起的问题不能通过增加内存条和cpu的数量来解决。之所以这样是因为门闩是为了顺序访问以及修改一些内存区域而设置的,这些内存区域是不能被同时修改。当一个sql语句提交后,oracle会首先检查一下共享缓冲池(shared pool)里有没有与之完全相同的语句,如果有的话只须执行软分析即可,否则就得进行硬分析。 而唯一使得oracle 能够重复利用执行计划的方法就是采用绑定变量。绑定变量的实
质就是用于替代sql语句中的常量的替代变量。绑定变量能够使得每次提交的sql语句都完全一样。
普通sql语句:
SELECT fname, lname, pcode FROM cust WHERE id = 674;
SELECT fname, lname, pcode FROM cust WHERE id = 234;
SELECT fname, lname, pcode FROM cust WHERE id = 332;
含绑定变量的sql 语句:
SELECT fname, lname, pcode FROM cust WHERE id = :cust_no;
 
Sql*plus 中使用绑定变量:
sql> variable x number;
sql> exec :x := 123;
sql> SELECT fname, lname, pcode FROM cust WHERE id = :x;
 
pl/sql
 pl/sql很多时候都会自动绑定变量而无需编程人员操心,即很多你写得sql语句都会自动利用绑定变量,如下例所示:
create or replace procedure dsal(p_empno in number)
as
  begin
    update emp
    set sal=sal*2
    where empno = p_empno;
    commit;
  end;
/
也许此时你会想要利用绑定变量来替代p_empno,但是这是完全没有必要的,因为在pl/sql中,引用变量即是引用绑定变量。
但是在pl/sql中动态sql并不是这样。
vbjava以及其他应用程序中都得显式地利用绑定变量。
对于绑定变量的支持不仅仅限于oracle,其他RDBMSSQLSERVER也支持这一特性。
但是并不是任何情况下都需要使用绑定变量, 下面是两种例外情况:
对于隔相当一段时间才执行一次的sql语句,这是利用绑定变量的好处会被不能有效利用优化器而抵消
数据仓库的情况下。
以下介绍几种情况:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。