友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
狗狗书籍 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

SQL语言艺术(PDF格式)-第15章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




利于多数 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 即可找出所要信息似乎令人高兴,但实际情况并非如此,因为 

只有上述活动之后,才能检查最新状态的日期,即必须按照子查询编写的顺序来执行。 



上述两个子查询是关联子查询,这很�
返回目录 上一页 下一页 回到顶部 赞(1) 踩(1)
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!