SQLSERVER是怎麽通过索引和统计信息来找到目标数据的(第二篇)

SQLSERVER是怎麽通过索引和统计信息来找到目标数据的(第二篇)

是怎麽通过索引和统计信息来找到目标数据的(第二篇)

在看这篇文章的内容之前,请阁下先看第一篇的内容,因为没有第一篇的基础的话会看到一头雾水哦o(∩_∩)o

第一篇的地址:是怎麽通过索引和统计信息来找到目标数据的(第一篇)

——————————开始—————————————————————-

索引上的数据检索方法

如果一张表上没有聚集索引,数据将会以随机的顺序存放在表格里。

t

为例子(这个表在第一篇里已经建立好了)。他的上面没有聚集索引,

只有一个在上的非聚集索引。所以表格的每一行记录,不会按照任何顺序,而是随意地存放在Hash里

这时候如果用户要找所有单价大于200的销售详细记录,要运行的语句会是

<pre style="background: #e8e8e8; color: #333333; padding: 1.2em; border-radius: 8px; overflow-x: auto; margin: 1.6em 0; font-family: ‘JetBrains Mono’, Consolas, monospace; font-size: 14px; line-height: 1.6;”>1 SET STATISTICS PROFILE ON
2 USE [AdventureWorks]
3 GO
4 SELECT
5 [SalesOrderDetailID],[UnitPrice]
6 FROM [dbo].[SalesOrderDetail_test]
7 WHERE [UnitPrice]>200

由于表格在上没有索引,所以不得不对这个表格从头到尾扫描一遍,把所有的值大于200的记录

一个一个挑出来SQLSERVER是怎麽通过索引和统计信息来找到目标数据的(第二篇),从执行计划里可以清楚地看出来做了一个表扫描。(执行计划我就不贴出来了 )

如果这个表格上有聚集索引,事情会怎样呢?还是以刚才那张表做例子,先给他在值是唯一的字段上

建立一个聚集索引,这样所有的数据都会按照聚集索引的顺序存储

<pre style="background: #e8e8e8; color: #333333; padding: 1.2em; border-radius: 8px; overflow-x: auto; margin: 1.6em 0; font-family: ‘JetBrains Mono’, Consolas, monospace; font-size: 14px; line-height: 1.6;”>1 USE [AdventureWorks]
2 GO
3 CREATE CLUSTERED INDEX SalesOrderDetail_test_CL ON [dbo].[SalesOrderDetail_test]([SalesOrderDetailID])
4 GO

可惜的是,查询条件上没有索引,所以还是要把所有记录都扫描一遍

和刚才有区别的是:执行计划里的表扫描变成了聚集索引扫描.因为在有聚集索引的表格上数据是

直接存放在索引的最底层的,所以要扫描整个表格里的数据,就要把整个聚集索引扫描一遍。

在这里,聚集索引扫描就相当于一个表扫描。所要用的时间和资源与表扫描没有什么差别。

并不是说这里有了“Index”这个字样,就说明执行计划比表扫描的有多大进步。

当然反过来讲,如果看到“Table Scan”的字样SQLSERVER是怎麽通过索引和统计信息来找到目标数据的(第二篇),就说明这个表格上没有聚集索引

现在在上面建立一个非聚集索引,看看情况会有什么变化

<pre style="background: #e8e8e8; color: #333333; padding: 1.2em; border-radius: 8px; overflow-x: auto; margin: 1.6em 0; font-family: ‘JetBrains Mono’, Consolas, monospace; font-size: 14px; line-height: 1.6;”>1 USE [AdventureWorks]
2 GO
3 CREATE INDEX SalesOrderDetail_test_NCL_Price ON [dbo].[SalesOrderDetail_test]([UnitPrice])
4 GO

在非聚集索引里,会为每条记录存储一份非聚集索引索引键的值和一份聚集索引索引键的值

【在没有聚集索引的表格里,是RID值指向数据页面,有聚集索引的话指向聚集索引的键(在不使用时)】

所以在这里,每条记录都会有一份

记录,按照

的顺序存放

再跑刚才那个查询,你会看到这次不用扫描整个表了。根据新建的索引,

3063211&fm=253&fmt=JPEG&app=138&f=JPEG?w=454&h=280″ alt=”sqlserver 建立索引”/ style=”max-width: 100%; height: auto; display: block; margin: 1.8em auto; border-radius: 10px; box-shadow: 0 4px 20px rgba(0,0,0,0.12);”>

他直接找到了符合记录的值执行计划:索引查找

但是,光用建立在

上的索引不能告诉我们其他字段的值。如果在刚才那个查询里再增加几个字段返回,

就要先在非聚集索引上找到所有

大于200的记录,然后再根据

的值

找到存储在聚集索引上的详细数据。这个过程可以称为“ ” 书签查找(书签查找很难避免)

为什麽很难避免书签查找?阁下继续看下去就知道了

<pre style="background: #e8e8e8; color: #333333; padding: 1.2em; border-radius: 8px; overflow-x: auto; margin: 1.6em 0; font-family: ‘JetBrains Mono’, Consolas, monospace; font-size: 14px; line-height: 1.6;”>1 SET STATISTICS PROFILE ON
2 USE [AdventureWorks]
3 GO
4 SELECT [SalesOrderID],[SalesOrderDetailID],[UnitPrice]
5 FROM [dbo].[SalesOrderDetail_test] WITH (INDEX (salesorderdetail_test_ncl_price))
6 WHERE [UnitPrice]>200

在以后, 的动作用一个嵌套循环来完成。所以在执行计划里,可以看到

先seek了非聚集索引,然后用 index seek把需要的行找出来。

这里的嵌套循环其实就是

———————————–总结——————————————————–

总结一下,在里根据找寻目标的不同和方法不同,有下面几种情况

寻找数据的方法

结构                                                   Scan                               Seek

堆(没有聚集索引的表格数据页)            Table Scan                          无

聚集索引                                       Index Scan           Index Seek

非聚集索引                                         Index Scan                     Index Seek

注意:非聚集索引的情况:(如果表格没有聚集索引的话数据还是存放在堆结构的表数据页,只是在非聚集索引里,

会为每条记录存储一份非聚集索引索引键的值和一份聚集索引索引键的值 (在没有聚集索引的表格里<strong style="font-weight: 600; color: #333333;”>sqlserver 建立索引,是RID值指向数据页面,

有聚集索引的话指向聚集索引的键) !!

为什麽不叫: Index Scan? Index Seek?

前面说了只有两种索引:聚集索引和非聚集索引

下面这两句话是一样的都是建立非聚集索引:

<pre style="background: #e8e8e8; color: #333333; padding: 1.2em; border-radius: 8px; overflow-x: auto; margin: 1.6em 0; font-family: ‘JetBrains Mono’, Consolas, monospace; font-size: 14px; line-height: 1.6;”>1 CREATE NONCLUSTERED INDEX SalesOrderDetail_test_NCL_Price ON [dbo].[SalesOrderDetail_test]([UnitPrice])
2 GO
3
4
5 CREATE INDEX SalesOrderDetail_test_NCL_Price ON [dbo].[SalesOrderDetail_test]([UnitPrice])
6 GO

所以就没有必要叫 Index Scan和 Index Seek了

————————————————–再总结————————————————————–

因为要说的太长<strong style="font-weight: 600; color: #333333;”>sqlserver 建立索引,没有办法,我都不知道怎么排版了

如果在执行计划里看到这些动作,就应该能知道正在对哪种对象在做什么样的操作。

表扫描表明正在处理的表格没有聚集索引,正在扫描整张表。

聚集索引扫描表明正在扫描一张有聚集索引的表,但是也是整张表扫描。

32,4090094138&fm=253&fmt=JPEG&app=138&f=JPEG?w=642&h=377″ alt=”sqlserver 建立索引”/ style=”max-width: 100%; height: auto; display: block; margin: 1.8em auto; border-radius: 10px; box-shadow: 0 4px 20px rgba(0,0,0,0.12);”>

Index Scan表明正在扫描一个非聚集索引。由于非聚集索引上一般只会有一小部分字段,

所以这里虽然也是扫描但是代价会比整表扫描会少很多,因为数据不存放在索引里面。

Index Seek和Index Seek说明SQL正在利用索引结果检索目标数据。如果结果集只占表格总数据量的一小部分

并且结果集的字段都包含在索引里,Seek会比Scan便宜很多,索引就起到了提高性能的作用,

否则就会引起 书签查找

————————————-再再总结——————————————————

(1)where 后面(筛选的字段):决定你建索引的时候要建的字段的范围,如果某个字段经常作为筛选字段那么可以在他上面建立索引

<pre style="background: #e8e8e8; color: #333333; padding: 1.2em; border-radius: 8px; overflow-x: auto; margin: 1.6em 0; font-family: ‘JetBrains Mono’, Consolas, monospace; font-size: 14px; line-height: 1.6;”>1 CREATE CLUSTERED INDEX SalesOrderDetail_test_CL ON [dbo].[SalesOrderDetail_test]([SalesOrderDetailID])

(2)where前面(返回的字段):决定你的表数据的查找速度,根据聚集索引来返回其他字段的值,没有聚集索引的话到数据页面里去找字段值

(3)聚集索引扫描:where后面的字段是没有建立索引【包括非聚集索引(表格上要有非聚集索引)和聚集索引】的字段

但是表格上有聚集索引 ,不管表格上有没有非聚集索引

(3)非聚集索引扫描:where后面的字段是没有建立索引(非聚集索引)的字段 ,但是表格上有非聚集索引但没有聚集索引

(4)表扫描:where后面的字段是没有建立索引的字段 并且表格上没有聚集索引和非聚集索引

(5)书签查找:where后面的字段建立了索引(不管是聚集索引还是非聚集索引),但是where前面返回的字段中有些没有建立索引

(不管是聚集索引还是非聚集索引)

个人意见:一般很少人会在建索引的时候在很多字段上建立索引不管是聚集索引还是非聚集索引,因为维护这些索引

需要成本,需要付出代价

<pre style="background: #e8e8e8; color: #333333; padding: 1.2em; border-radius: 8px; overflow-x: auto; margin: 1.6em 0; font-family: ‘JetBrains Mono’, Consolas, monospace; font-size: 14px; line-height: 1.6;”>1 CREATE INDEX SalesOrderDetail_test_NCL_Price ON [dbo].[SalesOrderDetail_test]([UnitPrice]。。。N个表字段)
2 GO

可以把经常被返回的列放到索引的里面去<strong style="font-weight: 600; color: #333333;”>sqlserver 建立索引,在不增加索引键大小的情况下尽可能覆盖尽可能多的列

这样当遇到某些查询,没有用到组合索引的先导列,但又感觉不值得为其建立索引时,若此查询用到得字段被组合索引实现了索引覆盖

可以参考的文章 这两篇文章都是博客园里的园友写的:

听风听雨

SQL 索引中的魅力(具有包含性列的索引)

Sql 查询性能优化之创建合理的索引(下篇)

非聚集索引的存在必要性:

个人觉得:如果可以为聚集索引指定包含性列,那么非聚集索引就没有什么用了。本人测试了一下

结果不能为聚集索引指定包含性列,应该是因为聚集索引把数据都存放到索引页

(上面提到在有聚集索引的表格上数据是直接存放在索引的最底层的)所以这些包含性索引列不能随意添加,

因为添加了会改变数据的存放顺序而非聚集索引就没有这个问题。

所以非聚集索引的存在还是很有必要的

377530/o_不能为聚集索引指定包含性列.jpg” alt=”sqlserver 建立索引”/ style=”max-width: 100%; height: auto; display: block; margin: 1.8em auto; border-radius: 10px; box-shadow: 0 4px 20px rgba(0,0,0,0.12);”>

今晚继续写第三篇  o(∩_∩)o

第三篇地址:是怎麽通过索引和统计信息来找到目标数据的(第三篇)

公告:
1. 本站所有资源来源于用户上传和网络,如有侵权请联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系站长处理!
6. 本站不售卖代码,资源标价只是站长收集整理的辛苦费!如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
7. 站长QQ号码 2205675299

资源库 - 资源分享下载网 » SQLSERVER是怎麽通过索引和统计信息来找到目标数据的(第二篇)

常见问题FAQ

关于资源售价和售后服务的说明?
本站所有资源的标价均为本站收集资源的辛苦费,不代表资源本身的价值。软件是高智慧高价值的商品,不可能是白菜价。本站资源标价只是赞助费用,收取的赞助费仅用来维持本站的日常运营!毕竟收集整理资料需要投入云计算资源和站长大量的精力。
代码有没有售后服务和技术支持?
由于代码的运行具有不可预见性,本站不保证代码完整可运行,不提供技术支持和售后服务。 本站原创代码都是站长自己开发的,可以有偿提供技术支持服务。 网站里标明【亲测】的代码都是站长亲测过的,其他的代码由于精力有限,没有一一测试,不能保证代码就一定能够使用,更没有技术支持服务,下载前请自行斟酌。
有没有搭建服务?
由于搭建服务比较费时费力,所以本站除了原创代码外均不提供搭建服务。本站分享代码纯属兴趣爱好,不以盈利为目的,请勿咨询有没有搭建服务,谢谢理解。
链接地址失效了怎么办?
请带上资源链接地址联系客服,工作时间内我们看到后将第一时间回复。
关于解压密码
本站资源一般都没有加密,如果发现需要解压密码的,那么就输入 hao.35dc.com 试试。

发表评论

资源库,由老程序员细心甄别、精心筛选,只为提供优质的源码资源

关于我们 联系我们