的需求是列出所有尚未标记为完
成状态的订单(假设所有jiāo易都已终止)的下列字段:订单号、客户名、订单的最后状态,以
及设置状态的时间。最终,我们写出下列查询,滤掉已完成的订单,并找出订单当前状态:
乍一看,这个查询很合理,但事实上,它让人非常担心。首先,上面代码中有两个子查询,但
它们嵌入的方式和前一个例子的方式不同,它们只是彼此间接相关的。最让人担心的是,这两
个子查询访问相同的表,而且该表在外层已经被访问过。我们编写的过滤条件质量如何呢?因
为只检查了订单是否完成,所以它不是非常精确。
这个查询如何执行的呢?很显然,可以扫描orders 表,检查每一条订单记录是否为已完成状
态——注意,仅通过表orders 即可找出所要信息似乎令人高兴,但实际情况并非如此,因为
只有上述活动之后,才能检查最新状态的日期,即必须按照子查询编写的顺序来执行。
上述两个子查询是关联子查询,这很不好。因为必须要扫描orders 表,这意味着我们必须检
查orders 的每条订单记录状态是否为“COMPLETE”,虽然检查状态的子查询执行很快,但多
次重复执行就不那么快了。而且,若第一个子查询没找到“COMPLETE” 状态时,还必须执行
第二个子查询。那么,何不试试非关联子查询呢?
要编写非关联子查询,最简单的办法是在第二个子查询上做文章。事实上,在某些SQL 方言
中,我们可以这么写:
这个子查询会对orderestatus 作“全扫描”,但未必是坏事,下面会对此加以解释。
重写的子查询条件中,等号左端的“字段对”有点别扭,因为这两个字段来自不同的表,其实不
必这样。我们想让orders和orderstatus的订单ID相等,但优化器能感知这一点吗?答案是不一
select c.custncom, o.ordid, os.status, os.statusdate
from custcomrs c,
orders o,
orderstatus os
where o.ordid = os.ordid
and not exists (select null
from orderstatus os2
where os2.status = 'COMPLETE'
and os2.ordid = o.ordid)
and os.statusdate = (select max(statusdate)
from orderstatus os3
where os3.ordid = o.ordid)
and o.custid = c.custid
and (o.ordid, os.statusdate) = (select ordid, max(statusdate)
from orderstatus
group by ordid)
定。所以优化器可能依然先执行子查询,依然要把orders和orderstatus这两个表连接起来。我
们应该将查询稍加修改,使优化器更容易明白我