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

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

本篇我想针对网上一些对于非聚集索引使用场合的某些说法进行一些更正. 下面引用下MSDN对于非聚集索引结构的描述.

非聚集索引结构:

1:非聚集索引与聚集索引具有相同的 B 树结构,它们之间的显著差别在于以下两点:

* 基础表的数据行不按非聚集键的顺序排序和存储。

* 非聚集索引的叶层是由索引页而不是由数据页组成。

2:非聚集索引行中的行定位器或是指向行的指针,或是行的聚集索引键,如下所述:

* 如果表是堆(意味着该表没有聚集索引),则行定位器是指向行的指针。该指针由文件标识符 (ID)、页码和页上的行数生成。整个指针称为行 ID (RID)。

* 如果表有聚集索引或索引视图上有聚集索引,则行定位器是行的聚集索引键。如果聚集索引不是唯一的索引,SQL Server 将添加在内部生成的值(称为唯一值)以使所有重复键唯一。此四字节的值对于用户不可见。仅当需要使聚集键唯一以用于非聚集索引中时,才添加该值。SQL Server 通过使用存储在非聚集索引的叶行内的聚集索引键搜索聚集索引来检索数据行。

网络观点:order by 子句中使用了的列,可以在此列上建非聚集索引以提高查询速度.

原文地址:http://gocom.primeton.com/blog10697_1221.htm

本人观点:总之一句话,环境不同,表结构不同,数据分布不同,最终结果也不一定相同.

案例:本人最近做一个项目时有两个大表关联,都接近千万.一个表是订单表order,另一个是会员表member,订单中有一字段create_date:类型为datatime,其中的值都是不相同且唯一,而且并不连续,下面是一些值:

create_date

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

2008-10-05 04:00:56.000

2008-10-05 03:55:55.000

2008-10-05 03:55:42.000

2008-10-05 03:54:40.000

2008-10-05 03:54:32.000

2008-10-05 03:54:23.000

2008-10-05 03:47:16.000

2008-10-05 03:46:08.000

2008-10-05 03:42:28.000

2008-10-05 03:42:09.000

订单表和会员表有一个关联字段为proxyID,各自均建有索引.查询语句如下:

select * from order inner join member on order.proxyID=member.proxyID

where leaveDate between ‘开始时间‘ and ‘结束时间‘ order by create_date desc

测试:

情况一:在create_date上创建非聚集索引.执行的IO和所用时间消耗如下图:可以看出这种情况对memer表进行了大量的表扫描. 83588次.

情况二:删除create_date上的索引,按理来说应该会比有索引会慢些,下面是执行的IO和时间消耗图:

对此我有以下发现:

1:order by 字段没有创建索引的情况下,对member表只扫描了9次.远少于创建索引时的83588次.

2:还有一个现象就是如果按在查询分析器中全部显示出数据来看,没有创建索引最终所用时更少.

3:创建索引的查询会比没有创建索引的查询早一步显示数据,不过最终完成的时间要长.

测试未知难题:

1:就查询速度来说,是早一步在查询分析器中显示数据的查询快还是说要看最终完全的时间来判断.(create_date创建索引的情况会更早显示数据,不过总共用时会比不创建索引的慢)园友zping曾告诉我不要看时间要看IO数量.不知道大家是怎么分析的.

2:在一个字段上创建索引为什么会引发member表的多次表扫描.

测试说明:由于SQL2005有缓存功能,所有两次查询的时间段并不相同,但数据量都差不多.

根据园友 perfectdesign的观点,order by 时,如果字段是聚集索引将会是最优的,这点我个人以及MSDN都同意,奇怪的是,上面的语句中,leave_date上即聚集索引,然后order by leave_date desc,然而也会产生5万多次的member表扫描,好像是order by 索引字段,无论是聚集还是非聚集都会大量增加对member表的扫描.真是百思不得其解.下面是详细的ID情况:

(2000 row(s) affected)

Table ‘member‘. Scan count 52796, logical reads 234885, physical reads 0, read-ahead reads 3687, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table ‘v_hotel‘. Scan count 1, logical reads 3121, physical reads 0, read-ahead reads 28, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

测试结论:这种情况足以说明对于order by 字段创建索引并不一定能发挥非聚集索引的优势,至于其中原因本人不才,目前并无答案,如大家有答案还望指教一二.数据库的调优虽然有一定的原则及准则,但这些所谓准则并一定全对.本人觉的都仅供参考,还是要按实际情况来分析.

下面贴下MSDN对于非聚集索引应用场合的说明,我觉的还是可能参考的:

在创建非聚集索引之前,应先了解访问数据的方式。考虑对具有以下属性的查询使用非聚集索引:

  • 使用 JOIN 或 GROUP BY 子句。

    应为联接和分组操作中所涉及的列创建多个非聚集索引,为任何外键列创建一个聚集索引。

  • 不返回大型结果集的查询。

    创建筛选索引以覆盖从大型表中返回定义完善的行子集的查询。

  • 包含经常包含在查询的搜索条件(例如返回完全匹配的 WHERE 子句)中的列。

 注:

    本文引用:MSDN

时间: 2024-11-01 22:22:40

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

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

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

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

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

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

原文:SQL开发中容易忽视的一些小地方(二) 目的:继上一篇:SQL开发中容易忽视的一些小地方(一) 总结SQL中的null用法后,本文我将说说表联接查询. 为了说明问题,我创建了两个表,分别是学生信息表(student),班级表(classInfo).相关字段说明本人以SQL创建脚本说明: 测试环境:SQL2005 CREATE TABLE [dbo].[student]( [ID] [int] IDENTITY(1,1) NOT NULL, [sUserName] [nchar](10) C

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代码.