为什么不按聚集索引排序而按非聚集索引排序

Cassava 2013-10-28 10:08:56
下面为测试语句:

CREATE TABLE [dbo].[a](
[id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NULL,
CONSTRAINT [PK_a] PRIMARY KEY CLUSTERED
(
[id] ASC
)
)
CREATE UNIQUE NONCLUSTERED INDEX [IX_a] ON [dbo].[a]
(
[name] ASC
)
GO
insert a(name)
select 'd'
union all
select 'c'
union all
select 'b'
union all
select 'a'

select * from a

显示结果为
id name
4 a
3 b
2 c
1 d
为什么显示结果不是按聚集索引的id字段排序,而是按非聚集索引的name字段排序呢?哪位大哥能解释一下
...全文
677 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
lenxuekuangmo 2016-06-30
  • 打赏
  • 举报
回复
我也是醉了,害我查了半天,难道以后要查数据的时候,全部要手动排序一遍。。。
dongdongdongJL 2013-11-02
  • 打赏
  • 举报
回复
学习,果然深入!看了很多关于聚集索引的内容。呵呵,不过我想问问,提问题的人, 你为什么是希望这个查找是聚集索引查找的哪?难道是为了效率吗?
LongRui888 2013-10-28
  • 打赏
  • 举报
回复
另外,虽然你已经建立了聚集索引,但sql server 并不知道你要按照哪一列的顺序,返回结果集,虽然sql server选择了非聚集索引,但结果是正确的。

这种情况下,直截了当的指明,你想按照哪个字段排序,比如这样就可以:


select * from a
order by id
/*
id name
1 d
2 c
3 b
4 a
*/


这个是执行计划,我们可以看到,虽然加了order by,但是并没有排序,因为可以直接通过访问聚集索引,里面的数据已经按照id来排过序了,所以就不用再次排序了:
Cassava 2013-10-28
  • 打赏
  • 举报
回复
还是加order by id吧,看来默认是显示非聚集索引的排序了
LongRui888 2013-10-28
  • 打赏
  • 举报
回复
仔细看了一下,楼主确实是把id列作为主键,而且也作为了聚集索引,而name是非聚集索引。

我运行了下面的两个语句:

select * from a

--通过查询提示,强制使用聚集索引PK_a
select * from a with(index (PK_a))


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


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

这种查询提示,实本质上就是手动给SQL Server的优化器建议,建议他采用聚集索引,之所以微软会提供这种查询提示,就是已经预料到会有你所遇到的问题,所以才提供了这种可以由你来进行微调的技术。
發糞塗牆 2013-10-28
  • 打赏
  • 举报
回复
select * from a WITH (INDEX=[PK_a])你加这个,让查询强制使用聚集索引,可以对比开销,其实是一样的,我不知道是不是sqlserver在开销一样的前提下优先使用非聚集索引。如何排序,首先要先知道用了哪个索引。如果优化器决定使用非聚集,那会按照非聚集的顺序来排序,如果选择聚集,就会使用聚集来排序.你用我上面的语句,可以看到是按id排序了。
Cassava 2013-10-28
  • 打赏
  • 举报
回复
引用
主键又不一定是聚集索引。只是在未指定聚集索引的时候,主键才默认为聚集索引。
表的默认排序是根据聚集索引来的

我不单指定id为主键,也指定了id为聚集索引了啊,但不按聚集索引的id字段来排序啊,是什么原因啊,难道加了非聚集索引就按非聚集索引排序吗?这是什么道理啊
Cassava 2013-10-28
  • 打赏
  • 举报
回复
我测试了select id from a也是按非聚集索引排序的啊,还是搞不懂为什么不按聚集索引的id字段排序,而按非聚集索引的name字段排序,我看了不少聚集索引和非聚集索引的资料,聚集索引写明了该索引中键值的逻辑顺序决定了表中相应行的物理顺序,难道select显示的默认顺序不是物理顺序吗?搞不明白啊
發糞塗牆 2013-10-28
  • 打赏
  • 举报
回复
你用了*号,如果用select id from a就不会了,由于*号包含了name列,优化器需要借助非聚集索引来查找,所以最后选择用非聚集索引,而不是用聚集索引
發糞塗牆 2013-10-28
  • 打赏
  • 举报
回复
因为它用了非聚集索引,索引按照非聚集索引排序
Cassava 2013-10-28
  • 打赏
  • 举报
回复
我没有把name字段建为聚集索引啊,name为非聚集索引
你上面的语句把name字段建立的唯一索引去掉了,不可以去掉name字段的唯一非聚集索引,因为我需要这个唯一索引对name字段进行唯一约束
--小F-- 2013-10-28
  • 打赏
  • 举报
回复
主键又不一定是聚集索引。只是在未指定聚集索引的时候,主键才默认为聚集索引。 表的默认排序是根据聚集索引来的
發糞塗牆 2013-10-28
  • 打赏
  • 举报
回复
如果是单列索引,就按定义的那列来排序,如果是多列,会先按第一列排序,如果第一列有相同的数据,才按第二列,以此类推
發糞塗牆 2013-10-28
  • 打赏
  • 举报
回复
CREATE TABLE [dbo].[a](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [name] [varchar](50) NULL,
 CONSTRAINT [PK_a] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)
)
CREATE UNIQUE NONCLUSTERED INDEX [IX_a] ON [dbo].[a] 
(
    id ASC
)
GO
insert a(name)
select 'd'
union all
select 'c'
union all
select 'b'
union all
select 'a'
 
select * from a

/*
id          name
----------- --------------------------------------------------
1           d
2           c
3           b
4           a
*/
發糞塗牆 2013-10-28
  • 打赏
  • 举报
回复
因为你按name字段来做聚集,如果你要按id来排序,需要用id作为聚集列的第一行
昵称被占用了 2013-10-28
  • 打赏
  • 举报
回复
没有oeder by子句,结果理论上是没有次序的
Andy__Huang 2013-10-28
  • 打赏
  • 举报
回复
引用 11 楼 yupeigu 的回复:
仔细看了一下,楼主确实是把id列作为主键,而且也作为了聚集索引,而name是非聚集索引。 我运行了下面的两个语句:

select * from a

--通过查询提示,强制使用聚集索引PK_a
select * from a with(index (PK_a))
下面是两个语句的执行计划: 这个到底为什么不按照聚集索引排序,而非得按照非聚集索引来排序,这个是由sql server的优化器来决定的,sql server 的优化器通过一堆的判断,最后生成了(在不影响结果正确性的前提下的)这样的执行计划,但可能不一定符合我的要求。 这种查询提示,实本质上就是手动给SQL Server的优化器建议,建议他采用聚集索引,之所以微软会提供这种查询提示,就是已经预料到会有你所遇到的问题,所以才提供了这种可以由你来进行微调的技术。
比较赞同!

34,590

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧