虎虎漫画小说

繁体版 简体版
虎虎漫画小说 > > SQL语言艺术最新章节 > 第 8 章

第 8 章 免费阅读

销售是否发生在最近六个月,比反过来cāo作要快。如果表orderdetail 的artid字段有索引,这

个方法会更快,否则,这个聪明巧妙的举措就会黯然失色。

注意

每当对大量记录做存在xìng检查时,选择in还是exists须斟酌。

利于多数SQL 方言,非关联子查询可以被改写成from 子句中的内嵌视图。然而,一定要记住

的是,in 会隐式地剔除重复项目,当子查询改写为from 子句中的内嵌视图时,必须要显式地

消除重复项目。例如:

编写功能等价的查询时,不同的编写方式就好像同义词。在书面语和口语中,同义词的意思虽

select custncom

from custcomrs

where city = 'GOTHAM'

and custid in

(select custid

from orders

where ordered >= scomfunc

and ordid in (select od.ordid

from orderdetail od,

articles a

where a.artncom = 'BATMOBILE'

and a.artid = od.artid)

select custncom

from custcomrs

where city = 'GOTHAM'

and custid in

(select o.custid

from orders o,

(select distinct od.ordid

from orderdetail od,

articles a

where a.artncom = 'BATMOBILE'

and a.artid = od.artid) x

where o.ordered >= scomfunc

and x.ordid = o.ordid)

然大致相同,但又有细微差异,因此某个词在特定语境中更合适。同样,数据和处理的具体实

现细节可以决定选择哪种查询方式。

蝙蝠车买主案例总结

前面讨论的各段SQL语句,看似意义不大的编程技巧练习,实则不然。关键是“擒获(attack)”

数据的方法有很多,不必按照先custcomrs、然后orders、接着orderdetail和articles的方式来编

写查询。

现在以箭头表示搜索条件的强度——条件分辨力越强,箭头就越大。假设Gotham市的客户非

常少,但过去六个月的销售业绩不错,卖出了很多蝙蝠车,此时规划图如图4-6所示。虽然商品

名称之上有个过滤条件,但图中的中等大小的箭头指向了表orderdetail,因为该表是真正重要

的表。待售商品可能很少,反映出销售收入的百分比;也可能待售商品很多,最畅销的商品之

一就是蝙蝠车。

相反,如果我们假设多数客户在Gotham市,但其中很少的客户买了蝙蝠车,则规划图如图4-7

所示。很显然,此时表orderdetail 是最大的目标。来自这个表的数据的数据量缩减速度越快,

查询执行得就越快。

还要注意的非常重要的一点是,“过去六个月”并不是个非常精确的条件。但如果我们把条件改为

过去两个月,而库中有十年的销售记录,会发生什么呢?在这种情况下,如果能先访问到近期

的订单(借助第5章中描述的一些技术,这些数据或许就聚集在一起),查询的效率就会更高些;

找出近期订单后,一方面选取Gotham 的客户,另一方面则选取蝙蝠车订单。所以,换个角度

来看,最好的执行计划并不只相依于数据值,还应该随着时间而不断进化。

好了,总结一下。首先,解决问题的方法不只一种……而且查询的编写方式经常会与数据隐含

的假设相关。殊途同归,最终的结果集都是一样的,但执行速度可能有极大差异。查询的编写

方式会影响执行路径,尤其是应用无法在真正的关系环境中表达的条件时。若想让优化器发挥

极致,我们就必须扩大关系处理的工作量,并确保非关系的部分对最后结果集的影响最小。

本章前面一直假设代码的执行方式与编写方式一样,但其实,优化器可能改写查询——有时改

动还很大。你或许认为优化器所做的改写无关紧要,因为SQL本是一种声明xìng语言(declarative

language),用它来说明想要什么,并让DBMS 予以执行。然而,你也看到了,每次用不同方

式改写查询时,都必须更新关于数据分布和已有索引的假设。因此有一点非常重要:应预先考

虑优化器的工作,以确定它能找到所需数据——这可能是索引,也可能是数据相关的详细统计

信息。

总结:保证SQL 语句返回正确结果,只是建立最佳SQL语句的第一步。

大数据量查询

Querying Large Quantities of Data

越快剔除不需要的数据,查询的后续阶段必须处理的数据量就越少,自然查询的效率就越高,

这听起来显而易见。集合cāo作符(set operator)是这一原理的绝佳应用,其中的union使用最

为广泛,我们经常看到通过unioncāo作将几个表“粘”在一起。中等复杂程度的union语句较为常见,

大多数被连接的表都会同时出现在union两端的select 语句中。例如下面这段代码:

这类查询是典型的“照搬式”编程。为了提高效率,可以仅对代码中非共用的表(本例中即E1和

E2)使用union,然后配合筛选条件,把union 语句降级为内嵌视图。代码如下:

另一个“查询条件用错了地方”的经典例子,和在含有group by 子句的查询中进行过滤cāo作有

关。你可以过滤分了组的字段,也可以过滤聚合(aggregate)结果(例如检查count() 的结果

是否小于某阈值),或者同时过滤两者;SQL 允许在having 子句中使用这类条件,但应该在

group by 完成后才进行过滤(比如排序之后再进行聚合cāo作)。任何影响聚合函数(aggregate

select ...

from A,

B,

C,

D,

E1

where (condition on E1)

and (joins and other conditions)

union

select ...

from A,

B,

C,

D,

E2

where (condition on E2)

and (joins and other conditions)

select ...

from A,

B,

C,

D,

(select ...

from E1

where (condition on E1)

union

select ...

from E2

where (condition on E2)) E

where (joins and other conditions)

function)结果的条件都应放在having 子句中,因为在group by 之前无从知道聚合函数的结

果。任何与聚合无关的条件都应放在where 子句中,从而减少为进行group by而必须执行的排

序cāo作所处理的数据量。

现在回过头来看客户与订单的例子,我承认先前处理订单的方法比较复杂。在订单完成之前,

必须经历几个阶段,这些都记录在表orderstatus中,该表的主要字段有:ordid(订单ID)、status、

statusdate(时间戳)等,主键由ordid和statusdate组成。我们

松语文学免费小说阅读_www.16sy.com

『加入书签,方便阅读』