首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > SQL Server >

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

2012-12-15 
写了个存储过程,但查询很慢,请教大家优化建议如下: CREATE PROCEDURE Finallenergy @enddatetimechar(10),

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


 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。
大体思路就是这些,但是具体写能让查询更快些?
我不知道我表述清楚了没啊

热点排行