利于多数 SQL 方言,非关联子查询可以被改写成from 子句中的内嵌视图。然而,一定要记住
的是,in 会隐式地剔除重复项目,当子查询改写为 from 子句中的内嵌视图时,必须要显式地
消除重复项目。例如:
select custname
from customers
where city = "GOTHAM"
and custid in
(select o。custid
from orders o;
(select distinct od。ordid
from orderdetail od;
articles a
where a。artname = "BATMOBILE"
and a。artid = od。artid) x
where o。ordered 》= somefunc
and x。ordid = o。ordid)
编写功能等价的查询时,不同的编写方式就好像同义词。在书面语和口语中,同义词的意思虽
…………………………………………………………Page 44……………………………………………………………
然大致相同,但又有细微差异,因此某个词在特定语境中更合适。同样,数据和处理的具体实
现细节可以决定选择哪种查询方式。
蝙蝠车买主案例总结
前面讨论的各段SQL语句,看似意义不大的编程技巧练习,实则不然。关键是“擒获(attack)”
数据的方法有很多,不必按照先customers、然后orders、接着orderdetail和articles的方式来编
写查询。
现在以箭头表示搜索条件的强度——条件分辨力越强,箭头就越大。假设 Gotham市的客户非
常少,但过去六个月的销售业绩不错,卖出了很多蝙蝠车,此时规划图如图4…6所示。虽然商品
名称之上有个过滤条件,但图中的中等大小的箭头指向了表orderdetail,因为该表是真正重要
的表。待售商品可能很少,反映出销售收入的百分比;也可能待售商品很多,最畅销的商品之
一就是蝙蝠车。
相反,如果我们假设多数客户在 Gotham市,但其中很少的客户买了蝙蝠车,则规划图如图4…7
所示。很显然,此时表orderdetail 是最大的目标。来自这个表的数据的数据量缩减速度越快,
查询执行得就越快。
还要注意的非常重要的一点是,“过去六个月”并不是个非常精确的条件。但如果我们把条件改为
过去两个月,而库中有十年的销售记录,会发生什么呢?在这种情况下,如果能先访问到近期
的订单(借助第5章中描述的一些技术,这些数据或许就聚集在一起),查询的效率就会更高些;
找出近期订单后,一方面选取Gotham 的客户,另一方面则选取蝙蝠车订单。所以,换个角度
来看,最好的执行计划并不只相依于数据值,还应该随着时间而不断进化。
好了,总结一下。首先,解决问题的方法不只一种……而且查询的编写方式经常会与数据隐含
的假设相关。殊途同归,最终的结果集都是一样的,但执行速度可能有极大差异。查询的编写
方式会影响执行路径,尤其是应用无法在真正的关系环境中表达的条件时。若想让优化器发挥
极致,我们就必须扩大关系处理的工作量,并确保非关系的部分对最后结果集的影响最小。
本章前面一直假设代码的执行方式与编写方式一样,但其实,优化器可能改写查询——有时改
动还很大。你或许认为优化器所做的改写无关紧要,因为 SQL本是一种声明性语言(declarative
language),用它来说明想要什么,并让 DBMS 予以执行。然而,你也看到了,每次用不同方
式改写查询时,都必须更新关于数据分布和已有索引的假设。因此有一点非常重要:应预先考
虑优化器的工作,以确定它能找到所需数据——这可能是索引,也可能是数据相关的详细统计
信息。
总结:保证SQL 语句返回正确结果,只是建立最佳 SQL语句的第一步。
大数据量查询
Querying Large Quantities of Data
越快剔除不需要的数据,查询的后续阶段必须处理的数据量就越少,自然查询的效率就越高,
这听起来显而易见。集合操作符(set operator)是这一原理的绝佳应用,其中的union使用最
为广泛,我们经常看到通过union操作将几个表“粘”在一起。中等复杂程度的union语句较为常见,
大多数被连接的表都会同时出现在union两端的select 语句中。例如下面这段代码:
…………………………………………………………Page 45……………………………………………………………
select 。。。
fromA;
B;
C;
D;
E1
where (condition on E1)
and (joins and other conditions)
union
select 。。。
fromA;
B;
C;
D;
E2
where (condition on E2)
and (joins and other conditions)
这类查询是典型的“照搬式”编程。为了提高效率,可以仅对代码中非共用的表(本例中即E1和
E2)使用union,然后配合筛选条件,把 union 语句降级为内嵌视图。代码如下:
select 。。。
fromA;
B;
C;
D;
(select 。。。
from E1
where (condition on E1)
union
select 。。。
from E2
where (condition on E2)) E
where (joins and other conditions)
另一个“查询条件用错了地方”的经典例子,和在含有 group by 子句的查询中进行过滤操作有
关。你可以过滤分了组的字段,也可以过滤聚合(aggregate)结果(例如检查 count() 的结果
是否小于某阈值),或者同时过滤两者;SQL 允许在 having 子句中使用这类条件,但应该在
group by 完成后才进行过滤(比如排序之后再进行聚合操作)。任何影响聚合函数(aggregate
…………………………………………………………Page 46……………………………………………………………
function)结果的条件都应放在 having 子句中,因为在 group by 之前无从知道聚合函数的结
果。任何与聚合无关的条件都应放在 where 子句中,从而减少为进行group by而必须执行的排
序操作所处理的数据量。
现在回过头来看客户与订单的例子,我承认先前处理订单的方法比较复杂。在订单完成之前,
必须经历几个阶段,这些都记录在表orderstatus中,该表的主要字段有:ordid(订单ID)、status、
statusdate(时间戳)等,主键由ordid和statusdate组成。我们的需求是列出所有尚未标记为完
成状态的订单(假设所有交易都已终止)的下列字段:订单号、客户名、订单的最后状态,以
及设置状态的时间。最终,我们写出下列查询,滤掉已完成的订单,并找出订单当前状态:
select c。custname; o。ordid; os。status; os。statusdate
from customers c;
orders o;
orderstatus os
where o。ordid = os。ordid
and not exists (select null
from orderstatus os2
where os2。status = "PLETE"
and os2。ordid = o。ordid)
and os。statusdate = (select max(statusdate)
from orderstatus os3
where os3。ordid = o。ordid)
and o。custid = c。custid
乍一看,这个查询很合理,但事实上,它让人非常担心。首先,上面代码中有两个子查询,但
它们嵌入的方式和前一个例子的方式不同,它们只是彼此间接相关的。最让人担心的是,这两
个子查询访问相同的表,而且该表在外层已经被访问过。我们编写的过滤条件质量如何呢?因
为只检查了订单是否完成,所以它不是非常精确。
这个查询如何执行的呢?很显然,可以扫描 orders 表,检查每一条订单记录是否为已完成状
态——注意,仅通过表 orders 即可找出所要信息似乎令人高兴,但实际情况并非如此,因为
只有上述活动之后,才能检查最新状态的日期,即必须按照子查询编写的顺序来执行。
上述两个子查询是关联子查询,这很?
小说推荐
- C语言实例教程(PDF格式)
- -Page 1-前 言Visual C+是开发运行于Windows 95和Windows NT环境下的Win32应用程序的可视化编程工具中最重要的成员之一,它为软件开发人员提供了完整的编辑、编译和调试工具和建立于Win32 API(ApplicationProgramming Interface)基
- 其他
- 最新章:第143章
- SQL 21日自学通(V3.0)(PDF格式)
- -Page 1-SQL 21 日自学通(V1.0 翻译人 笨猪目录目录 1译者的话 14第一周概貌 16从这里开始 16
- 其他
- 最新章:第170章
- C语言游戏编程从入门到精通(PDF格式)
- -Page 1-Page 2-Page 3-Page 4-Page 5-Page 6-Page 7-Page 8-Page 9-Page 10-Page 11-Page 12-Page 13-Page 14
- 其他
- 最新章:第4章
- JMS简明教程(PDF格式)
- -Page 1-JMS1.1规范中文版卫建军2007‐11‐22-Page 2
- 其他
- 最新章:第28章
- oracle从入门到精通(PDF格式)
- -Page 1-Oracle 从入门到精通-Page 2-资源来自网络,仅供学习 Oracle 从入门到精通一、SQL 8
- 其他
- 最新章:第37章
- 深入浅出MFC第2版(PDF格式)
- -Page 1-Page 2-山高月小山高月小 水落石出水落石出山高月小山高月小 水落石出水落石出-Page 3-深入淺出MFC(第版 使用Visual C 5.0 MFC 4.2)Dissecting MFC(Second Edition Using Visual C 5.0 MFC 4.2)侯俊
- 其他
- 最新章:第309章
- 软件工程实践者的思想(PDF格式)
- -Page 1-大 道 至 简—软件工程实践者的思想周爱民(Aimingoo 著-Page 2-序2004 年 11 月初爱民(Aimingoo)第一次把他的书稿给我,我翻看了一下,第一反应讲的是感想。这不错,在技
- 其他
- 最新章:第26章
- VB2008从入门到精通(PDF格式英文版)
- -Page 1(R)The eXperT’s Voice inBeginningVB 2008From Novice to ProfessionalChristian Gross-Page 2-Page 3-Beginning VB 2008From Novice to Professional■C
- 其他
- 最新章:第214章
- 电子电路大全(PDF格式)
- -Page 1-电力生产人员技能培训电路基础部分电路基础部分电电路路基基础础部部分分-Page 2-一、电路的基本概念和基本定律-Page 3-考试点1o 1、掌握电阻、独立电压源、独立电流源、11受控源、电容、电感、耦合电感、理想变压器诸元件的定义、性质2o 2、掌握电流、电压参考方向的概念223
- 其他
- 最新章:第353章