这是上一个问题的续集,
上个问题见:http://topic.csdn.net/u/20090603/11/ccd4d8c8-3343-4975-9f4d-95ca9839a84b.html
经过yangfuen637200高手的指点,已经能达到目的,但是该表每天的数据量都有20万多,如果统计的时间稍长,会造成查询特别慢,甚至要几十秒钟以上,我想问一下有没有什么方式能提高此查询的效率。谢谢。
select count(num),num from (
select count(userid ) Num ,userid  from table where to_char(date,'YYYY-MM-DD' )>2009-05-01  and to_char(date,'YYYY-MM-DD' )<'2009-06-01'
group by userid 
)a
group by num 

解决方案 »

  1.   

    其实这个问题也不难,
    你要找到正确的方法,首先一个SQL随着数据量的增大,一定会越来越慢,
    我想你应该换种问题的解决方法,如果是我我会这样做:创建一个表,记录每个月每个用户访问的数量,
    表字段: 日期,用户,访问数量然后做个定时执行,每天凌晨1点,统计昨天的用户访问数量,毕竟一天的数量不会很多,
    把结果累计出来。以后每次都使用这个统计表进行统计分析。又快又好。
    程序死的,人是活的,换换实现方法,能够更快解决问题。
      

  2.   


     userid字段 重建索引,试试看,毕竟你的sql语句已经很简练了!
      

  3.   

    谢谢楼上的老兄,你说的方法,我这个程序还不能用,因为数据库里记录的就是每天访问的id,一个id无论上线几次,只记录一次
    所以每天的表都是20万个不同的userid,就这一天来说已经无法再继续统计了。
    这个表是为了统计一段时间以来,用户上线的频度情况,如看有多少用户天天上线,连续两天上线的有多少,连续三天。。
    我觉得貌似除了用这个sql,没有什么更好的方法了。
      

  4.   

    用并行 /*+parallel(tbname)*/select count(num),num from ( 
    select count(userid ) Num ,userid  from table where to_char(date,'YYYY-MM-DD' )>2009-05-01  and to_char(date,'YYYY-MM-DD' ) <'2009-06-01' 
    group by userid 
    )a 
    group by num 
      

  5.   

    给你写个优化的地方
    where to_char(date,'YYYY-MM-DD' )>2009-05-01  and to_char(date,'YYYY-MM-DD' ) <'2009-06-01' 
    这是一个很常见的关于日期类筛选的简化写法
    可以说是个偷懒写法
    却是最常见影响效率的根源首先一般如果条件经常会用到日期来做筛选,并且字段是DATE型,一般都会做索引
    而你用TO_CHAR的写法就会使语句不使用索引
    在查询数据量占总数据量不大的情况下,会明显降低效率
    尤其是你的数据量庞大时,差别至少是数十倍的
      

  6.   

    对于这个问题,我就发现过我同时为写SQL时少打几个字,而喜欢用TO_CHAR的写法
    对此我专做了测试,把测试纪录发邮件给他们
    要求所有有日期条件的,全部用to_date来实现,不要因为to_date要多打几个字而牺牲性能
    这两者的影响只要你所要查的数据量占全表的百分比很大时,才会是差不多的,否则的话,会相差很大的
    尤其是你的全表数据很大,但要查询的数据可能只占全表的1%甚至更低时,两者的差别是非常明显的
      

  7.   

    关于你的这个统计语句的后续优化可以这样考虑
    1、确定语句层面无法再优化,像你现在的情况就是语句层可以再优化2、判断常用的条件时间段,根据这个建立分区3、如果这些还不能满足要求,而统计语句又是经常要做的,但不要求实时数据,就可以考虑每天做个日结表,每天0点用JOB把前一天的统计数据算好存到新表中,这样查询就会快的
      

  8.   

    这个问题的性能瓶颈主要在下面语句的红色字体部分:
    select count(num),num from ( 
    select count(userid ) Num ,userid  from table where to_char(date,'YYYY-MM-DD' )>2009-05-01  and to_char(date,'YYYY-MM-DD' ) <'2009-06-01' 
    group by userid 
    )a 
    group by num 要记住:
    在操作符号(如>或<)的左边,尽量不要使用函数。如果该表有20w条记录,那么你上面的sql语句中的to_char函数将要计算40w遍,如果有100w条记录,to_char就要计算200w遍,这样以来性能就肯定好不了。
      

  9.   


    通过应用来解决是一个不错的方法,不过这条sql本身也可以优化一下select count(num),num from (
    select count(userid ) Num ,userid  from table where to_char(date,'YYYY-MM-DD' )>2009-05-01  and to_char(date,'YYYY-MM-DD' )<'2009-06-01'
    group by userid 
    )a
    group by num 
    select count(num),num from (
    select count(userid ) Num ,userid  from table where date>to_date('2009-05-01', 'yyyy-mm-dd')  and date < to_date('2009-06-01','yyyy-mm-dd')
    group by userid 
    )a
    group by num 在date上建立index。