性能问题:请高手为我排忧解难,在线恭候大驾光临

zhougang86 2008-08-19 10:08:52
CREATE procedure QueryACCP @StartTime datetime,@EndTime datetime
as
declare @STCD char(8)
declare @ACCP float
create table #Result(STCD CHAR(8) ,ACCP float)
declare STCDCursor cursor
for
select distinct STCD from ViewHourQuery where TM between @StartTime and @EndTime

open STCDCursor
while(0=0)
begin
fetch next from STCDCursor into @STCD
if(@@FETCH_STATUS<>0) BREAK
set @ACCP=dbo.TotalACCP(@STCD,@StartTime,@EndTime)
insert into #Result values(@STCD,@ACCP)
end
close STCDCursor
deallocate STCDCursor
select a.STCD,a.STNM,b.ADDVNM,c.ACCP from (ST_STBPRP_B a left outer join ST_ADDVCD_B B on a.ADDVCD=b.ADDVCD)inner join #Result c on a.STCD=c.STCD
drop table #Result

这是我写的存储过程,查询一段时间以内的各个站点的降雨量,STCD是站点号,ACCP是降雨量,最后连接2张表,投影STNM(站点名称),ADDVNM(站点所属城市名称)
TotalACCP函数是计算一个STCD的降雨量,里面用到了其他的几个函数
因为表中的记录不是连续的,有的没有进行统计,如某一天的记录没有,则调用NotExistDay求
NotExist1stXun(上旬记录没有)、NotExist2stXun(中旬记录没有)、NotExist3stXun(下旬记录没有)、NotExistMonth(月记录没有),计算的过程是:如果时间段跨月,则先在月表里去记录,该月记录不存在,则调用NotExistMonth求之,再在剩余的时间段里,够得上旬的则在旬表里取(旬分上、中、下),不够的则调用相应的函数求,再按同样的思路在天表里,最后在到时段表(给时间分段,取值再合计)
1.create function NotExistDay(@STCD CHAR(8),@Time datetime)---统计日降雨量函数
returns float
as
begin
declare @number float
set @number=0
select @number=isnull(sum(DRP),0)from ViewHourQuery where STCD=@STCD and TM between dateadd(dd,datediff(dd,0,@Time),0)and dateadd(ms,-3,dateadd(dd,datediff(dd,0,@Time),0))
return @number
end

其他的几个函数就不贴上来了,时段表记录有36万条,日表记录有18万条....
我现在是能求出相应站点在一个时间段内的降雨量了,但是性能太差了,360个站点要耗4分钟17秒,聚集索引也建立了,看看我的存储过程,能不能不写游标,游标很耗时间,我在执行计划里看了下,占34%(80多秒了),希望您能帮帮我!
...全文
141 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
zhougang86 2008-08-22
  • 打赏
  • 举报
回复
好了,现在搞定了,多亏了flairsky的帮助:
批量过滤,过程如下:
先找出在月表中有记录的站点
select STCD,IDTM,ACCP into #Month from ViewMonthQuery where IDTM BETWEEN ** AND ** AND stcd IN
(SELECT DISTINCT stcd from ViewHourQuery where TM between ** and **)

再在上旬表记录塞选,在这个时间段有记录,并且月份不和表记录的月份相同
select STCD,IDTM ,ACCP INTO #1stXun from View1stXunQuery a where IDTM BETWEEN ** AND **
AND stcd IN (SELECT DISTINCT stcd from ViewHourQuery where TM between ** and **)
and not exists(select * from #Month b where a.STCD=b.STCD and datepart(yy,a.IDTM)=datepart(yy,b.IDTM)and datepart(mm,a.IDTM)=datepart(mm,b.IDTM))

其他类似,最后分组求和 select STCD,SUM(ACCP)as ACCP from ** group by STCD
zhougang86 2008-08-20
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 flairsky 的回复:]
引用 15 楼 zhougang86 的回复:
引用 13 楼 flairsky 的回复:
这样时间大概为(4*60+17)/90

10秒以内
[/Quote]
帅哥,帮我再看下,我现在的思路可有问题了:
我先创建一个临时表table1(tablename char(16),querytime datetime)用来存储该从哪个表读取数据
如:查询ACCP=‘50100100’的站点在2008-4-1 8:00:00 到2008-4-23 6:00:00的降雨量
判断后得到临时表table1的数据是:
tablename querytime
View1stXunQuery 2008.4 (上旬)
view2stXunQuery 2008.4 (中旬)
ViewDayQuery 2008-4-21
ViewDayQuery 2008-4-22
ViewDayQuery 2008-4-23
ViewhourQuery 2008-4-23
这样取数据的次数是少了,可是我每次还得判断记录存不存在(从表里扫描,要很多次)
select @total=@total+isnull(sum(ACCP),0) from dbo.View1stXunQuery a where STCD=@STCD and
exists
(select * from #QueryTable b where b.Tablename='View1stXunQuery' and datepart(yy,b.QueryTime)=datepart(yy,a.IDTM) AND DATEPART(mm,b.QueryTime)=datepart(mm,a.IDTM)

)

最后再这样读数据(相关子查询),看看可有什么好的方法啊

flairsky 2008-08-19
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 zhougang86 的回复:]
引用 13 楼 flairsky 的回复:
这样时间大概为(4*60+17)/90

10秒以内

这个是怎么估算的,我看不懂
[/Quote]

这个,你做完我再说
flairsky 2008-08-19
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 zhougang86 的回复:]
引用 12 楼 flairsky 的回复:
这个架构是好的

问题是游标+函数=遍历函数,问题大咯,你每做次统计,就是扫描一次某级别的表,360个站点,扫描表360次!

我认为,你需要先判断,而不是判断一个做一次统计

先判断每个站点在哪个级别能找到相应数据,然后同级别做一次统计,最后结果union all,这样你只要扫描(级别数)次表

我说清楚了没?


我知道了,我现在也在往这方面考虑,尽可能的减少读取表次数,可真不好判…
[/Quote]

你总要判断的,是不?
归类后再查
zhougang86 2008-08-19
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 flairsky 的回复:]
这样时间大概为(4*60+17)/90

10秒以内
[/Quote]
这个是怎么估算的,我看不懂
zhougang86 2008-08-19
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 flairsky 的回复:]
这个架构是好的

问题是游标+函数=遍历函数,问题大咯,你每做次统计,就是扫描一次某级别的表,360个站点,扫描表360次!

我认为,你需要先判断,而不是判断一个做一次统计

先判断每个站点在哪个级别能找到相应数据,然后同级别做一次统计,最后结果union all,这样你只要扫描(级别数)次表

我说清楚了没?
[/Quote]

我知道了,我现在也在往这方面考虑,尽可能的减少读取表次数,可真不好判断啊,对一个时间段进行分段讨论:夸月就在月表记录里查,旬则在旬表记录里查(旬还分上、中、下),其他类似,麻烦的是我还得逐一判断这些记录存不存在,期望到最后最多是在月、旬、日、时段表里面各取一次记录。你给我提议很好,真是我所想的,我努力朝这个方向去做
flairsky 2008-08-19
  • 打赏
  • 举报
回复
这样时间大概为(4*60+17)/90

10秒以内
flairsky 2008-08-19
  • 打赏
  • 举报
回复
这个架构是好的

问题是游标+函数=遍历函数,问题大咯,你每做次统计,就是扫描一次某级别的表,360个站点,扫描表360次!

我认为,你需要先判断,而不是判断一个做一次统计

先判断每个站点在哪个级别能找到相应数据,然后同级别做一次统计,最后结果union all,这样你只要扫描(级别数)次表

我说清楚了没?



zhougang86 2008-08-19
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 sdxiong 的回复:]

无语了,有快的方法不用,偏要用慢的。。。。

按你现在这样的写法,如果是有几千万的数据,不知要算多久了,恐怕到时泪水比算出来的雨水要多了,呵呵
[/Quote]

呵呵,是的啊,不过经理说他们以前写了一个功能一样的,500个站点只花17秒时间,我现在功能是实现了,现在优化就是我的目标,以前在学校里学的都是SQL入门,现在需求不一样了啊,我还得慢慢想啊
zhougang86 2008-08-19
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 sdxiong 的回复:]

无语了,有快的方法不用,偏要用慢的。。。。

按你现在这样的写法,如果是有几千万的数据,不知要算多久了,恐怕到时泪水比算出来的雨水要多了,呵呵
[/Quote]

呵呵,是的啊,不过经理说他们以前写了一个功能一样的,500个站点只花17秒时间,我现在功能是实现了,现在优化就是我的目标,以前在学校里学的都是SQL入门,现在需求不一样了啊,我还得慢慢想啊
zhougang86 2008-08-19
  • 打赏
  • 举报
回复
回复:184270428
这样不合任务的要求,没有分段取值,与本意相差甚远
sdxiong 2008-08-19
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 zhougang86 的回复:]
回复:sdxiong

我开始时也试过,的确是可以,而且才几秒钟,可是项目经理要我按任务要求做啊,我这个是学习任务!
[/Quote]


无语了,有快的方法不用,偏要用慢的。。。。

按你现在这样的写法,如果是有几千万的数据,不知要算多久了,恐怕到时泪水比算出来的雨水要多了,呵呵
184270428 2008-08-19
  • 打赏
  • 举报
回复
再试试这样:

CREATE procedure QueryACCP @StartTime datetime,@EndTime datetime
as
declare @STCD char(8)
declare @ACCP float
declare @Result table (STCD CHAR(8) primary key,ACCP float)
insert @Result
select
STCD,accp_new = isnull(sum(DRP),0)
from ViewHourQuery(index=idx_vq_tm)--这个你要建好 再建pk_stcd_tm比较一下用(index=pk_stcd_tm)
where
TM between @StartTime and @EndTime
group by
stcd

select a.STCD,a.STNM,b.ADDVNM,c.ACCP from
ST_STBPRP_B a(index=pk_ST_STBPRP_B_stcd)--如果可以,把stcd建成ST_STBPRP_B主键或聚集索引
inner join @Result c(index=pk_stcd_tm) on a.STCD=c.STCD
left outer join ST_ADDVCD_B B
on a.ADDVCD=b.ADDVCD



zhougang86 2008-08-19
  • 打赏
  • 举报
回复
回复:sdxiong

我开始时也试过,的确是可以,而且才几秒钟,可是项目经理要我按任务要求做啊,我这个是学习任务!
zhougang86 2008-08-19
  • 打赏
  • 举报
回复
回复:184270428
我也试过了去掉游标,执行后好象比原来有游标的还要慢很多
sdxiong 2008-08-19
  • 打赏
  • 举报
回复
才几十万的记录,取数为什么还要分日、旬、月呢,做一大堆的判断还不如把所有数再统计一次,楼主是把简单问题复杂化了


select b.stcd,b.stnm,c.addvnm,sum(a.drp)
from viewhourquery a
left join st_stbprp_b b on a.stcd=b.stcd
left join st_addvcd_b c on b.addvcd=c.addvcd
where a.tm >= dateadd(dd,datediff(dd,0,@Time),0) and a.tm < dateadd(dd,datediff(dd,0,@Time)+1,0)
group by b.stcd,b.stnm,c.addvnm


zhougang86 2008-08-19
  • 打赏
  • 举报
回复
怎么没有人帮帮我啊
184270428 2008-08-19
  • 打赏
  • 举报
回复
去掉cursor,看看会好一些不?
CREATE procedure QueryACCP @StartTime datetime,@EndTime datetime
as
declare @STCD char(8)
declare @ACCP float
declare @Result table (STCD CHAR(8) primary key,ACCP float)
insert @Result
select distinct
STCD,accp_new = dbo.TotalACCP(STCD,@StartTime,@EndTime)
from ViewHourQuery(index=idx_vq_tm)--这个你要建好
where
TM between @StartTime and @EndTime


select a.STCD,a.STNM,b.ADDVNM,c.ACCP from
(ST_STBPRP_B a left outer join ST_ADDVCD_B B on a.ADDVCD=b.ADDVCD)
inner join @Result c on a.STCD=c.STCD
水族杰纶 2008-08-19
  • 打赏
  • 举报
回复
help you up

22,210

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧