mysql 一定是索引组织表,且主键索引一定也是聚集索引。 所以 mysql 二级索引的叶子节点一定存放的是主键的值。
受mysql 影响,我也一度以为sql server 二级索引叶子节点也是存储的主键索引。但实际不一定是。
下面通过一个例子来慢慢探究一下
先构造一个测试数据,并创建一个二级索引
create table testIndex
(id int,
tname varchar(50)
)
insert into testIndex
select ROW_NUMBER() over(order by name),name from sys.objects where type = 'U'
create index ix_testIndex on testIndex(tname)
然后,我们写一个查询,强制走二级索引
select * from testIndex with(index(ix_testIndex))
where tname like 'ad%'
从实际计划中可以看到。因为二级索引 ix_testIndex 没有 我需要的所有列,所以需要回表拿更多数据,但从图中看到,这次回表走的是heap堆表回表拿数据.
我们再创建一个主键索引,将这个主键索引创建为非聚集的
ALTER TABLE testIndex ADD CONSTRAINT [PK_testIndex] PRIMARY KEY NONCLUSTERED (ID)
看一下现在的索引情况
然后再看上一个语句
select * from testIndex with(index(ix_testIndex))
where tname like 'ad%'
再看执行计划
回表还是走的堆表
我们继续,创建一个聚集索引
create CLUSTERED index clx_testIndex on testIndex(id)
看一下现在的索引
继续执行
select * from testIndex with(index(ix_testIndex))
where tname like 'ad%'
从执行计划中看到。这次索引没有回表。在二级索引上拿到了所有需要的数据,完成了索引覆盖,那就可以证明二级索引ix_testIndex 叶子节点存储的就是聚集索引id列的值。
再改一下语句 强制走主键索引
select * from testIndex with(index(PK_testIndex))
where tname like 'ad%'
从执行计划中可以看出,由于主键索引只有 id列,聚集也只有id列,所以主键索引拿不到tname列 需要回表, 这次回表就是回的聚集索引了。
所以sql server与mysql 还是有很大我区别。
1、sql server 主键索引只是一个约束,只有当它是聚集索引的时候,二级索引叶子节点才是主键的值
2、没有聚集索引的时候, 就是堆表,而不是索引组织表
3、有聚集索引的时候,就变成了索引组织表
4、二级索引叶子节点,存储的是聚集索引列的值。