读书人

加快你的Hibernate引擎(上)

发布时间: 2013-03-27 11:22:42 作者: rapoo

加速你的Hibernate引擎(上)


4.2.1 每个类层次一张表

只需要一张表,一条多态查询生成的SQL大概是这样的:

select id, payment_type, amount, currency, rtn, credit_card_type from payment

针对具体子类(例如CashPayment)的查询生成的SQL是这样的:

select id, amount, currency from payment where payment_type=’CASH’ 

这样做的优点包括只有一张表、查询简单以及容易与其他表进行关联。第二个查询中不需要包含其他子类中的属性。所有这些特性让该策略的性能调优要比其他策略容易得多。这种方法通常比较适合数据仓库系统,因为所有数据都在一张表里,不需要做表连接。

主要的缺点整个类层次中的所有属性都挤在一张大表里,如果有很多子类特有的属性,数据库中就会有太多字段的取值为null,这为当前基于行的数据库(使用基于列的DBMS的数据仓库处理这个会更好些)的SQL调优增加了难度。除非进行分区,否则唯一的数据表会成为热点,OLTP系统通常在这方面都不太好。

4.2.2每个子类一张表

需要4张表,多态查询生成的SQL如下:

select id, payment_type, amount, currency, rtn, credit_card type,????????case when c.payment_id is not null then 1        ?????when ck.payment_id is not null then 2        ?????when cc.payment_id is not null then 3        ?????when p.id is not null then 0 end as clazzfrom payment p left join cash_payment c on p.id=c.payment_id left join???cheque_payment ck on p.id=ck.payment_id left join ???credit_payment cc on p.id=cc.payment_id; 

针对具体子类(例如CashPayment)的查询生成的SQL是这样的:

select id, payment_type, amount, currencyfrom payment p left join cash_payment c on p.id=c.payment_id; 

优点包括数据表比较紧凑(没有不需要的可空字段),数据跨三个子类的表进行分区,容易使用超类的表与其他表进行关联。紧凑的数据表可以针对基于行的数据库做存储块优化,让SQL执行得更好。数据分区增加了数据修改的并发性(除了超类,没有热点),OLTP系统通常会更好些。

同样的,第二个查询不需要包含其他子类的属性。

缺点是在所有策略中它使用的表和表连接最多,SQL语句稍显复杂(看看Hibernate动态鉴别器的长CASE子句)。相比单张表,数据库要花更多时间调优数据表连接,数据仓库在使用该策略时通常不太理想。

因为不能跨超类和子类的字段来建立复合索引,如果需要按这些列进行查询,性能会受影响。任何子类数据的修改都涉及两张表:超类的表和子类的表。

4.2.3每个具体类一张表

涉及三张或更多的表,多态查询生成的SQL是这样的:

select p.id, p.amount, p.currency, p.rtn, p. credit_card_type, p.clazzfrom (select id, amount, currency, null as rtn,null as credit_card type,             1 as clazz from cash_payment union all      select id, amount, null as currency, rtn,null as credit_card type,             2 as clazz from cheque_payment union all      select id, amount, null as currency, null as rtn,credit_card type,             3 as clazz from credit_payment) p;  

针对具体子类(例如CashPayment)的查询生成的SQL是这样的:

select id, payment_type, amount, currency from cash_payment; 

优点和上面的“每个子类一张表”策略相似。因为超类通常是抽象的,所以具体的三张表是必须的[开头处说的3张或更多的表是必须的],任何子类的数据修改只涉及一张表,运行起来更快。

缺点是SQL(from子句和union all子查询)太复杂。但是大多数数据库对此类SQL的调优都很好。

如果一个类想和Payment超类关联,数据库无法使用引用完整性(referential integrity)来实现它;必须使用触发器来实现它。这对数据库性能有些影响。

4.2.4使用隐式多态实现每个具体类一张表

只需要三张表。对于Payment的多态查询生成三条独立的SQL语句,每个对应一个子类。Hibernate引擎通过Java反射找出Payment的所有三个子类。

具体子类的查询只生成该子类的SQL。这些SQL语句都很简单,这里就不再阐述了。

它的优点和上节类似:紧凑数据表、跨三个具体子类的数据分区以及对子类任意数据的修改都只涉及一张表。

缺点是用三条独立的SQL语句代替了一条联合SQL,这会带来更多网络IO。Java反射也需要时间。假设如果你有一大堆领域对象,你从最上层的Object类进行隐式选择查询,那该需要多长时间啊!

根据你的映射策略制定合理的选择查询并非易事;这需要你仔细调优业务需求,基于特定的数据场景制定合理的设计决策。

以下是一些建议:

读书人网 >软件架构设计

热点推荐