读书人

写了个存储过程但查询很慢优化建议

发布时间: 2012-12-15 15:16:03 作者: rapoo

写了个存储过程,但查询很慢,请教大家优化建议
如下:


CREATE PROCEDURE Finallenergy @enddatetime char(10),@sub char(10) AS
DECLARE @username varchar(50)
DECLARE @userid char(11)
DECLARE @moterid char(12)
DECLARE @strsinReadtime1 char(16)
DECLARE @fsinEnergy1 decimal(18,2)

IF not EXISTS (SELECT name FROM sysobjects
WHERE name ='Finalldianliang' )
begin
CREATE TABLE Finalldianliang (
[userid] [char] (11) COLLATE Chinese_PRC_CI_AS NOT NULL ,
[username] [varchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL ,
[moterid] [char] (12) COLLATE Chinese_PRC_CI_AS NOT NULL ,
[endengy] [decimal](18, 2) NULL,
[enddate] [char] (16) COLLATE Chinese_PRC_CI_AS NULL,
) ON [PRIMARY]
end

DECLARE userinfo CURSOR LOCAL FOR select username,userid,moterid from userprofile u,sub s where s.subid=u.sub and s.substation=@sub order by line,userid
OPEN userinfo
FETCH NEXT FROM userinfo INTO @username,@userid,@moterid
while(@@fetch_status = 0)
begin
set @strsinReadtime1=' '
set @fsinEnergy1=-1
select @strsinReadtime1=enddate,@fsinEnergy1=endengy from userdayengy where userid=@userid and moterid=@moterid and datetime=@enddatetime
if (@fsinEnergy1=-1) --如果没有,取前一天
begin
select @strsinReadtime1=enddate,@fsinEnergy1=endengy from userdayengy where userid=@userid and moterid=@moterid and datetime=dateadd(day,-1,@enddatetime)
end
if (@fsinEnergy1=-1) --如果没有,取后一天
begin
select @strsinReadtime1=enddate,@fsinEnergy1=endengy from userdayengy where userid=@userid and moterid=@moterid and datetime=dateadd(day,1,@enddatetime)
end
if (@fsinEnergy1=-1)
begin
set @enddatetime=@enddatetime+'-23-59'
end
if (@fsinEnergy1 != -1)
begin
insert into Finalldianliang (username,userid,moterid,enddate,endengy) values(@username,@userid,@moterid,@strsinReadtime1,@fsinEnergy1)
end
FETCH NEXT FROM userinfo INTO @username,@userid,@moterid
end
CLOSE userinfo
DEALLOCATE userinfo
GO

[最优解释]
不用游标的话速度最少提高几倍。
[其他解释]
 CREATE PROCEDURE Finallenergy
@enddatetime CHAR(10) ,
@sub CHAR(10)
AS
DECLARE @username VARCHAR(50)
DECLARE @userid CHAR(11)
DECLARE @moterid CHAR(12)
DECLARE @strsinReadtime1 CHAR(16)
DECLARE @fsinEnergy1 DECIMAL(18, 2)



IF NOT EXISTS ( SELECT name
FROM sysobjects
WHERE name = 'Finalldianliang' )
BEGIN
CREATE TABLE Finalldianliang
(
[userid] [char](11) COLLATE Chinese_PRC_CI_AS
NOT NULL ,
[username] [varchar](50) COLLATE Chinese_PRC_CI_AS
NOT NULL ,
[moterid] [char](12) COLLATE Chinese_PRC_CI_AS
NOT NULL ,
[endengy] [decimal](18, 2) NULL ,
[enddate] [char](16) COLLATE Chinese_PRC_CI_AS
NULL,
)
ON [PRIMARY]
END

DECLARE userinfo CURSOR LOCAL
FOR
SELECT username ,
userid ,
moterid
FROM userprofile u , --1 这个地方查询出来的数据行数,直接影响了LZ后面的循环,查看是否可用集合的方式处理
sub s
WHERE s.subid = u.sub
AND s.substation = @sub
ORDER BY line ,


userid
OPEN userinfo
FETCH NEXT FROM userinfo INTO @username, @userid, @moterid
WHILE ( @@fetch_status = 0 )
BEGIN
SET @strsinReadtime1 = ' '
SET @fsinEnergy1 = -1
SELECT @strsinReadtime1 = enddate ,
@fsinEnergy1 = endengy
FROM userdayengy
WHERE userid = @userid
AND moterid = @moterid
AND datetime = @enddatetime
IF ( @fsinEnergy1 = -1 ) --如果没有,取前一天
BEGIN
SELECT @strsinReadtime1 = enddate ,
@fsinEnergy1 = endengy
FROM userdayengy
WHERE userid = @userid
AND moterid = @moterid
AND datetime = DATEADD(day, -1, @enddatetime)
END
IF ( @fsinEnergy1 = -1 ) --如果没有,取后一天
BEGIN
SELECT @strsinReadtime1 = enddate ,
@fsinEnergy1 = endengy
FROM userdayengy
WHERE userid = @userid


AND moterid = @moterid
AND datetime = DATEADD(day, 1, @enddatetime)
END
IF ( @fsinEnergy1 = -1 )
BEGIN
SET @enddatetime = @enddatetime + '-23-59'
END
IF ( @fsinEnergy1 != -1 )
BEGIN
INSERT INTO Finalldianliang
( username ,
userid ,
moterid ,
enddate ,
endengy
)
VALUES ( @username ,
@userid ,
@moterid ,
@strsinReadtime1 ,
@fsinEnergy1
)
END
FETCH NEXT FROM userinfo INTO @username, @userid, @moterid


END
CLOSE userinfo
DEALLOCATE userinfo
GO


[其他解释]
引用:
SQL code12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394……

集合的方式?可以给举个例子吗?谢谢了
[其他解释]
引用:
不用游标的话速度最少提高几倍。

不用游标?那该怎么写啊
[其他解释]
你说说你这东西要干嘛的?瞄了一下,好像是嵌套循环的东西,用CTE基本上可以解决。
[其他解释]
引用:
你说说你这东西要干嘛的?瞄了一下,好像是嵌套循环的东西,用CTE基本上可以解决。

先根据电站信息sub从sub和userprofile表中得到userid,moterid,username信息(一个sub对应很对userid,moterid,username);然后依次根据userid和moterid,以及时间信息enddatetime从userdayengy中得到endengy和enddate。
简单说:先得到userid等信息,然后根据它们逐条查询表userdayengy,当然用户需要输入sub和enddatetime信息......
[其他解释]
从逻辑来说貌似完全没有必要用游标哦。一次性做不行吗?如果不行,给出表结构,少量测试数据,希望结果》。。。
[其他解释]
引用:
从逻辑来说貌似完全没有必要用游标哦。一次性做不行吗?如果不行,给出表结构,少量测试数据,希望结果》。。。

可是一起逐个的轮询userid,moteird,根据它们再去查表userdayengy,不用游标,我不知道怎么写?帮忙写个做法吧,谢谢啦
[其他解释]
表结构,少量数据,2、3条就够了。期望的结果。
[其他解释]
引用:
表结构,少量数据,2、3条就够了。期望的结果。

sub表结构:

userprofile结构:

userdayengy结构:


[其他解释]
引用:
表结构,少量数据,2、3条就够了。期望的结果。

sub表中subid和sub相关联
[其他解释]
你那个startdate什么数据?这么有创意的?
[其他解释]
引用:
你那个startdate什么数据?这么有创意的?

这条数据此次不用,是另外功能需要的,这次查询endengy和enddate就行了
[其他解释]
我不明白你为什么每一步都是逐条?你最终结果是啥?幻想不出来。给你造数据眼睛都花了
[其他解释]
引用:
我不明白你为什么每一步都是逐条?你最终结果是啥?幻想不出来。给你造数据眼睛都花了

可能我表达的麻烦了:
我给你详细说手:一个sub对应很多的userid和moterid,根据给出的sub名称(substation)根据表sub和userprofile我们可以找出表userprofile中的userid和moterid:

select userid,moterid from userprofile u,sub s where s.subid=u.sub and s.substation=sub order by line,userid

然后根据这些userid,moterid从表userdayengy中查询出endstate和endengy。
大体思路就是这些,但是具体写能让查询更快些?
我不知道我表述清楚了没啊

读书人网 >SQL Server

热点推荐