何时使用聚集索引或非聚集索引 (一)

何时使用聚集索引或非聚集索引 (一)

 
下面的表总结了何时使用聚集索引或非聚集索引(很重要)。 


动作描述                           使用聚集索引 使用非聚集索引 
外键列                                 应                    应 
主键列                                 应                      应 
列经常被分组排序(order by) 应                    应 
返回某范围内的数据              应                   不应 
小数目的不同值                   应                     不应 
大数目的不同值                     不应                应 
频繁更新的列                      不应               应 
频繁修改索引列                  不应                应 
一个或极少不同值              不应                不应 
 
 
 
通过非聚集索引,提升select count(*) from 的查询速度的本质在于,非聚集索引所占空间的大小往往,远小于聚集索引或堆表所占用的空间大小;
同样的,表中占用较少字节的字段的非聚集索引,对于速度的提升效果,也要远大于,占用较多字节的字段的非聚集索引,因为占用字节少,那么索引占用的空间也少,同样扫描,只需要更少的时间,对硬盘的访问次数也更少,那么速度就会更快了。
 
 
那“对聚集表查询的时候,未显式指定排序列的时候,默认查询结果的顺序一定按什么顺序?”
这个问题,最准确的答案怎么描述呢?

1、按索引中占用空间最小的索引顺序。
2、按逻辑读最小的查询顺序
3、按执行计划
4、大家可以描述下.....

我认为3,但这又废话。哈哈。
 
属于表覆盖索引,掌握聚集索引和非聚集索引结构,理解索引查询原理和数据库引擎选择,用覆盖索引比聚集索引小,查询速度更快,叶子级指针指向数据记录不需要聚集索引目录一级级向下找
 
 
 
 
 
 
 
 
表是按聚集索引排序的吗?
 
 
显示结果为
id    name
4      a
3      b
2      c
1      d
为什么显示结果不是按聚集索引的id字段排序,而是按非聚集索引的name字段排序呢?哪位大哥能解释一下
 
 
 
 
 
仔细看了一下,楼主确实是把id列作为主键,而且也作为了聚集索引,而name是非聚集索引

我运行了下面的两个语句:
1
2
3
4
5
<br>
select from a<br>
<br>
--通过查询提示,强制使用<strong>聚集索引</strong>PK_a<br>
select from with(index (PK_a))<br>


下面是两个语句的执行计划:


这个到底为什么不按照聚集索引排序,而非得按照非聚集索引来排序,这个是由sql server的优化器来决定的,sql server 的优化器通过一堆的判断,最后生成了(在不影响结果正确性的前提下的)这样的执行计划,但可能不一定符合我的要求。

这种查询提示,实本质上就是手动给SQL Server的优化器建议,建议他采用聚集索引,之所以微软会提供这种查询提示,就是已经预料到会有你所遇到的问题,所以才提供了这种可以由你来进行微调的技术。
 
 
 
 
 
 

对聚集表查询的时候,未显式指定排序列的时候,默认查询结果的顺序一定是按照聚集索引顺序排序的吗

本文之外可参考另外一篇文章作为补充:http://www.cnblogs.com/wy123/p/6189100.html

 

在sql server 中,如果一张表存在聚集索引的时候,
大多数情况下,如果进行select * from TableName查询,默认的返回顺序是按照聚集所在列的顺序返回的
但是,在一张表存在聚集索引的时候,并不一定所有的情况都是按照聚集索引列的顺序排列的,
下面开始测试

1
2
3
4
5
6
7
8
9
create table TestDefaultOrder
(
    Id int identity(1,1) primary key,--主键上默认会建立聚集索引
    Col2 char(5),
    COL3 char(5)
)
--写入100000条测试数据
insert into TestDefaultOrder  values (SUBSTRING(cast(NEWID() as varchar(50)),1,5),SUBSTRING(cast(NEWID() as varchar(50)),1,5))
go 100000

如下查询完全没有问题,正如你所预料的,按照聚集索引所在的列(Id)排序的,完全没有问题,下面开始切入正题

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
--创建一张同样的对照表
create table TestDefaultOrder_Contrast
(
    Id int identity(1,1) primary key,--主键上默认会建立聚集索引
    Col2 char(5),
    COL3 char(5)
)
 
--将TestDefaultOrder表中的数据写入进去,目前,两张表的数据和索引结构一模一样
insert into TestDefaultOrder_Contrast (Col2,Col3) 
select Col2,Col3 from TestDefaultOrder
 
--仅仅在对照表上创建一个非聚集索引,这是唯一的不同点
Create Index idx2 on TestDefaultOrder_Contrast(Col2,Col3)

接下来的查询,或许会有一点一点出乎你的意料,

上面说了,两张表的数据是一模一样的,聚集索引结构也是一样的,只是对照表多个一个非聚集索引

发现对照表的结果返回顺序,根本是按照聚集索引的排序返回的

 

那么原因在哪里呢?我们要从不同类似索引占用的空间情况进行分析,通过dm_db_index_physical_stats发现,在数据数据完全一致的情况下,

因为TestDefaultOrder_Contrast这个表上的非聚集索引,占用的空间更少(248个page,而TestDefaultOrder的聚集索引是285个page),

正因为此,sqlserver在进行全表扫描的时候,会选择一个代价更小的索引(进行扫描),

因为TestDefaultOrder表上只有一个聚集索引,按照聚集索引扫描进行查询,返回的结果的顺序是按照聚集索引列排序的

但是TestDefaultOrder_Contrast就不同了,因为在非聚集索引idx2 上,包含了全部的数据(Col2,Col3以及指向聚集索引键值的Id),

但idx2这个索引是占用的空间更小,所以对于TestDefaultOrder_Contrast的查询,是按照idx2这个非聚集索引进行扫描的

 

因为,在TestDefaultOrder_Contrast这个表上,

直接select * TestDefaultOrder_Contrast进行查询的话,

跟对表TestDefaultOrder进行 select * TestDefaultOrder查询

是用两种完全不同的方式进行的,出来的结果自然也就不同了

 

 

而事实上,sqlserver在对TestDefaultOrder_Contrast进行查询的时候,通过走idx2这个索引扫描,代价确实要比TestDefaultOrder的聚集索引扫描,代价要小

 

如果有兴趣的话,再次分析为什么存储同样的数据(TestDefaultOrder上的聚集索引和TestDefaultOrder_Contrast的非聚集索引idx2),

TestDefaultOrder表上的聚集索引,要比TestDefaultOrder_Contrast上的idx2(Create Index idx2 on TestDefaultOrder_Contrast(Col2,Col3))占用的空间大呢

这里的原因在于,一个表上的聚集索引(于非聚集索引相比),除了要存储数据,要维护的信息更多的元数据信息,占用的空间自然就较多一点

而sqlserver在进行查询的时候,总是会选择一个代价相对较低的方式。

 

总结:千万不要以为,只要表上建立了聚集索引,在查询的时候,返回结果的默认的排序方式,是按照聚集索引来的

 

 

 

后记:为什么要研究这个问题?

因为之前遇到过,某些查询没有显式指定排序列,但是借助表上聚集索引,返回结果的时候,会得一个想要的顺序。

这种情况其实会潜在一种问题,如果发生类似上面这种情况,想要对查询结果按照聚集索引的顺序排序,而又不显式制定排序列,查询结果的显示顺序,可就不一定了。

 

 
分类: [SQL]索引
 
 
« 上一篇:Buffer cache hit ratio性能计数器真的可以作为内存瓶颈的判断指标吗?
» 下一篇:通过手动创建统计信息优化sql查询性能案例

posted on 

posted @   阿玛  阅读(695)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
历史上的今天:
2015-04-21 转发:IT行业中的甲方乙方关系
点击右上角即可分享
微信分享提示