1、JDBC和Hibernate两者的查询效率谁会更优?
谈到这个问题,很多爱拍脑袋的可能会说“你们怎么用Hibernate,这个性能比jdbc差很多......”。对于这个问题,我觉得经过实践测试才最有发言权,而早前实践测试结果是:如果需要查询表中的全部字段或大部分字段,并且需要组装成bean,那么Hibernate和jdbc的查询效率是相当的,有时候Hibernate还可能胜出。况且使用hibernate目的大都在于性能满足的情况下,将开发者的重心从繁琐的数据库操作中转移。
2、问题的背景
查询故障过程中,log中出现了这个异常:[org.jboss.resource.adapter.jdbc.local.LocalManagedConnection] this is a fatal exception: I/O Error: Read timed out。后来网上查阅了相关资料,基本上都说是SQL查询太慢超时导致的。后来找到了一条导致查询超时的语句:
String hql =
"select l2inf, l3inf, subinf1.bindingVlan, subinf2.bindingVlan, subvlan "
+ "from InfMngEthSubMemberBean subinf1,InfMngEthSubMemberBean subinf2,InterfaceBinderItem l3inf,VpnAcData l2inf, SubVlan subvlan "
+ "where subinf1.neid=l3inf.neID and subinf2.neid=l2inf.neID and subvlan.supervlanInfName=l3inf.interfaceName "
+ "and subinf2.infName=l2inf.acInterfaceName and subinf1.bindingVlan=subinf2.bindingVlan "
+ "and subinf1.neid=subinf2.neid and l2inf.acInterfaceName like 'ulei%.%' and subvlan.neID=l3inf.neID "
+ "and l3inf.interfaceName like 'supervlan%' and subvlan.memberInfName=subinf1.infName";
这是一条HSQL涉及4张表,结果包含4个bean,数据量最大的表中数量级大概1万。
3、问题的解决
分析代码并将HSQL翻译成了SQL语句,在查询器中进行了查询,发现速度很慢。后来把查询结果的table数量减少,或者本来应该查询一个table的所有字段,现在改为查table的某几个关键字段,这时候查询速度快了很多。说明在条件不变的情况下,查询目标字段的减少能够提高查询效率。那么为什么要查整个bean,能不能改为查bean的某些字段?进一步分析代码,发现查询整个bean那是因为后续处理的接口设计需要。再进一步分析,查询到整个的bean在后续使用中,仅仅使用了bean的几个关键字段,而只有一个bean真正需要所有字段。由于业务逻辑的关系,查询条件是无法修改的,因此想到了一种优化思路:改为JDBC查询,查询必须的关键字段,不进行整个bean信息的查询,得必须的字段后手工进行bean组装(不影响后续使用bean),而需要查询所有字段的bean进行一次性单独查询并且进行缓存(正好发现,这个bean对应的表的数量级很小)。得到下面的SQL语句:
String sql=
" select l2inf.SERVICENAME,l2inf.acname,l3inf.VRF_NAME,l3inf.infname, subinf2.bindingVlan, subvlan.NEID,subvlan.SUPERVLANINFNAME, subvlan.MEMBERINFNAME " +
" from IP_RCM_SERVICE_INFMNG_ETHSUBMB subinf1,IP_RCM_SERVICE_INFMNG_ETHSUBMB subinf2,IP_E2E_VRF_INFBINDITEM l3inf,IP_ROSNG_NE_VPN_SAC l2inf, IP_RCM_SERVICE_SUBVLAN subvlan " +
" where subinf1.neid=l3inf.NE_ID and subinf2.neid=l2inf.neID and subinf1.neid=subinf2.neid and l3inf.NE_ID=subvlan.NEID " +
" and subvlan.SUPERVLANINFNAME=l3inf.infname and subvlan.MEMBERINFNAME=subinf1.infName and subinf2.infName=l2inf.ACNAME " +
" and subinf1.bindingVlan=subinf2.bindingVlan " +
" and l2inf.ACNAME like 'ulei%.%' and l3inf.infname like 'supervlan%' ";
采用上述方法处理后,没出现上述异常,并且在都无异常情况下,性能提高将近10倍数,满足了相关要求。