因为公司要保持上一个员工构建的系统结构--struct1+hibernate,让我接手这个项目,我第一次用起了HIBERNATE.算学学用
项目是一个日志收集与展现系统.每天要收集与展现的日志一张物理表就将近30W,每个元组平均900字节.用户要求保留3个月的数据
在线,差不多也就2000W吧. 数据库为ORACLE,数据的检索基本上要用到时间条件,我在时间上建了索引,并设为不可为空(防止全表扫描).
600W数据时我采用分区表了.在PL/SQLD执行,效果还不错.但连接到系统上,统计记录数这一步居然要几分钟,有时10几分钟.
因为我采用数据库分页,第一步就是统计符合条件的记录数.我感到不对了,很多人都在用HIBERNATE有这么差吗?
起初的代码是这样的(只粘了统计记录数这一步):
}
}
因为Criteria拼绑定SQL比较方便. 所以起初采用他.现在看别人都用HSQL,我想也别用Criteria 了,可能他的性能真的不行吧.
换:
}
这一下终于有了起色,快了很多,大功告成.然而问题又出现了.终计一天的数据时,起止时间都是'2009-10-15' ,结果居然为0,
逻辑错误肯定不允许.但库里明明有数据呀(ORACLE的DATE类型).把结束时间换成'2009-10-16'结果出来了.哦,到可能是
Hibernate.DATE只传了年月日部分.打开Hibernate源码:
}
不出所料'dd MMMM yyyy',没有时分秒.果然如此.怎么办呢,这时却有了意外收获,不好意思,时间紧文档看得少.
发现还有一个在Timestamp类型在旁边.CODE:
}
这不正是我要的吗.呵呵,换成 Hibernate.TIMESTAMP吧:
}
噩梦并没有结束,这时性能又降到刚开始的状态.为什么两个都不可用呢,查文档,也没找到可用信息.到底问题在哪儿.
通过ORACLE查看绑字信息:
从输出发现用Hibernate.Date时,绑字是Date类型,但时分秒都为0,明显不对.用Hibernate.TIMESTAMP时绑定的是
TIMESTAMP类型.但数据库类型是DATE,据我对ORACLE的理解,肯定是该字段的类型DATE发生了隐式类型转换,导致索引无效了.
验证(eventreportedtime 是DATE类型):
SQL> select * from stmmlog where eventreportedtime = cast(sysdate as timestamp)
2 /
未选定行
已用时间: 00: 06: 40.53
执行计划
----------------------------------------------------------
Plan hash value: 2651278941
--------------------------------------------------------------------------------
---------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
Pstart| Pstop |
--------------------------------------------------------------------------------
---------------
| 0 | SELECT STATEMENT | | 66490 | 55M| 321K (1)| 01:04:18 |
| |
| 1 | PARTITION RANGE ALL| | 66490 | 55M| 321K (1)| 01:04:18 |
1 | 9 |
|* 2 | TABLE ACCESS FULL | STMMLOG | 66490 | 55M| 321K (1)| 01:04:18 |
1 | 9 |
--------------------------------------------------------------------------------
---------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(INTERNAL_FUNCTION("EVENTREPORTEDTIME")=CAST(SYSDATE@! AS timestamp
))
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
1883117 consistent gets
1866294 physical reads
116 redo size
1482 bytes sent via SQL*Net to client
389 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
果真如此,PARTITION RANGE ALL,分区都是全扫描,无办法了,改TO_DATE吧,我最初放弃的(因为与数据库偶合),却是我的最终选择.
呵呵,有恋爱的感觉?
}
}
到这里问题算解决了,但是突然有些不明,HIBERNATE为什么没有作这方面的处理呢,对于大数据量的查询来说,时间索引没了,
结果将是致命的.因为为HIBERNATE不熟,如果仁兄看过这篇文章之后,有更好的方法.请留言.谢谢.