具体场景描述:
    比如,某网站有100万个会员,每个会员每个月都会在网站进行消费,每个月有且仅有一次消费,有专门的表存放这些消费记录。也就是说,在这个消费记录表里,每个月都会新增100万条记录。
    那么网站现在有一个需求:对这些会员的消费进行跟踪调查。具体描述:网站每年不定期根据行情设置一个消费金额上限和下限,网站统计每位会员当时的消费是否在当时的上限和下限之间,并将该统计结果存放在一张表中。(例如:网站在2007年1月10日,设置了一个上限和下限,在2008年3月5日,设置了一个新的上限和下限,那么网站会员在2008年3月4日的消费金额,统计结果参考2007年3月5日设置的上限和下限,而在2008年3月5日的消费金额,统计结果应该参考2008年3月5日新设置的上限和下限。)当然,我这里只是模拟一个环境,并不是在做传销。呵呵。
    我的思路是做增量存储,写一存储过程实现上面描述的需求,存储过程每天执行一次,只对每天新增的消费信息进行统计,不用每天都把N年的数据全部重新统计一次。没个月100万条的数据平均每天就3.3万条,这样数据库就轻松多了。再一个,我对会员信息表和消费信息表都创建了索引,这样在多表查询的时候也会提升速度。
    这样做只保证了统计走入正轨以后能统计得快一点,不能保证在第一次统计的时候就有很好的效率,因为第一次统计可能要统计1年的数据,那会员信息是100万条,而消费记录可能是1200万条,那一次统计的时候,还得判断该消费记录是按照哪个消费上限和下限统计,这个速度就是鬼速了。
    实际说明,我在统计的时候,存储过程都执行了3个小时了,统计表里才出现1万条记录,还是在服务器上跑。数据库是 oracle 10g。
    各位高手,能有好的解决方案么,解决存储过程在第一次执行的时候的效率太低的问题,如果能提高以后每次存储过程的执行效率也请指教。    唉,一个搞技术的,写这么多文字,我都觉得不爽,没办法,见谅。

解决方案 »

  1.   

    百万级数据两不算打,建好索引应该不会太慢,不要用视图太慢,在存储过程中处理数据的时候最好用rowid访问,我有体会,提高很多,另外提交的时候最好若干次提交一下,另外频繁处理表会导致索引和表存储结构混乱,经常分析一下索引,分析表会有明显效果
      

  2.   


    总的说来,你的建议确实可行,不过我有几个疑问:
    1. 如何用 rowid 访问?
        网站会员信息里有一个会员编号,这个是唯一的,这个字段也存放于消费信息表里,因为后期需求的需要,我还得把会员的身份证号也放到我的统计表里,也就是我用 rowid 访问消费记录表后,还得根据消费记录表的会员编号查询他的身份证号。这个身份证号是在开发后期加进去的,现在很苦恼,系统之所以慢,估计这里有一方面的原因。这是一方面,另一方面,我确实没使用过用 rowid 访问的方法,能指点指点么?2. 如何若干条提交一次?
        我现在就是一条一条的提交,你的建议不错,有没有具体思路?谢谢你的回答。
      

  3.   

    做个计数,满多少条才commit一次
    比如说5000条一次commit消耗的时间,实际上和一条一次commit差不多的
    但5000次一条一次是>5000条一次的
      

  4.   

    8.4不好的事务习惯
    许多开发人员在事务方面都有一些不好的习惯。如果开发人员使用过另外某个数据库,其中只是“支持”事务,而没有“提升”事务的使用,执行开发人员就常常有这样的一些坏习惯。例如,在Informix(默认设置)、Sybase和SQL Server中,必须显式地BEGIN(开始)一个事务;否则,每条单个的语句本身就是一个事务。Oracle在具体的语句外包了一个SAVEPOINT,采用类似的方式,那些数据库则在各条语句外包了一个BEGIN WORK/COMMIT或ROLLBACK。这是因为,在这些数据库中,锁是稀有资源,另外读取器会阻塞写入器,反之,写入器也会阻塞读取器。为了提高并发性,这些数据库希望你的事务越小越好,有时甚至会以数据完整性为代价来做到这一点。
    Oracle则采用了完全不同的方法。事务总是隐式的,没有办法“自动提交”事务,除非应用专门实现(更多详细内容请见8.4.2节)。在Oracle中, 每个事务都应该只在必要时才提交,而在此之前不能提交。事务的大小要根据需要而定。锁、阻塞等问题并不是决定事务大小的关键,数据完整性才是确定事务大小 的根本。锁不是稀有资源,并发的数据读取器和数据写入器之间不存在竞争问题。这样在数据库中就能有健壮的事务。这些事务不必很短,而要根据需求有足够长的 持续时间(但是不能不必要地太长)。事务不是为了方便计算机及其软件,而是为了保护你的数据。
    8.4.1在循环中提交
    如果交给你一个任务,要求更新多行,大多数程序员都会力图找出一种过程性方法,通过循环来完成这个任务,这样就能提交多行。据我听到的,这样做的两个主要原因是:
             频繁地提交大量小事务比处理和提交一个大事务更快,也更高效。
             没有足够的undo空间。
    这 两个结论都存在误导性。另外,如果提交得太过频繁,很容易让你陷入危险,倘若更新做到一半的时候失败了,这会使你的数据库处于一种“未知”的状态。要编写 一个过程从而在出现失败的情况下能平滑地重启动,这需要复杂的逻辑。到目前为止,最好的方法是按业务过程的要求以适当的频度提交,并且相应地设置undo段大小。
      

  5.   

    6. /*+ROWID(TABLE)*/
      提示明确表明对指定表根据ROWID进行访问.
      例如:
      SELECT /*+ROWID(BSEMPMS)*/ * FROM BSEMPMS WHERE ROWID>='AAAAAAAAAAAAAA'