能否用Delphi写大型的WebApp(WINCGI/IISCGI/SOAP),非高手莫进 ? (yysun老师在哪?)(0分)

  • 主题发起人 主题发起人 Rocklee
  • 开始时间 开始时间
顺便提提,我去过很多论坛,总觉得大富翁人气最旺,其他论坛,走进去,好像
一个人在太空漫步。
 
上面第一个 stored procedure 是我根据 4guysfromrolla.com 和 google 里检索到的
一些资料写出来的。第二个 cursor 的算法是我的一个俄国同事写的,我们正在生成1百万
条记录来看,那个效率好些。谢谢 Rocklee 的意见,我们可以增加一个测试项目就是 inner
join 的次序。那个 2 就是您想要的记录起始位置,当然是动态的。
李维先生的建议“尽量小的数量流量”、“客户端curror”都是对,但是如果用 +,
“尽量小的数量流量 + 客户端curror”,则可能互相矛盾。
(假设“尽量小的数量流量”是指 web 服务器和数据库服务器之间的数据流量而言)
就象 Rocklee 说的一次检索的结果可能上万条,如果用客户端curror,根本就是造成了
巨大的数据流量,以至于出现超时错误。只有用 stored preocedure 分好页后返回20条
或者100条,才能得到小的数据流量。所以要分析“小数据流量”前提下的需要哪些具体
手段,而不能加起来。
“异步索取模式”我不是很懂其含义。我们的体会是在一定数据量前提下,比如 10k,
连接服务器10次,每次1k 不如 连接服务器 1 次 的到 10k,因为初始化网络,建立通讯
通道的开销挺大的。有时候 ADO 很慢,因为它的 recordset 每次 movenext 都会去呼叫
一下服务器(用 socket 监视软件可看到)。如果在注册表什么地方,改个参数,设置
recordset 的 cache 为 10,即每 10 个 movenext 呼叫服务器一下,则感觉效率大大提高。
(上面提到的那个俄国同事做过试验)。
但是,这又违反了“小数据流量”的原则,因为需要得传过来被 cache 的 10 记录。
再但是,如果 SQL Server 和 IIS 在一台机器上、SQL Server 和 IIS 在不同的机器上、
IIS 在 Web farm 上、....... 还会有很多情况需要分析。
所以,结论就是参照这些原则的时候要做综合性能分析和负载平衡分析,不能死搬硬抄。
目前看来,web app 瓶颈还是在数据库设计上,与用 Delphi 或者 ASP 无关。
 
to yysun,
老师,你的技术却是值得佩服和学习。
问你个问题,现在dfw进入的时候和掉帖子的时候还是比较慢。
能不能在帖子尾部加一个时间显示,这样会知道是程序慢,数据库慢,还是网络慢了。
班门弄斧了:)
 
高手就是高手,果然不同凡响!!!
 
"尽可能少的数据量"就是指用您老的第2种方式得到嘛。
我所说的拉1万条记录,只是用来测试而已,如果真正用,就绝对不应该这样做。
异步索取模式就是executeoptions设为eoAsyncFetchNonBlocking,这样查询时介面不会出现
白屏,用户的感觉会好一点(我指的不是写web app,而是常用的c/s程序)。
你说得对,我讲漏一点,就是设好cachesize,李维先生推荐设为1000,他还给出各种值之间
执行速度的差别。
 
今天用100万条数据进行测试,证明我的方法比俄国人方法在 < 25000 页 (每页20)的情况
下更好(web app 大概不会有人翻 25000 页 [:D])。然后,俄国人想出了第三个方法,
统统输给它。下面是三个方法的 stored procedure,供大家参考。(inner join 的次序没有什么影响)
==========================================================
CREATE PROCEDURE usp_speed1
@nextid int, @counter int
AS
set nocount on
create table #t ( rid int )
declare AA insensitive scroll cursor for
select UserId from tblUser order by UserId for read only
open AA
fetch absolute @nextid from AA into @nextid
while @counter>0 begin
fetch next from AA into @nextid
if @@fetch_status=0 insert #t (rid) values (@nextid)
set @counter = @counter-1
end
close AA
deallocate AA
select rid as UserId from #t
GO
==========================================================
CREATE PROCEDURE usp_speed2
@PageNo int, @PageSize int
AS
SET NOCOUNT ON
CREATE TABLE #Temp (
Id int IDENTITY primary key,
rid int
)
declare @MaxGet int
set @MaxGet=@PageSize*@PageNo
SET ROWCOUNT @MaxGet;
INSERT INTO #Temp (rid) SELECT UserId FROM tblUser ORDER BY UserId
SELECT rid as UserId FROM #Temp
WHERE Id>@MaxGet-@PageSize
GO
==========================================================
CREATE PROCEDURE usp_speed3
@nextid int, @pagesize int
AS
set nocount on
declare @sql nvarchar(2000)
set @sql=N'select top '+convert(varchar(12),@pagesize)+
' UserId from tblUser where UserId not in (select top ' + convert(varchar(12),@nextid) +
' UserId from tblUser order by userId) order by userId'
exec sp_executesql @sql
GO
花些功夫在这种算法研究上是值得的。
我们总是觉得 VC++ 最快,于是用 VC++ 做了一大堆 COM但是,并没有发现效果上比
ASP 有多大差别,原来瓶颈就在 ADO 上。如果用 Delphi 调用 ADO,效果也一样。
弄到最后就是需要进去设置什么 cache size。
气得我们立即扔掉了 ASP + VC(COM) 的方案,转而使用 .NET。
您相信下面网页中关于 .NET, ASP+COM,以及 ISAPI 的 效率差别吗?
http://www.gotdotnet.com/team/compare/nileperf.aspx
 
关注!
你所指的"你的方法"是不是就是指currsor那种方法?
"俄国人想出了第三个方法,统统输给它"的"它"是指俄国人的方法还是你的方法?
我认为通用性和效率还是你那个currsor的方法最好.
还有,如果说ado是瓶颈是说不过去,ado只提供与前端程序的连接并提供若干方法与
属性以便程序员更方便程序员而已,如果ado设置得好,关键还是服务器端.
我认为如果连mssql, ado还是很好的,最起码比bde优秀.
 
抱歉没有说明白,上面的
usp_speed1 是俄国人的老方法(用 cursor),
usp_speed2 是我改进后的方法(用 identity),
usp_speed3 是俄国人的新方法(用 not in)。
可不能想当然,那个用 cursor 的办法不行的。下面是大致的测试结果 (1M记录,单位秒)
页码 usp_speed1 usp_speed2 usp_speed3
10 10 0. 0.
100 10 0. 0.
1000 10 0. 0.
10000 10 1. 0.
20000 10 7 1
200000 10 18 1
(0. 表示 <1 秒)
ADO 是瓶颈,因为整个系统的大部分运行时间化在 ADO 上。有机会给您自己测试一下就知道。
另外,我们用 rational purify 检测发现 ADO 2.6 的内存泄漏简直是惊人。
2.7 改进了很多,但是仍然不干净。所以运行 IIS 的服务器需要经常启动真是不希奇。
我们不用 BDE 不是 ADO 技术原因,其 SQL link 就比 ODBC 快。
主要是因为它的市场周期已经结束。此为另外的话题,又有很多故事。
 
yysun , 你别往我头上直浇冷水, 我的书可刚买了90多元!
那你说,BDE不好,ADO又漏油,那我们开发Delphi程序,该用什么连接后台数据库呢?
我所指的不是那个usp_speed2,而是你早先讲的第二个方法id:1143660。
俄国佬的新方法,如果我要写一个50行以上的SP,那该怎样写嘛, 动态写sql,再execute它?
我宁愿慢些!
而你的usp_speed2,我还是感受不到您老所表达的意思.
set @MaxGet=@PageSize*@PageNo
SET ROWCOUNT @MaxGet;
INSERT INTO #Temp (rid) SELECT UserId FROM tblUser ORDER BY UserId --为何全部记录放到临时表中?如果Userid有100万的记录呢?
SELECT rid as UserId FROM #Temp --为何全部加到#temp中,再利用自动增量的ID获得其内容?
WHERE Id>@MaxGet-@PageSize
所以我认为,这不是个完整的sp,也许只给出前半段,是吧。
而我所指你的第二个方法,如果fetch absolute 2 from AA into @nextid真的可以快速指向"2"的话,
应该速度非常快。


 
fetch absolute 是快,就算 fetch absolute 200000 都很快,
但是,问题是为了这个 fetch absolute,必须 open scroll cursor,即使 readonly。
100万条记录就是10秒,无论 fetch absolute 2 还是 200000,这个 10 都跑不了。
怕描述不清楚,源程序贴出来,让您 copy+paste 去自己试,
又怕您自己不愿意试验,我的实验结果贴了出来给您。
您自己不试不看,只是一味猜测,甚至猜想到:“这不是个完整的sp”,我无话可说了。
 
yysun:
不知是不是我没看明白,下面的方法不是比俄国人的第二种方法更简单也更快速吗?
CREATE PROCEDURE usp_speed3
@nextid int, @pagesize int
AS
set nocount on
declare @sql nvarchar(2000)
set @sql=N'select top '+convert(varchar(12),@pagesize)+
' UserId from tblUser where UserId >' + convert(varchar(12),@nextid) +
' order by userId'
exec sp_executesql @sql
GO
 
softdog 您的写法以来于 UserId,如果有条件以及有排序,就不行了。
例如 name like 'a%' order by name desc.
usp_speed3 的核心思想 not in 就能解决这个问题,这时的 sql 这应该为:
set @sql=N'select top '+convert(varchar(12),@pagesize)+
' UserId from tblUser where UserId not in (select top ' + convert(varchar(12),@nextid) +
' UserId from tblUser name like ''a%'' order by name desc) where name like ''a%'' order by name desc'
而 usp_speed2 则比较简单
INSERT INTO #Temp (rid) SELECT UserId FROM tblUser where name like 'a%' order by name desc
所以这里只要的是核心思想
usp_speed1 用 cursor: 不大好。
usp_speed2 用 temp table + identity。
usp_speed3 用 not in。
 
yysun问一个浅显的问题别笑话了啊。为什么这三种不同的核心会产生这么大的区别呢?
特别是usp_speed2 为什么不在原表上进行操作呢,而加了一个生成临时表的步骤?我们
做有一个直接在原表上操作的好象速度还挺快。
第一次与yysun大侠对话,说得不对还请原谅。
 
real_clq,大家讨论问题,不用客气。
本贴贴主的意思是担心如果数据库中有大量的数据,比如10000条数据,web app 该如何处理。
那么,我的建议就是用 stored procedure 的办法做分页,举了三个例子,并且给出了它们
在 1000000 条数据时,不同页码的执行时间比较。说明数据量大并不可怕,选择好的算法
是能够做 web app 的,无论 Delphi,ASP 还是 .NET、数据库端很重要。
那三个例子就是起这个说明作用,是编程思想的演示:
已知一个数据集的条件、每页记录数=20,页码=10,如何提取数据?
usp_speed1:选择符合条件的数据一个 cursor,用 fetch absolute 定位到 181(@nextid=180),循环得到 20 个数据。
usp_speed2:选择符合条件的数据的前 200 个(@MaxGet=20*10)到临时表,再取出 > 180 以后的数据。
usp_speed3:选择符合条件的数据 减去 其中前 180 个(@nextid=180)后的20个。
这样描述是否清楚些了?
第一个为什么慢呢?因为 open scroll cursor 会很慢。
第二个用了 top @MaxGet,小页码时快,页码越大越慢,但是 web app 不会允许 10000 页,
所以基本没有问题,而其特点是写法简单。为什么要用临时表和 IDENTITY 字段呢?因为,
按照条件选择数据后,例如 order by name 原始表的 id 不能用来作为记录号了。Get it?
第三个没有用 cursor 和临时表,一句 SQL 解决,所以快,但是这句 SQL 却比第二个方法
难写,得重复两次条件。见我上面写的 name like 'a%' order by name desc 的例子。
而当条件越来越复杂,例如“选择所有用户,要求其具有创建记录的权限”。这就需要多表连
接,用户 --M:M-- 用户组 --M:M-- 权限,牵涉到 4-5 个表。
tblUser join tblUserInGroup join tblUserGroup join tblUserGroupPrevillige ...
用第二、第三种编程思想该如何来编写您自己的 stored procedure 呢?
 
啊,yysun说得非常的清楚,谢谢!
 
yysun,你怎么说我没试呢,你的回答中,并没有下面解释我的疑问,难道我在你的程序摘要中的注释无看到?是不是您对我有偏见?
很抱歉,因为我本身工作很忙,所以并非所有sp都试,我只试自己认为有问题的sp,
比如INSERT INTO #Temp (rid) SELECT UserId FROM tblUser ORDER BY UserId
我就想知道你的用意,如果全部倒到一个Temp Table中,只是为了利用ID的IDENTITY
特性来得到顺序序列,我觉得非常没效率,我试验的效果也一样,所以才发出此疑问。
你的sp_speed2完整的代码:
CREATE PROCEDURE usp_speed2
@PageNo int, @PageSize int
AS
SET NOCOUNT ON
CREATE TABLE #Temp (
Id int IDENTITY primary key,
rid int
)
declare @MaxGet int
set @MaxGet=@PageSize*@PageNo
SET ROWCOUNT @MaxGet;
INSERT INTO #Temp (rid) SELECT UserId FROM tblUser ORDER BY UserId
SELECT rid as UserId FROM #Temp
WHERE Id>@MaxGet-@PageSize
GO
那个UserID想必就是tblUser的Key, 只得到User的ID,对我没什么用吧,难道就显示个ID给人家看吗?
一旦我想得到tblUser的其他资料,是否也要Join到tblUser中去?但代码中,你没写啊?
所以我说你可能没写完。
我说它没效率,也有别方面,如果我的Table并非只是一个Int型的UserID那么简单,而是几个Field组成,比如 Date+Jobnumber+Line是不是Temp Table中也须建那几个Field? 而INSERT INTO #Temp (rid)
SELECT UserId FROM tblUser ORDER BY UserId 这句,如果tblUser有许多记录,而Key又比较多
,那Temp table是会吃掉很大的内存。delphibbs论坛流程处理相对简单(想起我刚认识Delphibbs时,
觉得很有趣,接着自己学着用ASP+sql用了3天时间也写了一个让同事玩玩),可以用全部的心思放在
效率方面,但我们在企业系统中面对的常常要复杂的数据处理或查询,所定义的表也会复杂多,所以
用动态生成sql的方面根本不适用,代码以后也难以维护,而且我们的系统多是以C/S为主的GUI程序(抱歉,说到这里,已经
远离主题了),工作模式跟Web上完全不同,比如用户非要按Ctrl+end看最后一只记录,是不是
SELECT rid as UserId FROM #Temp
WHERE Id>@MaxGet-@PageSize
这句就完全无用了,因为前面yysun您也说得很清楚,用户越要看后面的,这方法的效率就越低。
所以我个人认为,currsor的方法是最好(但听yysun你这么一说,我还要试试才知道)。
用currsor的方法,我是直观上认为很快,很抱歉,我是没试过,如果有空,我一定会试试。
在许多方面,我的观点跟yysun不同,我总结了一下,可能是我们所处的背境不同吧,yysun
是一版之主,可能站在Web开发的角度,而我是以企业的管理程序角度(主要是生产控制/效率计算和
计粮),有很多方面的差异。
还有,因为公司的电脑都是以通过y2k且能跑Netterm/(用来跟unix相联的Client)和普通程序为标准的瘦机,所以我必须编程时要考虑其效率和资源损耗,所以会提出这么多疑问。
因为我的目的是讨论技术嘛,心中如果有疑问,当然要说,如果我觉得您老的程序有问题,
也会说出来的嘛,你说不是吗?
请不要见怪。
我还想在这里呆下去,别轰我走。
 
Rocklee,“别轰我走。”从何说起?很高兴大家能深入地讨论问题。
大家都充分进入了问题,个人有自己的思考和理解,因而有所争论,是好事情,
比要一段程序就走人不知道要好多少,这里完全不存在“偏见”什么的。
否则,大家都很忙,何必打怎么多的字进来。
> yysun 是一版之主,可能站在Web开发的角度,而我是以企业的管理程序角度
此话说得好象......,老兄怎么忘记这个贴子的标题是: ...WebApp...
上面 id=1164754 的回贴,我已经尽可能详细地解释了您和其他人的疑问。
有机会试验一下全部的程序、验证我的解释、并思考我在那贴最后留下的思考题吧。
 
作为小虫,本人十分佩服各位大侠,本人是新手,一定好好努力,看来delphi很有前途吗:)
另:建议Rocklee以后标题不要这么伤人自尊,看看yysun多么谦虚!
对于yysun,我很佩服!!!
 
cjh_xf 说得对,
向yysun致敬!
 
后退
顶部