CREATE TABLE [UserEdemaHeartProfitRanking](
[rId] [uniqueidentifier] NOT NULL CONSTRAINT [DF_UserEdemaHeartProfitRanking_rId]  DEFAULT (newid()),
[rUserId] [uniqueidentifier] NOT NULL,
[rMoney] [money] NOT NULL,
[rDate] [datetime] NOT NULL)此表数据大概有400万
要求统计出60天之内,赚钱比例最多,且数据条数大于60的Top 30用户ID, 其中rMoney>0 表示赚钱,rMoney<0表示出钱,为了精确的排序,我的Sql语句中把比例精确到了4位数。
rUserId,rDate都做了非聚集索引,rId是主键
SELECT TOP 30
        rUserId
FROM    ( SELECT    SUM(1) AS raceCount ,
                    CAST(CAST(SUM(CASE WHEN rMoney > 0 THEN 1
                                       ELSE 0
                                  END) AS DECIMAL) / CAST(SUM(1) AS DECIMAL) AS DECIMAL(10,
                                                              4)) AS userSeniority ,
                    rUserId
          FROM      dbo.UserEdemaHeartProfitRanking
          WHERE     DateDiff(d, rDate,getdate())<60
          GROUP BY  rUserId
        ) AS tempRank
WHERE   raceCount > 60
ORDER BY userSeniority DESC 这是我目前的语句,运行时间大概40s,因为有6、7个类似的统计。例如还要统计30天之内,条数大于30的,90天之内条数大于90的,等等。一次性跑完耗时就有5、6分钟了。放网站里面就超时了。另外表中的数据是可删减的,不一定只有增,求高手们的优化建议。

解决方案 »

  1.   

    视图能加快SQL的执行速度吗?不能吧?忘记说明了,最终查询出的结果是要update到用户表的
      

  2.   

    然后有一个现象,很奇怪,本来rDate字段是没有加非聚集索引的,然后我加上后执行起来飞快,5秒就完成了,过了2天后,速度又变回原样了。这几天数据量没大变化。
      

  3.   

    SELECT top 30 rUserId
      FROM dbo.UserEdemaHeartProfitRanking
      WHERE DateDiff(d, rDate,getdate())<60
      GROUP BY rUserId having  SUM(1)>60
      ORDER BY CAST(CAST(SUM(CASE WHEN rMoney > 0 THEN 1
                ELSE 0 END) AS DECIMAL) / CAST(SUM(1)) AS DECIMAL(10,
                 4))DESC 
      

  4.   

    SELECT top 30 rUserId
      FROM dbo.UserEdemaHeartProfitRanking
      WHERE DateDiff(d, rDate,getdate())<60
      GROUP BY rUserId having  count(*)>60
      ORDER BY CAST(SUM(CASE WHEN rMoney > 0 THEN 1
                        ELSE 0 END)*1.0/count(*)) AS DECIMAL(10,4))DESC 
      

  5.   

    嗯,省去了Cast as decimal 快了5秒
      

  6.   

    rdate的索引基本没有,你用了函数。可以考虑用临时表吧。
      

  7.   

    嗯,使用函数DateDiff(d, rDate,getdate())<60没能提升,我真正SQL里面是用 < 判断的。
      

  8.   


    ---这样试试?另外,你为什么还要精确到4位小数
    SELECT top 30 rUserId
      FROM dbo.UserEdemaHeartProfitRanking
      WHERE rDate between dateadd(day,-60,getdate()) and getdate() 
      GROUP BY rUserId having  count(*)>60
      ORDER BY SUM(CASE WHEN rMoney > 0 THEN 1
                        ELSE 0 END)*1.0/count(*)DESC 
      

  9.   

    SUM(CASE WHEN rMoney > 0 THEN 1
                        ELSE 0 END)*1.0/count(*)很精确了。
      

  10.   

    嗯,乘以1.0,这个想法很好,有了这个就可以省去所有的CAST的,提升了一些,但是6个基本相同的Update语句,每个现在是35秒左右了。加起来就是3分钟
      

  11.   

    你话都没说完,到底是查询还是修改--查出来得数据放到#tb临时表里,用临时表里的数据更新你的其他upadte语句吧
    SELECT top 30 rUserId into #tb
      FROM dbo.UserEdemaHeartProfitRanking
      WHERE rDate between dateadd(day,-60,getdate()) and getdate() 
      GROUP BY rUserId having  count(*)>60
      ORDER BY SUM(CASE WHEN rMoney > 0 THEN 1
                        ELSE 0 END)*1.0/count(*)DESC update tb 连接 #tb睡了,喝多了,有点晕
      

  12.   

    是把查询出来后的用户Update一下。