r.item_id = scomvalue
and outer.record_date = (select max(inner.record_date)
from hist_data as inner
where inner.item_id = outer.item_id
and inner.record_date <= reference_date)
考察这个查询的执行路径,我们发现:首先,内层查询与外层查询是有关联的(correlated), 因
为内层查询参照了item_id的值,该值是由外层查询返回的当前记录一个字段。下面,先来分析
外层查询。
理论上,复合键中的字段顺序不会有太大影响,但实际上它们非常重要。如果我们误把主键定
义为(record_date, item_id),而不是(item_id, record_date),前例的内层查询就非常依赖item_id
字段的索引,否则无法高效地向下访问树状结构索引。但我们知道,额外增加一个索引的代价
很高。
外层查询找到了保存item_id 历史的各条记录,接着使用当前item_id 值逐次执行子查询。注
意,内层查询只依赖item_id,这与外层查询处理的记录相同,这意味着我们执行相同的查询、
返回相同的结果。优化器会注意到查询总是返回相同的值吗?无法确定。所以最好不要冒这个
险。
在使用关联子查询时,如果它处理不同的记录后总是返回相同的值,就没有意义了。所以,应
该改用无关联子查询:
select whatever
from hist_data as outer
where outer.item_id = scomvalue
and outer.record_date = (select max(inner.record_date)
from hist_data as inner
where inner.item_id = scomvalue
and inner.record_date <= reference_date)
现在子查询的执行不需要访问表,只需访问主键索引就够了。
个人习惯各有不同,但如果DBMS支持将“子查询的输出”与多个字段进行比较(这个特xìng不是
所有产品都支持的),则应优先考虑基于主键比较:
select whatever
from hist_data as outer
where (outer.item_id, outer.record_date) in
(select inner.item_id, max(inner.record_date)
from hist_data as inner
where inner.item_id = scomvalue
and inner.record_date <= reference_date
group by inner.item_id)
让子查询返回的字段,完全与复合主键的字段相符,有一定道理。如果必须返回“数据项值的列