sql与PB程序的优化


下面内容从CSDN的一篇贴子中找到的。sql

我用过的一个优化方法是:当检索表和视图混合的查询时,若须要检索参数,且表与视图都可用于检索参数的话,应使用视图做检索条件,速度将有明显提高。数据库

另附两篇关于 pb 代码优化的网摘:express

优化你的 sql 和 dw编程

  1、处理 SQL 语句数组

  一、缓冲 SQL 语句 
  在应用程序中,有时须要反复调用同一组SQL语句,在这种状况下,能够经过在应用中为这些 SQL创建缓冲区来提升执行性能。在缺省状况下,SQL语句的缓冲区是关闭的,你能够经过以下语句打开它: 
  SQLCACHE = n 
  n 表示装入缓冲区的 SQL 语句数量(缺省为0)。
服务器

  例如: 
  dw_1.SetTransObject(sqlca) 
  SQLCA.dbParm = "SQLCache = 0" 
  dw_1.retrieve()
网络

  若是将上例的 "SQLCache = 0" 改成 "SQLCache = 25",此句的执行效率将提升五分之一左右。但应注意缓冲区的大小,不然也将影响程序执行的性能。编程语言

  注:此方法对用 ODBC 和 ORACLE 链接的数据库很是有效。ide

  二、捆绑变量函数

  请看下例:

  SQLCA.DBPARM = "DISABLEBIND=1" 
  INSERT INTO DA_DH VALUES("1","河南0") 
  INSERT INTO DA_DH VALUES("2","河南1") 
  INSERT INTO DA_DH VALUES("3","河南2") 
  INSERT INTO DA_DH VALUES("4","河南3") 
  INSERT INTO DA_DH VALUES("5","河南4") 
  INSERT INTO DA_DH VALUES("6","河南5")

  这里未使用捆绑变量,再插入时 PB 将从新处理每一个带有新值的SQL语句。

  若是将上例改成:

  SQLCA.DBPARM = "DISABLEBIND=0" 
  INSERT INTO DA_DH VALUES("1","河南0") 
  INSERT INTO DA_DH VALUES("2","河南1") 
  INSERT INTO DA_DH VALUES("3","河南2") 
  INSERT INTO DA_DH VALUES("4","河南3") 
  INSERT INTO DA_DH VALUES("5","河南4") 
  INSERT INTO DA_DH VALUES("6","河南5")

  则系统将把 INSERT 语句按以下格式进行处理: 
  INSERT INTO DA_DH VALUES(?,?) 
  其中 "?" 称为占位符。系统性能将有所加强。

  三、用数据窗口代替 SQL 语句

  一般,为了得到某些数据,采用数据窗口和 SQL 语句都是可行的,可是PB 对数据窗口和 SQL 语句采用不一样的处理机制,所以,具备不一样的效率。

  例:为里检索电话档案中的用户名,能够利用 SQL 语句,将全部的数据检索到一个多行编辑中,也能够检索到一个数据窗口中。

  若是使用第一种方法:

  首先定义一个游标: 
    DECLARE CUR CURSOR FOR 
    SELECT "DA_DH"."HM" 
    FROM "DA_DH";

  而后能够: 
    STRING stxt[],st 
    int li 
    open cur 
    do li = li + 1 
    fetch cur 
    into :stxt[li] ; 
    st=st+stxt[li] + "~r~n" 
    loop while stxt[li] <>"" 
    close cur; 
    mle_1.txt = st

  也可使用第二种方法:

  dw_1.settransobject(sqlca) 
  dw_1.retrieve()

  利用 POWERBUILDER PROFILER 工具进行检查,对比两种方法所需时间以下

  方法     所需时间 (百分之一秒) 
  SQL 语句   100.9857 
  数据窗口   49.0133

  因为数据窗口或DATASTORE使用了标准的内嵌代码,而不是由开发人员进行所有编码,同时编译执行的速度比解释执行的速度快的多,所以在开发过程当中应尽可能使用数据窗口和DATASTORE.即便是必须用SQL语句的时候,也应该尽可能将它们定义为存储过程(特别是在多用户的环境中),以提升应用程序的性能. 

  2、数据窗口的编程和执行

  数据窗口是PB最值得被称道的, 其具备以下特色: 
  1. 多种显示方式. 
  2. 多种编辑方式. 
  3. 使用方法简单. 
  4. 具备多种报表形式. 
  5. 可实现屏幕滚动. 
  6. 可实现数据的有效性校验. 
  7. 执行性能显著提升. 
  8. 编程工做变少. 
  9. 能够在数据窗口内部实现数据哭的更新.

  下面, 我将介绍一些用于提升数据窗口性能的技术.

  1. 减小链接数据库的次数

  连库操做是很是影响执行速度的操做. 所以在程序中,一旦与数据库链接后就应当尽可能保持与数据库的链接, 减小链接数据库的次数.PowerBuilder 提供里两个函数来创建数据窗口与事务对象的链接: 
  SetTrans() 
  SetTransObject()

  在程序中应当尽可能使用 SETTRANSOBJECT(), 由于SETTRANS() 函数在每次调用 RETRIEVE(), UPDATE() 等函数以后, 都要执行数据库的链接和断开操做.

  2. 下拉数据窗口与表的链接

  对于数据库服务器来讲, 表的链接操做是一项很是大的开销, 而 POWERBUILDER 提供的下拉数据窗口在某些状况下能够代替表的链接操做.例如, 为了在数据窗口上显示用户的电话号码和姓名:若是用表的链接的方法, 数据窗口对应的 SQL 语句应是这样的: 
  SELECT "DA_DH"."DHHM","DA_HTH"."DWM" 
  FROM "DA_HTH", "DA_DH" 
  WHERE ("DA_HTH"."DHHM"="DA_DH"."DHHM")

  一样的程序可用下拉数据窗口来完成, 这里再也不具体介绍.可是, 应当注意, 以上两种方法究竟哪种数据更快, 与表的结构, 表的数量, 链接的方法等均有关系, 应当具体分析.

  3. 共享数据

  在一个应用程序中, 某些数据须要频繁的使用, 若是在每次使用时都从数据库中进行检索, 则需占用大量的服务器资源和网络资源. 为了减小开销, 能够在客户端对这些数据只进行一次检索, 而后容许其它任务共享这些数据.

  例如, 若是有两个数据窗口, 都须要从第三方表中检索出用户的电话号码, 且此列用下拉数据窗口给出. 若是每次都对电话号码进行检索, 则性能较低. 所以, 能够单独创建一个关于电话号码的数据窗口. 在每次打开窗口时, 首先将电话号码检索到此数据窗口中, 而后另外两个数据窗口中关于电话号码的下拉数据窗口能够共享此数据窗口中的数据.

  在窗口的 OPEN 事件中编写以下程序: 
  dw_1.settransobject(sqlca) 
  dw_2.settransobject(sqlca) 
  dw_3.settransobject(sqlca) 
  // 检索 dw_1 
  dw_1.retrieve() 
  // 使 DW_2 的下拉数据窗口共享 DW_1 
  datawindowchild child1 
  dw_2.getchild('dhhm',child1) 
  child1.settransobject(sqlca) 
  dw_1.sharedata(child1) 
  // 使 DW_2 的下拉数据窗口共享 DW_1 
  datawindowchild child2 
  dw_3.getchild('dhhm',child2) 
  child2.settransobject(sqlca) 
  dw_1.sharedata(child1)

  使用这种方法, 避免了各个数据窗口间物理的拷贝数据, 所以减小了空间上的开销,提升了应用程序的综合性能.

  4. 数据窗口间数据的拷贝

  若是须要在数据窗口间共享数据, 应当尽可能使用 SHAREDATA() 函数, 可是, SHAREDATA() 函数并非物理地在数据窗口间拷贝数据, 若是在显示数据的同时, 还要对数据进行操做, 则须要进行数据的拷贝.

  例如, 要求将 DW_1 中选定的行拷贝到 DW_2 中:

  在窗口的 OPEN 事件中编程: 
  dw_1.settransobject(sqlca) 
  dw_2.settransobject(sqlca) 
  dw_1.retrieve()

  在数据窗口 DW_1 的 ROWFOCUSCHANGED 事件中编写下列程序: 
  long lr 
  lr = dw_1.selectrow(0,false) 
  lr = dw_1.getrow() 
  lr = dw_1.selectrow(lr,true)

  要完成从 DW_1 到 DW_2 的拷贝工做, 有两种方法:

  第一种:

  在按钮 "拷贝" 的 CLICKED 事件中编程 
  long lr 
  lr = dw_1.getselectedrow(0) 
  dw_1.rowscopy(lr,lr,primary!,dw_2,100,primary!)

  执行程序, 利用 POWERBUILDER PROFILER 得出所需时间为 1.7034(百分之一秒)

  第二种:

  在按钮 "拷贝" 的 CLICKED 事件中编程 
  dw_2.object.data = da_1.object.data.selected

  执行程序, 利用 POWERBUILDER PROFILER 得出所需时间为 0.8062(百分之一秒)

  5. 数据窗口属性的访问和修改

  A. 数据窗口属性的访问

  在程序中访问数据窗口的属性有下列几种方法:

  A1. 采用点表达式访问

  A2. 应用多个独立的 DESCRIBE() 函数访问

  A3. 只使用一个 DESCRIBE() 函数, 采用复合参数访问多个属性

  上面三中方法, 一般第一种方法最慢, 第三种方法最快.

  例如: 
  在窗口的 OPEN 事件中 
  DW_1.SETTRANSOBJECT(SQLCA) 
  DW_1.RETRIEVE()

  第一种方法:

  在检索按钮的 CLICKED 事件中编程. 
  string dx, dy, dh, dw 
  dx = dw_1.object.da_dh.x 
  dy = dw_1.object.da_dh.y 
  dx = dw_1.object.da_dh.height 
  dy = dw_1.object.da_dh.width 
  st_1.text =dx+","+dy+","+dh+","+dw 
   
  第二种方法:

  string dx, dy, dh, dw 
  dx=dw_1.describe("da_dh.x") 
  dx=dw_1.describe("da_dh.y") 
  dx=dw_1.describe("da_dh.height") 
  dx=dw_1.describe("da_dh.width") 
  st_1.text =dx+","+dy+","+dh+","+dw

  第三种方法:

  string dx, dy, dh, dw 
  st_1.text=dw_1.describe("da_dh.x" +& 
  "da_dh.y" +& 
  "da_dh.height" +& 
  "da_dh.width")

  实验证实, 第三种方法的速度是最快的. 可是程序的可读性最差.

  B. 数据窗口属性的修改

  在程序中修改数据窗口的属性有下列几种方法:

  A1. 采用点表达式修改

  A2. 应用多个独立的 MODIFY() 函数访问

  A3. 只使用一个 MODIFY() 函数, 采用复合参数访问多个属性

  上面三种方法, 一般第一种方法最慢, 第三种方法最快.

  例如: 
  在窗口的 OPEN 事件中 
  DW_1.SETTRANSOBJECT(SQLCA) 
  DW_1.RETRIEVE()

  第一种方法:

  在检索按钮的 CLICKED 事件中编程. 
  DW_1.SETREDRAW(FALSE) 
  dw_1.object.da_dh.x = 18 
  dw_1.object.da_dh.y = 16 
  dw_1.object.da_dh.height = 100 
  dw_1.object.da_dh.width = 200 
  DW_1.setredraw(true) 
  st_1.text =dx+","+dy+","+dh+","+dw

  第二种方法:

  DW_1.SETREDRAW(FALSE) 
  dw_1.modify("da_dh.x = 18") 
  dw_1.modify("da_dh.y = 16") 
  dw_1.modify("da_dh.height = 100") 
  dw_1.modify("da_dh.width = 200") 
  dw_1.setredraw(true)

  第三种方法:

  dw_1.modify("da_dh.x=18" +& 
  "da_dh.y=16" +& 
  "da_dh.height=100" +& 
  "da_dh.width=200")

  实验证实, 第三种方法的速度是最快的. 可是程序的可读性最差.注意, 在方法一和方法二中, 都使用的 setredraw() 函数以减小屏幕的重绘, 不然, 执行速度将严重降低.


 6. 数据窗口中数据的访问

  在程序中, 常常会须要动态的修改数据窗口中的数据. 对此, PB 提供了多种方法, 各类方法在性能上会有一些差别.

  A. 数据窗口中数据的访问

  目的: 将数据窗口中的电话号码存放在一个数组中.请比较下面两中方法.

  方法一: 
  string da_dh[] 
  long ll,i 
  ll = dw_1.rowcount() 
  for i = ll to 1 stet -1 
  da_dh[i] = dw_1.getitemstring(i,"dhhm") 
  next

  方法二: 
  string da_dh[] 
  da_dh[] = dw_1.object.dhhm.current

  测试发现, 第二种方法比第一种方法快将近一倍. 数据量越大这种差别越明显.

  B. 数据窗口中数据的修改

  目的: 修改数据窗口中的电话号码列的值.

  请比较下面两中方法.

  方法一: 
  dw_1.setitem(i,"dhhm",l_name)

  方法二: 
  dw_1.object.name[i] = l_name

  测试发现, 第二种方法比第一种方法快将近一倍. 数据量越大这种差别越明显.

  7. 数据窗口事件对性能的影响

  对于数据窗口控制中常常发生的事件, 应当尽可能减小其中的程序代码. 特别是以下事件: 
  a. itemchanged 
  b. editchanged 
  c. itemfocuschanged 
  d. pbm_dwnkey 
  e. rowfocuschanged 
  f. retrieverow

  在这些事件中的任何处理程序, 都会下降应用程序的处理速度. 因此应当尽可能减小这些事件中的处理程序, 必要时, 能够考虑只将重要的代码放在这些事件中, 而将剩余的代码放在一个传递的事件中.

  例如,若是须要用到数据窗口的 ROWFOCUSCHANGED 事件,能够为数据窗口定义一用户事件 "UE_RE",而在数据窗口的 ROWFOCUSCHANGED 事件中写以下代码: 
  PARENT.postevent("ue_re")

  在 UE_RE 事件中再编写相应的程序代码,如: 
  string code 
  dw_1.selectrow(0,false) 
  dw_1.selectrow(rownum,true) 
  code = getitemstring(dw_1,rownum,"dhhm") 
  dw_2.retrieve(code)

  另外, 为了得到当前行号,应尽可能使用数据窗口的 CURRENTROW 变量,而少用 GETROW() 函数。

  8. 数据窗口的列名称与列编号

  对数据窗口的某列进行访问, 能够采用该列的名称, 也可使用该列的编号。

  例如: 
  采用列编号: 
  dw_1.object.data[ll_row,2] 
  dw_1.getitemstring(3,2)

  采用列名称表示某列: 
  dw_1.object.article_text[ll_row] 
  dw_1.getitemstring(3,"dhhm") 
  dw_1.setitem(3,"date",1999-03-31) 
  ... 
  
  对于以上两种方法,若是只进行一次查询,在速度上并无太大的区别,若是须要循环访问数据窗口上的某一列,则速度上的差别就表现的比较明显,采用第一种方法要快, 可是程序的可读性比较差。可是,在使用函数时(如 GETITEM() 和 setitem() ), 执行速度每每没有很大差异。

  9. 计算域

  数据窗口的计算域会对数据的操做性能产生影响。 若是数据窗口中包含许多复杂的计算域,将严重影响数据窗口的执行速度。


-----------------------------------------------------------------------------------------------


条件和循环类语句的优化

现今计算机的运行速度已经很快了,而且因为老板时常在耳边念着紧箍咒,所以,咱们有意或者无心的忘记优化咱们的代码,只要能完成任

务就好了(我也是)。不过,咱们闲下来的时候,不妨也来看看咱们的代码是否有须要改进的地方。下面就是我以为值得优化的几种状况。


第一种状况:

  IF condition1 AND condition2 THEN

      //Code goes here.

END IF

IF condition1 THEN

      IF condition2 THEN

            //Code goes here.

      END IF

END IF


对于书写的第一种方式,因为PB编译方式与常见的方式不一样,就是不管条件1的值如何,都要对条件2进行运算。这样一来,当条件1为false

时,就可能要无谓的对条件2进行运算了。就按随机的几率而言,可能会多进行一半的运算。所以,对于大多数状况而言,我想最好是以第二

种方式书写。固然,特殊状况也是有的,那就是你的确想对条件2进行运算。相似地,对于or也同样。


IF condition1 OR condition2 THEN

      //Code goes here.

END IF

IF condition1 THEN

      //Code goes here.

ELSE

      IF condition2 THEN

            //Code goes here.

      END IF

END IF 
  第二种状况:


IF NOT condition THEN

      //Code goes here.

END IF

IF condition THEN

      //No code goes here.

ELSE

      //Code goes here.

END IF


对于上一种方式,条件表达式返回false而且再进行一个非运算,才执行下面的代码。这样相对于下面一种书写方式可能多执行了一个非运算

。若是你们有什么疑问,您不妨测试一下下面这个例子:


//小测试:其中的判断条件只是为了表示一下,实际状况可能更复杂。


long i                  //计数器

long ll_start          //执行开始时间

long ll_used1      //方式一耗时

long ll_used2      //方式二耗时


//方式一

ll_start = Cpu()

for i = 1 to 900000

      if not (1 > 1) Then

            i = i

      end if

next       

ll_used1 = Cpu() - ll_start

//方式二

ll_start = Cpu()

for i = 1 to 900000

      if 1 > 1 Then

           

      else

            i = i

      end if

Next

ll_used2 = Cpu() - ll_start


//查看结果

If ll_used2 > ll_used1 Then

      MessageBox("提示","前者运行时间短!")

Else

      MessageBox("提示","后者运行时间短!")

End If


可能有人会说,用下面的那种方式,若是在条件表达式返回false的时候,那么,if下就没有代码,这样看起来就不太舒服。的确是这样。因

此,咱们在写成上面的那种方式时,尽可能保持不要使用not运算,而保持条件表达式自己就返回但愿的true值。

  第三种状况: 
IF condition1 THEN

      //condition1

ELSEIF condition2 THEN

      //condition2

ELSEIF condition3 THEN

      //condition3

ELSE

      //Other

END IF

choose case /*expression*/

      case /*item*/

            /*statementblock*/

      case /*item*/

            /*statementblock*/

      case else

            /*statementblock*/

end choose


对于形如这样的表达式,我想咱们通常都没去考虑前后顺序。可是,其实咱们应该把最可能发生的状况,放在前面,这样能够避免在对一大

堆条件进行判断后,才到咱们真正须要运行代码的地方。 
  

第四种状况:


 FOR ... TO ...

   

      IF condition THEN

            //true

      ELSE

            //false

      END IF

   

NEXT

IF condition THEN

      //true

      FOR ... TO ...

            //Code goes here

      NEXT

ELSE

      //false

      FOR ... TO ...

            //Code goes here

      NEXT

END IF


尽管下面这种书写方式,看起来好象代码多了一些,可是却极大的避免了在每一个循环中都进行条件判断。其实,一个原则就是,咱们应当尽

量避免在循环中进行条件判断,而是把条件判断放到循环体的外面进行。


其实,真正对于PB语言有特殊性的,也就是第一种状况,对于后面三种状况,对于别的编程语言,我想也一样适用。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xiongxiao/archive/2009/01/13/3764759.aspx

相关文章
相关标签/搜索