zoukankan      html  css  js  c++  java
  • 除非迫不得已不要用游标

            不管是sql server 还是 oracle都提供了游标,其一般用途就是从查询结构中遍历数据。游标很好用,许多初学oracle或者sql server的程序员都喜欢用,然而如果滥用游标的话,对程序的性能会造成很大的影响。我认为:除非不得已,不要使用游标。下面是我的一次优化经历。
    问题:
            在我们的系统中,需要管理产品模型,对PDM了解的人知道,其实产品模型可以当作一个特殊的零部件来处理,所以在数据表的时候产品模型与零部件使用相同的数据表来存放数据,只不过是用一个flag来标示是零部件还是产品模型。产品模型具有版本。现在的要求的是查出最新的所有的零部件信息,查询的时候允许用户自定义查询条件。
            用户自定义查询条件是从界面上通过各种选项来构造的,因此传递的是动态SQL语句,为了提高效率数据库上建立了一个存储过程专门来查询产品模型。下面是一个初学oracle不久的编程人员编写的存储过程:

     1PROCEDURE GETPRODMODELBYSQL(p_sql        IN VARCHAR2,                 
     2                               cur_mi_prodmodel OUT SYS_BASE.BASECURSOR) AS
     3   sqlstr varchar2(1000);
     4   idstr  varchar2(1000);
     5   
     6   
     7   dis_id number;
     8   maxver number;
     9        cursor disid_curs is
    10              select distinct pt_id
    11              from mi_part
    12              where pt_flag = 2;                               
    13   BEGIN
    14    open disid_curs;
    15         loop
    16             fetch disid_curs
    17             into dis_id;
    18             exit when disid_curs% notfound;
    19             
    20             select max(pv_id)
    21             into maxver
    22             from mi_partver
    23             where pv_partid = dis_id;
    24             
    25             if maxver is null then
    26                 idstr := idstr;
    27             else
    28                 idstr := idstr || maxver || ',';
    29             end if;
    30          end loop;
    31
    32          idstr  := rtrim(idstr, ',');
    33          idstr  := ltrim(idstr, ',');
    34          if idstr is null then
    35              sqlstr := p_sql || ' ORDER BY PV_PRODUCTID,PT_PARTNUMBER';
    36          else
    37              sqlstr := p_sql || ' and MI_PARTVER.pv_id in (' || idstr || ')  ORDER BY PV_PRODUCTID,PT_PARTNUMBER';
    38           end if;
    39
    40        open cur_mi_prodmodel for sqlstr;
    41   END GETPRODMODELBYSQL;

    这个存储过程可以正常工作,但是其速度执行起来非常慢,如果数据表中有很多数据的话,其速度很可能是直线下降,究其原因是因为使用游标来遍历然后构造查询语句。对这个存储过程进行优化:
     1PROCEDURE GETPRODMODELBYSQL(p_sql        IN VARCHAR2,                 
     2                               cur_mi_prodmodel OUT SYS_BASE.BASECURSOR) AS
     3   s varchar2(300);
     4   sqlstr varchar2(1000);
     5   /*idstr  varchar2(1000);
     6   
     7   
     8   dis_id number;
     9   maxver number;
    10        cursor disid_curs is
    11              select distinct pt_id
    12              from mi_part
    13              where pt_flag = 2;  */
                                 
    14   BEGIN
    15    /*open disid_curs;
    16         loop
    17             fetch disid_curs
    18             into dis_id;
    19             exit when disid_curs% notfound;
    20             
    21             select max(pv_id)
    22             into maxver
    23             from mi_partver
    24             where pv_partid = dis_id;
    25             
    26             if maxver is null then
    27                 idstr := idstr;
    28             else
    29                 idstr := idstr || maxver || ',';
    30             end if;
    31          end loop;*/

    32          s:=' and MI_PARTVER.pv_id in (select a.pv_id from mi_partver a,mi_part c where a.pv_partid = c.pt_id and c.pt_flag =2 and
    33a.pv_id in (select e.pv_id from mi_partver e
    34where e.pv_id in (select max(b.pv_id) from mi_partver b where e.pv_partid = b.pv_partid)))';
    35          /*idstr  := rtrim(idstr, ',');
    36          idstr  := ltrim(idstr, ',');
    37          if idstr is null then
    38              sqlstr := p_sql || ' ORDER BY PV_PRODUCTID,PT_PARTNUMBER';
    39          else
    40              sqlstr := p_sql || ' and MI_PARTVER.pv_id in (' || idstr || ')  ORDER BY PV_PRODUCTID,PT_PARTNUMBER';
    41           end if;*/

    42              sqlstr := p_sql || s ||  'ORDER BY PV_PRODUCTID,PT_PARTNUMBER';
    43        open cur_mi_prodmodel for sqlstr;
    44   END GETPRODMODELBYSQL;

    这里的有效语句是使用查询语句来构造查询,其结果是速度得到了数量级的提高,而且避免了一个隐患就是缓冲区溢出,因为原来的存储过程中定义了几个varchar2(1000)的变量,实际上这个变量的上界是不可以预期的,而缓冲区溢出也是很多初学oracle的程序员经常忽略甚至想不到的问题。
  • 相关阅读:
    Chrome应用商店打不开解决方法
    vue中的列表项删除操作
    markdown(语法)入门学习:
    利用插件(jQuery-ui.js)实现表格行的拖拽排序
    div拖拽互换位置(vue)
    MarkDown学习
    经典算法精讲精练之回溯法求解0-1背包问题
    读书笔记——《谁说菜鸟不会数据分析—Python篇》
    读书笔记之《统计之美:人工智能时代的科学思维》
    读书笔记之《漫画算法:小灰的算法之旅》
  • 原文地址:https://www.cnblogs.com/yanrongpi/p/583262.html
Copyright © 2011-2022 走看看