SQLStory摘录(二)————联接查询初探

<script type="text/javascript"> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>

例1-2、键值重复的信息
现在看一下压缩掉重复信息的PRODUCT表
IDPNAMEPRICENUMBERPDESCRIPTION
1Apple123000NULL
2Banana16.997600NULL
3Olive25.224500NULL
4CocoNut40.992000NULL
4Orange15.995500NULL
5Pineapple302500NULL
6Olive25.223000NULL

这里还有几个有问题的地方。表中CocoNut和Orange的ID都是4,ID号为3和6的两种商品的品名(PNAME)都是Olive。而我们的原意显然是想要让每一种商品对应一个ID号,而且表中的ID号和PNAME都应该是唯一的。这个表中只有7行,我们可以直接观察,用肉眼发现问题,表中数据量很大时呢?
现在我们回顾一下例1中查询重复数据的语句。我们用
……
GROUPBYID,PNAME,PRICE,NUMBER,PDESCRIPTION
对数据集进行了分组,并用
HAVINGCOUNT(*)>1
过滤出了重复的数据,依此类推,单独对ID列进行分组和过滤,能否找出ID重复的数据呢?试一试:
SELECTID
FROMPRODUCT
GROUPBYID
HAVINGCOUNT(*)>1
返回结果:
ID
-----------
4
这样倒是出现了我们所要的ID号,可这种报表实在没什么实际意义,现在我们查一下这个ID到底是谁:
SELECTID,PNAME,PRICE,NUMBER,PDESCRIPTION
FROMPRODUCT
GROUPBYID
HAVINGCOUNT(*)>1
这条语句执行出错,很显然,ID号之后的四列既不在GROUPBY中,也是统计函数,它们不应该出现在这里。而这样的语句:
SELECTID,PNAME,PRICE,NUMBER,PDESCRIPTION
FROMPRODUCT
GROUPBYID,PNAME,PRICE,NUMBER,PDESCRIPTION
HAVINGCOUNT(*)>1
返回的是一个空结果集:
IDPNAMEPRICENUMBERPDESCRIPTION
---------------------------------------------------------------------------------------------------

 

(所影响的行数为0行)
很多朋友用子查询
SELECTID,PNAME,PRICE,NUMBER,PDESCRIPTION
FROMPRODUCT
WHEREIDIN(
SELECTID
FROMPRODUCT
GROUPBYID
HAVINGCOUNT(*)>1
)
来解决,我还见过一个用二级游标的例子(!?),那么没有更好的办法了吗?
我更喜欢以下这行语句:
SELECTL.ID,R.PNAME,R.PRICE,R.NUMBER,R.PDESCRIPTION
FROMPRODUCTL
JOINPRODUCTR
ONL.ID=R.ID
GROUPBYL.ID,R.PNAME,R.PRICE,R.NUMBER,R.PDESCRIPTION
HAVINGCOUNT(*)>1
返回结果如下:
IDPNAMEPRICENUMBERPDESCRIPTION
4CocoNut40.992000NULL
4Orange15.995500NULL

使用联接查询,速度会比子查询快很多,因为不用每次用IN操作在子语句中的结果集中搜索数据。尤其当表中数据很多,返回的结果集也很大时,其差异是相当惊人的。如果在多处理器,多硬盘的服务器上运行,联接查询还可以充分利用并行运算来提高效率。1999年夏天,IBM公司的工程师们在兰州大学出席全国技术会议时,向我们讲解了运用并行运算技术优化联接查询所带来的性能飚升。相比之下,子查询在这方面有点吃亏。有些强大的数据库引擎会在适当的时候将子查询转化为联接查询,或反之。但把真理掌握在我们自己手中,不是更好吗?
当然,子查询并不是一定比联接慢,有机会我也会演示一些子查询快于联接查询的例子,甚至有些子查询语句,用联接是很难实现的。理论来讲,联接查询会生成一个迪卡尔积,这个集合的大小是组成它的各个子集的乘积。这会带来空间上的巨大开销(实际我们所见的数据库系统没有一个真这么干的)。而子查询的情况比较复杂。由生成的结果集来分,有标量子查询和向量子查询,(标量子查询指返回一个简单数据的查询,这种子查询语句在MS中可以直接做为外部查询语句的一列);由子查询与外部查询的关系来分,有相关子查询和非相关子查询(相关子查询的结果集取决于外部查询当前的数据行,非相关子查询反之)。通常相关子查询比较让人头痛,它需要反复执行子查询语句,若外部查询操作的数据集(不是返回的数据集)行数为n,子查询操作的数据集行数为m,那它的复杂度最大将是m的n次方!加上子查询数据集展开带来的巨大空间开销,会极大影响速度。上例中的子查询比较幸运,是一个无关的向量子查询,但即使如此,也要在运算中保存一个子结果集并对其反复操作,而且难以并行运算,结果是它的速度不会比联接查询快。这也就是在很长时间里一直不支持子查询的原因。在通常情况下,大数据集的操作,联接查询的性能总是优于子查询,所以我们应当充分掌握这一方法。 1 <script type="text/javascript"> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值