堆表、回表、索引覆盖、主键索引、聚集索引等一些知识点

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%'
堆表.png

从实际计划中可以看到。因为二级索引 ix_testIndex 没有 我需要的所有列,所以需要回表拿更多数据,但从图中看到,这次回表走的是heap堆表回表拿数据.

我们再创建一个主键索引,将这个主键索引创建为非聚集的

ALTER TABLE testIndex ADD  CONSTRAINT [PK_testIndex] PRIMARY KEY NONCLUSTERED (ID)

看一下现在的索引情况


indexs.png

然后再看上一个语句

select * from testIndex with(index(ix_testIndex))
where tname like 'ad%'

再看执行计划


堆表.png

回表还是走的堆表

我们继续,创建一个聚集索引

create CLUSTERED index clx_testIndex on testIndex(id)

看一下现在的索引


indexs.png

继续执行

select * from testIndex with(index(ix_testIndex))
where tname like 'ad%'
query.png

从执行计划中看到。这次索引没有回表。在二级索引上拿到了所有需要的数据,完成了索引覆盖,那就可以证明二级索引ix_testIndex 叶子节点存储的就是聚集索引id列的值。

再改一下语句 强制走主键索引

select * from testIndex with(index(PK_testIndex))
where tname like 'ad%'
priindex.png

从执行计划中可以看出,由于主键索引只有 id列,聚集也只有id列,所以主键索引拿不到tname列 需要回表, 这次回表就是回的聚集索引了。

所以sql server与mysql 还是有很大我区别。

1、sql server 主键索引只是一个约束,只有当它是聚集索引的时候,二级索引叶子节点才是主键的值
2、没有聚集索引的时候, 就是堆表,而不是索引组织表
3、有聚集索引的时候,就变成了索引组织表
4、二级索引叶子节点,存储的是聚集索引列的值。

你可能感兴趣的:(堆表、回表、索引覆盖、主键索引、聚集索引等一些知识点)