我的难题之一:如何计算一个SQL查询语句的效率?(100分)

  • 主题发起人 主题发起人 wddelphi
  • 开始时间 开始时间
W

wddelphi

Unregistered / Unconfirmed
GUEST, unregistred user!
有时写存取数据的程序时,可以写一个包含了多个子查询的复杂select语句,包括使用
“参考外部数据”、“参考内部数据”等方法,可以将一个复杂的表格用一次查询取出,
但这样的select语句的效率怎么计算呢?就像书上说“参考外部数据”、“参考内部数据”
的效率比较低,但有时用“参考外部数据”、“参考内部数据”可以解决非常复杂的查询,
程序简单,但我又不希望程序的效率太低,所以:

一、怎么计算SQL语句的效率?
二、子查询对查询效率的影响有多少?如何计算?
 
你写以这样写
var i:integer;
begin
i:=gettickcount;
query1.close;
query1.sql.text:=.....
query1.open;
showmessage(inttostr(gettickcount-i));
end;
 
不会吧?用这种方法?计算一个算法的效率也用这种方法?[:(!]
 
呵,你觉得这样不行吗?
 
不好意思,我虽然水平不怎样,但我也知道,效率不应该是这样算出来的,就像windows
应用程序,第一次运行和第二次运行,速度显然是不同的,但程序却是一样的![:(!]
 
奇怪,第一次运行和第二次运行,为什么不同???
前提是,不要运行其它程序,开机后立刻执行你的程序。

其实,除非特别大型的数据库,或者特别复杂的运算,你没有必要太在意效率。
当然,代码也不要写的太烂。基本上运行起来差别不大。
代码的可维护,健壮性才是最重要的。
 
我没说清楚,应该是“第一次运行和第二次运行的启动速度不同”,用 天真 的方法测,
效率岂不是不同?wukw,在一个查询中用了多个子查询,这个查询的效率会明显下降的,
而且和数据量成正比,但是如果不用子查询,就要进行多次查询(即用前一个查询的结果,
再查询出其它数据,也就是把子查询从整个查询这拆出来),那么一个是“一条包含了多个
子查询的复杂查询”,另一个是“拆开的多个简单查询”,它们的效率怎么计算?我觉得,
“一条包含了多个子查询的复杂查询”的效率应该不等于“拆开的多个简单查询”的效率,
谁来回答我?
 
当然,第一次启动还有连接数据库的时间,所以呢,
你要测试要分两个测试的
 
我要一个方法!
 
http://delphi.mychangshu.com/dispdoc.asp?id=874
http://delphi.mychangshu.com/dispdoc.asp?id=877
 
用专门的工具来测试吧,
楼上的萧大虾发过这种贴子的.
 
其实一条select语句两次查询的速度也是不同的,因为我以前是在foxpro 2.5 for dos下
学SQL语句的,foxpro有个功能,可以显示出每条语句执行的速度,我发现,同一条SQL语
句,第一次执行的速度,总要比之后运行的慢好多!

多谢 萧月禾 ,我正在用。

有谁能讲一下怎样分析SQL的效率,我想了解一下这方面的理论,谢谢!
 
to wddelphi 很多问题一一道来:
怎么测速度,要除去连接数据库的时间,只能你自己想办法。
效率究竟怎样?时间是检验真理的唯一标准。随着数据库记录多少的不同,数据类型的不同,各种优化方法不一样。
我同意你的“查询的效率会明显下降的”,我的意思是说如果得到结果,如果需要1秒和 0.1秒是没有区别的。
或者要花费30分钟和35分钟也是没有多大区别,多5分钟可以忍受的。
但是1秒和10秒的区别是绝对不可以容忍的。
foxpro的现象,你不能推而广之,运行效率如何,要在公平的情况下决斗。
大家都是第一次运行,看看谁厉害?

还有与其这样泛泛而谈,不如请你把SQL语句贴出来,大家一起来看看。同时请贴出总记录数和数据类型。
另外,CSDN的栏目分的非常专,你可以到那里的“数据库基础”栏目发个帖子。那里有很多高手。
这里主要靠delphi程序员所掌握的数据库知识来解答你的问题,那些专门的数据库管理员是不会来这里的。
说了很多废话,其实我什么都不会,只是给你一点建议。

另外,我觉得你真的很有思考问题和管理的能力,长远来看,不要当一个程序员,往管理方面发展!
有好消息告诉我!为你高兴。
 
要我贴语句吗?好吧,下面这个是我3年前在一个程序中写的,其中的“##”是要用日期替换的,
但是我认为,即使贴出来也没有什么太大的意思,因为,还需要花更多的功夫解释表结构的设计
才能让各位能看明白,而我只是想知道,如何能计算出这些sql语句的效率(只要理论就行)。

这个sql语句在vb+access中可以运行,其中data表(主要数据表,还有些其它的辅助表),数据量
在200条记录以下,大约可以在5~10秒内完成(PⅡ233+win98+vb5+access97),而当数据量超过
500条时,大约要将近2分钟才能完成,更多就更加不得了。我这个人有个小毛病,总是喜欢用一个
sql语句尽可能地把一个要填入界面grid的所有数据查询出来,所以,就产生了下面这个效率低下
的庞然大物,而现在我想,如果把其中的子查询拆出来,执行,可能效率会提高不少。

SELECT zb.bh AS id,zb.ssd,(select a2.data from data a2,zb_private zb1 where a2.zdbh=a1.zdbh and zb1.bh like a2.zdbh+'*' and a2.data<>0 and a2.zdlb='8' and Year(a2.date)=Year(##)-0 AND Month(a2.date)=Month(##)) AS Dnow8,(select a2.data from data a2,zb_private zb1 where a2.zdbh=a1.zdbh and zb1.bh like a2.zdbh+'*' and a2.data<>0 and a2.zdlb='7' and Year(a2.date)=Year(##)-0 AND Month(a2.date)=Month(##)) AS Dnow7,(select a2.data from data a2,zb_private zb1 where a2.zdbh=a1.zdbh and zb1.bh like a2.zdbh+'*' and a2.data<>0 and a2.zdlb='0' and Year(a2.date)=Year(##)-0 AND Month(a2.date)=Month(##)) AS Dnow0,Switch(zb.ssd='PJS',(select sum(a2.data) from data a2,zb_private zb1 where a2.zdbh=a1.zdbh and zb1.bh like a2.zdbh+'*' and a2.data<>0 and a2.zdlb='0' and Year(a2.date)=Year(##)-0 AND Month(a2.date)<=Month(##))/iif((select count(a2.data) from data a2,zb_private zb1 where a2.zdbh=a1.zdbh and zb1.bh like a2.zdbh+'*' and a2.data<>0 and a2.zdlb='0' and Year(a2.date)=Year(##)-0 AND Month(a2.date)<=Month(##))=0,1,(select count(a2.data) from data a2,zb_private zb1 where a2.zdbh=a1.zdbh and zb1.bh like a2.zdbh+'*' and a2.data<>0 and a2.zdlb='0' and Year(a2.date)=Year(##)-0 AND Month(a2.date)<=Month(##))),zb.ssd='SQS',(select sum(a2.data) from data a2,zb_private zb1 where a2.zdbh=a1.zdbh and zb1.bh like a2.zdbh+'*' and a2.data<>0 and a2.zdlb='0' and Year(a2.date)=Year(##)-0 AND Month(a2.date)<=Month(##)),zb.ssd='SDS','') AS p0J,(select a2.data from data a2,zb_private zb1 where a2.zdbh=a1.zdbh and zb1.bh like a2.zdbh+'*' and a2.data<>0 and a2.zdlb='0' and Year(a2.date)=Year(##)-1 AND Month(a2.date)=Month(##)) AS Dnow0Q,Switch(zb.ssd='PJS',(select sum(a2.data) from data a2,zb_private zb1 where a2.zdbh=a1.zdbh and zb1.bh like a2.zdbh+'*' and a2.data<>0 and a2.zdlb='0' and Year(a2.date)=Year(##)-1 AND Month(a2.date)<=Month(##))/iif((select count(a2.data) from data a2,zb_private zb1 where a2.zdbh=a1.zdbh and zb1.bh like a2.zdbh+'*' and a2.data<>0 and a2.zdlb='0' and Year(a2.date)=Year(##)-1 AND Month(a2.date)<=Month(##))=0,1,(select count(a2.data) from data a2,zb_private zb1 where a2.zdbh=a1.zdbh and zb1.bh like a2.zdbh+'*' and a2.data<>0 and a2.zdlb='0' and Year(a2.date)=Year(##)-1 AND Month(a2.date)<=Month(##))),zb.ssd='SQS',(select sum(a2.data) from data a2,zb_private zb1 where a2.zdbh=a1.zdbh and zb1.bh like a2.zdbh+'*' and a2.data<>0 and a2.zdlb='0' and Year(a2.date)=Year(##)-1 AND Month(a2.date)<=Month(##)),zb.ssd='SDS','') AS p0Q FROM data AS a1 Right Join zb_private AS zb On zb.bh like a1.zdbh+'*' WHERE zb.bh Like 'U2*' and val(mid(zb.bh,instr(instr(instr(zb.bh,'.')+1,zb.bh,'.')+1,zb.bh,'.')+1))<>'0' GROUP BY a1.zdbh,zb.bh, zb.ssd, zb.bh ORDER BY val(mid(zb.bh,instr(instr(instr(zb.bh,'.')+1,zb.bh,'.')+1,zb.bh,'.')+1));

而最近,我在编程时又遇到类似的问题,所以才提出来的,想听听大家有什么看法。

多谢wukw的夸奖,愧不敢当。
 
至于foxpro的现象,我觉得没有理由不能推而广之,因为我也是在看了《Foxpro 2.5 For Dos 提高篇》
中对SQL的详解篇后才熟悉起SQL语句的,其中说要慎用“参考外部数据”,因为其效率低,当时没有认
识,也没有体会,但在执行了上面的语句后,才有了深切的体会,上面的语句,正是用了“参考外部数据”
的查询,才能写出来的,也所以才效率低的!
所以,我觉得,虽然有很多不同的数据库系统,但遵守SQL标准的,其内核大致也是类似的吧。
 
天!拷成文本,占了整整大半个屏幕,大哥您自己研究吧。小弟实在无能为力。
反而倒是想请教大哥,慎用“参考外部数据”,是个什么意思?
外部数据是不是指并非数据库里的数据,而是从程序里读入的(比如手动输入的)?
第二次执行时速度快,是不是数据库内核里有缓存?把遍历的记录全都记了下了?或者偷偷建了索引(程序退出后删除)?
恳请指教!
 
“参考外部数据”指的是子查询里的查询条件使用外部查询语句中的数据,据个例子:

select a.f1,(select b.f1 from tableB as b where b.f1=a.f1) as f2 from tableA as a
~~~~~~~~~
“参考外部数据”其实很有用的,当然,上面的那个SQL是个反面典型,它实在是太庞大了,
数据库设计得也不合理,现在有时在一些较小的查询中也偶尔用“参考外部数据”,但是考虑到
它的效率低,用的时候总是很担心数据量大的时候性能上会怎样,如果有计算SQL语句效率的方法,
就可以判断了。

“参考内部数据”也是一样,就是外部查询使用子查询的数据,“慎用”也是书上说的,
原因我刚才说了,就是效率低,好像书上还补充说是“非常低”。
 
写错,应该:
select a.f1,(select b.f2 from tableB as b where b.f1=a.f1) as f2 from tableA as a
~~~~~~ ~~~~~~~~~
至于第二次执行快,我也不明白是为什么,可能就是你说的原因吧,因为我还记得,第二次
执行的速度通常是第一次的1/10,比如第一次0.7″,第二次就0.07″,效率提高这么多,大概
是暂存了以前的什么吧。
 
后退
顶部