SQL开发中容易忽视的一些小地方(二)

原文:SQL开发中容易忽视的一些小地方(二)

目的:继上一篇:SQL开发中容易忽视的一些小地方(一) 总结SQL中的null用法后,本文我将说说表联接查询.

为了说明问题,我创建了两个表,分别是学生信息表(student),班级表(classInfo).相关字段说明本人以SQL创建脚本说明:

测试环境:SQL2005

CREATE TABLE [dbo].[student](

[ID] [int] IDENTITY(1,1) NOT NULL,

[sUserName] [nchar](10) COLLATE Chinese_PRC_CI_AS NULL,--姓名

[sAddress] [varchar](200) COLLATE Chinese_PRC_CI_AS NULL,--地址

[classID] [int] NULL,--班级

[create_date] [datetime] NULL CONSTRAINT [DF_student_create_date]  DEFAULT (getdate())--入班时间

) ON [PRIMARY]

学生表记录:插入数据999999行.可以说的上是一个不大不小的表.

CREATE TABLE [dbo].[classInfo](

[classID] [int] IDENTITY(1,1) NOT NULL,--所属班级ID

[sClassName] [varchar](50) COLLATE Chinese_PRC_CI_AS NULL,--班级名称

[sInformation] [varchar](50) COLLATE Chinese_PRC_CI_AS NULL,--班级相关信息

[sDescription] [varchar](50) COLLATE Chinese_PRC_CI_AS NULL,--班级描述

[iSchooling] [int] NULL,--学费

CONSTRAINT [PK_classInfo] PRIMARY KEY CLUSTERED

(

[classID] ASC

)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]

) ON [PRIMARY]

班级表:共插入100行,实际可能不存在这么多的班级.

示例需求:查询学生的基本信息以及所属班级名称,我们都会第一时间想到用表关联,这里我列出相关实现方法.

第一:将数据量较大的学生表放在前面.

--大表在前

select top 1000 a.sUserName,b.sClassName from student a

inner join classInfo b on

a.classID=b.classID

第二:将数据量较小的班级表放在前面.

--小表在前

select top 1000 a.sUserName,b.sClassName from classInfo b

inner join student a on

a.classID=b.classID

第三:用where 实现.

--join与where

select top 1000 a.sUserName,b.sClassName from classInfo b, student a

where a.classID=b.classID

归纳:以上三种方式查询的结果都完全相同,但它们在实现效率上会有不同吗?这里首先提出两个网络上的观点:

网络观点一:一般要使得数据库查询语句性能好点遵循一下原则:在做表与表的连接查询时,大表在前,小表在后.

执行计划效果如图一:

网络观点一结论:从图上可以非常清楚的看出,三者在执行计划上完成一样.为此本人并不同意网络观点一.表在前与后并不影响最终的执行效率.大家有什么不同的意见望指教.

说明:

1:WHERE子句中使用的连接语句,在数据库语言中,被称为隐性连接。INNER JOIN称为显性连接。WHERE 和INNER JOIN产生的连接关系,没有本质区别,结果也一样。但是!隐性连接随着数据库语言的规范和发展,已经逐渐被淘汰,比较新的数据库语言基本上已经抛弃了隐性连接,全部采用显性连接了。

2:join的分类:

1> inner join:理解为“有效连接”,

2>left join:理解为“有左显示”,

3> right join:理解为“有右显示”

4> full join:理解为“全连接”

3 .join可以分主次表 左联是以左边的表为主,右边的为辅,右联则相反

网络观点二:inner join 与 where 在效率上是否一样?原文地址: http://topic.csdn.net/t/20050520/13/4022440.html 原文中有下面一段话:

---------------------------引用----------------------------------------------

4   指明多表关系会大大提高速度   ,如

SELECT   A.X,B.Y   FROM   A   B   WHERE   A.X=B.X

SELECT   A.X,B.Y   FROM   A   INNER   JOIN   B   ON   A.X=B.X

2句结果一样,但是速度相差很多,时间复杂度分别是   O(2n)和O(n*n)

------------------------------------------------------------------------------

我的观点:联接查询的时间复杂度并不是固定的,更不能说是由两种表现方式不同而决定的.join在查询的算法根据联接表的不同分三种情况:

第一种算法:NESTED LOOP:

定义: 对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择。在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表中检索找到与它匹配的行,因此整个查询返回的结果集不能太大(大于1 万不适合),要把返回子集较小表的作为外表。

示例:上面有了一个班级表,下面我再创建一个班级课程表,

CREATE TABLE [dbo].[course](

[ID] [int] IDENTITY(1,1) NOT NULL,

[sCourseName] [nchar](10) COLLATE Chinese_PRC_CI_AS NULL,--课程名称

[classID] [int] NULL,--所属班级ID

CONSTRAINT [PK_CKH] PRIMARY KEY CLUSTERED

(

[ID] ASC

)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]

) ON [PRIMARY]

业务需求:查询所有班级对应的课程情况.

select sCourseName,sClassName from classInfo a

inner join course b

on a.classID=b.classID

执行计划效果图:

结论:通过查询执行计划可以非常清楚的看出,采用了嵌套查询,因为两表的数据量都不大,而且数据大小相当.此时的查询开销为n*n

第二种算法:HASH JOIN :

定义: 散列连接是做大数据集连接时的常用方式,优化器使用两个表中较小的表(或数据源)利用连接键在内存中建立散列表,然后扫描较大的表并探测散列表,找出与散列表匹配的行。这种方式适用于较小的表完全可以放于内存中的情况,这样总成本就是访问两个表的成本之和。但是在表很大的情况下并不能完全放入内存,这时优化器会将它分割成若干不同的分区,不能放入内存的部分就把该分区写入磁盘的临时段,此时要有较大的临时段从而尽量提高I/O 的性能。

结论:从图一中可能看出SQL在联接班级表和学生表是采用了hash join方式,因为班级表数据量大,班级表数据量小.这种方式的查询时间复杂度为2n.

注意点:hash join可能非常容易的变成nested loop,下面的查询为hash join

select top 10000 a.ID,a.sUserName,b.sClassName from classInfo b

inner join student a on

a.classID=b.classID

转换(hash join变nesteed loop):如果在后面组加上排序呢?此是会变成嵌套查询

select top 10000 a.ID,a.sUserName,b.sClassName from classInfo b

inner join student a on

a.classID=b.classID

order by a.ID

转换(nesteed loophash join):上面的嵌套查询又可以改选成hash join

select * from(

select top 10000 a.ID,a.sUserName,b.sClassName from classInfo b

inner join student a on

a.classID=b.classID) as tbl

order by ID

第三种算法:排序合并连接

定义:通常情况下散列连接的效果都比排序合并连接要好,然而如果行源已经被排过序,在执行排序合并连接时不需要再排序了,这时排序合并连接的性能会优于散列连接。

网络观点二结论:inner join和where 在查询效率上没有区别,只是体现形式不同而已.

总结:我们可以通过查看SQL的执行计划来分析SQL的性能,一句话正确与否不在于说话的人,而在于实践验证结果.本人就表联接谈了自己的理解,如果有不对的地方还望各们指教.

注:

    本文引用:

                http://blog.chinaunix.net/u1/46451/showart.php?id=415529

时间: 2024-11-06 21:34:27

SQL开发中容易忽视的一些小地方(二)的相关文章

SQL开发中容易忽视的一些小地方(一)

原文:SQL开发中容易忽视的一些小地方(一) 写此系列文章缘由: 做开发三年来(B/S),发现基于web 架构的项目技术主要分两大方面: 第一:C#,它是程序的基础,也可是其它开发语言,没有开发语言也就不存在应用程序. 第二:数据库,现在是信息化世界,大多数信息都可以通过数据库存储来交换信息.常与应用程序互相交流信息. 但在SQL开发应用时,我们往往只观注些常用的方法(insert delete select update),对些小细节方面(系统存储过程,函数的应用,优化分析)研究的并不多或者是

SQL开发中容易忽视的一些小地方(四)

原文:SQL开发中容易忽视的一些小地方(四) 本篇我想针对网上一些对于非聚集索引使用场合的某些说法进行一些更正. 下面引用下MSDN对于非聚集索引结构的描述. 非聚集索引结构: 1:非聚集索引与聚集索引具有相同的 B 树结构,它们之间的显著差别在于以下两点: * 基础表的数据行不按非聚集键的顺序排序和存储. * 非聚集索引的叶层是由索引页而不是由数据页组成. 2:非聚集索引行中的行定位器或是指向行的指针,或是行的聚集索引键,如下所述: * 如果表是堆(意味着该表没有聚集索引),则行定位器是指向行

SQL开发中容易忽视的一些小地方( 三)

原文:SQL开发中容易忽视的一些小地方( 三) 目的:这篇文章我想说说我在工作中关于in和union all 的用法. 索引定义 : 微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引.簇集索引)和非聚集索引(nonclustered index,也称非聚类索引.非簇集索引). SARG的定义:用于限制搜索的一个操作,因为它通常是指一个特定的匹配,一个值得范围内的匹配或者两个以上条件的AND连接.形式如下: 列名 操作符 <常数 或 变量>或<

SQL开发中容易忽视的一些小地方(五)

原文:SQL开发中容易忽视的一些小地方(五) 背景: 索引分类:众所周知,索引分为聚集索引和非聚集索引. 索引优点:加速数据查询. 问题:然而我们真的清楚索引的应用吗?你写的查询语句是否能充分应用上索引,或者说你如何设计你的索引让它更高效? 经历:以前本人只知道索引的好处,但是是否能够真正让它发挥作用,并无太多理论,为些本人做了些DEMO,来简单说明下什么情况下才能充分利用索引. 案例: 这里建立一个学生表:有如下字段,此时表中没有建立任何索引. CREATE TABLE [dbo].[stud

SQL Server 中关于 @@error 的一个小误区

原文:SQL Server 中关于 @@error 的一个小误区 在SQL Server中,我常常会看到有些前辈这样写: if(@@error<>0) ROLLBACK TRANSACTION T else COMMIT TRANSACTION T 一开始,我看见别人这么写,我就想当然的以为它只是个计数器,每当检测到一处错误时,@@error的值+1,不过就因为这个理所当然,所以杯具了... 实际上,它并不是一个计数器,它是一个动态的值,动态的标识最后一条SQL命令执行的结果,如果成功则为0,

jQuery开发中容易忽视的错误

1.引用jQuery库文件的<script>标签,必须放在引用自定义脚本文件的<script>标签之前,否则,就会发生找不到对象:最好在<head>元素中,把引入样式表的<link />放在<script>标签前面:有时候其他的javascript库也会用$符号,为了不冲突,可以使用.noConflict()方法把控制权交给别的库.    <script src="prototype.js" type="tex

Web开发中致命的8个小错误

现在,有越来越多所谓的"教程"来帮助我们提高网站的易用性.本文收集了一些在Web开发中容易出错和被忽略的小问题,并且提供了参考的解决方案,以便于帮助Web开发者更好的完善网站. 通过避免下面这些小错误,可以使得我们的网站变得更为友好. 错误1:表单的label标签跟表单字段没有关联 利用"for"属性允许用户单击label也可以选中表单中的内容.这可以扩大复选框和单选框的点击区域,非常实用. 错误2:logo图片没有链接到主页 点击网站logo就能转到主页已经成为了

PL/SQL开发中动态SQL的使用方法

一般的PL/SQL程序设计中,在DML和事务控制的语句中可以直接使用SQL,但是DDL语句及系统控制语句却不能在PL/SQL中直接使用,要想实现在PL/SQL中使用DDL语句及系统控制语句,可以通过使用动态SQL来实现. 首先我们应该了解什么是动态SQL,在Oracle数据库开发PL/SQL块中我们使用的SQL分为:静态SQL语句和动态SQL语句.所谓静态SQL指在PL/SQL块中使用的SQL语句在编译时是明确的,执行的是确定对象.而动态SQL是指在PL/SQL块编译时SQL语句是不确定的,如根

android开发中碰到的三个小问题

Android开发中注意到的几个问题 1.  关于actionbar 初始化配置actionbar,getactionbar经常为null,原因是因为在源码或者布局文件中设置了全屏显示的缘故,不设置全屏显示就不会有问题. 2.  关于textview Textview默认是没有焦点的,因此不可能有点击事件,也无法直接实现背景的selector.通过设置android:clickable = true;就可以了,这一点与Button有很大的不同 3.  关于sourcinsight中的php代码.