4.6 HQL调优
4.6.1 索引调优
HQL看起来和SQL很相似。从HQL的WHERE子句中通常可以猜到相应的SQL WHERE子句。WHERE子句中的字段决定了数据库将选择的索引。
大多数Hibernate开发者所常犯的一个错误是无论何时,当需要新WHERE子句的时候都会创建一个新的索引。因为索引会带来额外的数据更新开销,所以应该争取创建少量索引来覆盖尽可能多的查询。
4.1节让你使用一个集合来处理所有可能的数据搜索条件。如果这不太实际,那么你可以使用后端剖析工具来创建一个针对应用程序涉及的所有 SQL的集合。基于那些搜索条件的分类,你最终会得到一个小的索引集。与此同时,还可以尝试向WHERE子句中添加额外的谓语来匹配其他WHERE子句。
范例7
有两个UI搜索器和一个后端守护进程搜索器来搜索名为iso_deals的表。第一个UI搜索器在unexpectedFlag、dealStatus、tradeDate和isold属性上有谓语。
第二个UI搜索器基于用户键入的过滤器,其中包括的内容除tradeDate和isold以外还有其他属性。开始时所有这些过滤器属性都是可选的。
后端搜索器基于isold、participantCode和transactionType属性。
经过进一步业务分析,发现第二个UI搜索器实际是基于一些隐式的unexpectedFlag和dealStatus值来选择数据的。我们还让tradeDate成为过滤器的必要属性(为了使用数据库索引,每个搜索过滤器都应该有必要属性)。
鉴于这一点,我们依次使用unexpectedFlag、dealStatus、tradeDate和isold构造了一个复合索引。两个UI搜索器都能共用它。(顺序很重要,如果你的谓语以不同的顺序指定这些属性或在它们前罗列了其他属性,数据库就不会选择该复合索引。)
后端搜索器和UI搜索器区别太大,因此我们不得不为它构造另一个复合索引,依次使用isold、participantCode和transactionType。
4.6.2绑定参数 vs.字符串拼接
既可以使用绑定参数构造HQL的WHERE子句,也可以使用字符串拼接的方法,该决定对性能会有一定影响。使用绑定参数的原因是让数据库一次解析 SQL,对后续的重复请求复用生成好的执行计划,这样做节省了CPU时间和内存。然而,为达到最优的数据访问效率,不同的绑定值可能需要不同的SQL执行计划。
例如,一小段数据范围可能只返回数据总量的5%,而一大段数据范围可能返回数据总量的90%。前者使用索引更好,而后者则最好使用全表扫描。
建议OLTP使用绑定参数,数据仓库使用字符串拼接,因为OLTP通常在一个事务中重复插入和更新数据,只取少量数据;数据仓库通常只有少量SQL查询,有一个确定的执行计划比节省CPU时间和内存更为重要。
要是你知道你的OLTP搜索对不同绑定值应该使用相同执行计划又该怎么办呢?
Oracle 9i及以后版本在第一次调用绑定参数并生成执行计划时能探出参数值。后续调用不会再探测,而是重用之前的执行计划。