mysql什么情况索引会重排_聚集索引更新后会不会马上重新排序

聚集索引更新后会不会马上重新排序

今天在QQ群里有人问到下面问题

b9aa74028ef63638e567b7fece1518c8.png

提问人用的是MYSQL,不过这个问题让我想起了SQLSERVER的万圣节问题

万圣节问题就是因为更新了非聚集索引之后,非聚集索引迅速排序导致的更新错误问题

当时我只是测试了非聚集索引下面的情况,但是聚集索引下面有没有这种情况呢?

我们修改一下

使用下面SQL脚本建立测试环境

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 USEmaster2 GO

3 CREATE DATABASESpool4 GO

5

6 USE [Spool]

7 GO

8

9

10 --建表

11 CREATE TABLEHalloween12 (13 ID INT IDENTITY(1, 1),14 Name VARCHAR(30) ,15 Salary NUMERIC(18, 2),16 Remark NVARCHAR(3000)17 )18 GO

19

20 --插入数据

21 INSERT INTO [dbo].[Halloween] ( [Name], [Salary], [Remark])22 SELECT '小明',1,replicate('a', 3000) UNION ALL

23 SELECT '小方',2,replicate('a', 3000)24

25

26

27

28 --建立聚集索引

29 CREATE CLUSTERED INDEX ix_Halloween ON Halloween(Salary ASC,[name])30 GO

31

32 --查询

33 SELECT * FROMHalloween34 GO

View Code

f7e958f0685a4a6313bd817641f9cc76.png

我们用下面SQL语句看一下聚集索引页面

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 CREATE TABLEDBCCResult (2 PageFID NVARCHAR(200),3 PagePID NVARCHAR(200),4 IAMFID NVARCHAR(200),5 IAMPID NVARCHAR(200),6 ObjectID NVARCHAR(200),7 IndexID NVARCHAR(200),8 PartitionNumber NVARCHAR(200),9 PartitionID NVARCHAR(200),10 iam_chain_type NVARCHAR(200),11 PageType NVARCHAR(200),12 IndexLevel NVARCHAR(200),13 NextPageFID NVARCHAR(200),14 NextPagePID NVARCHAR(200),15 PrevPageFID NVARCHAR(200),16 PrevPagePID NVARCHAR(200)17 )18

19 --TRUNCATE TABLE [dbo].[DBCCResult]

20 INSERT INTO DBCCResult EXEC ('DBCC IND(spool,Halloween,-1)')21

22 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC

View Code

聚集索引页面

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 DBCC TRACEON(3604,-1)2 GO

3 DBCC PAGE(spool,1,174,3)4 GO

View Code

210f25ca4fe176046ea997fd0cf03774.png

b2789bb8671e4ed548fd8e1e6bc94d83.png

我们update一下Salary等于1的那位员工的工资

1 UPDATE Halloween SET Salary = 2.5

2 FROMHalloween3 WHERE Salary =1

再看一下聚集索引页面

0adb0e6d73258fffefa9861d03be2122.png

可以看到SQLSERVER增加了页面89来保存结果,就是说聚集索引也是在更新之后马上排序的

b98c42b031e8ae4a7645dde95d208528.png

那么页面89和页面109里面到底有什么内容呢?

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 DBCC TRACEON(3604,-1)2 GO

3 DBCC PAGE(spool,1,109,3)4 GO

View Code

数据页面109

1 PAGE: (1:109)2

3

4

5 UNIQUIFIER = [NULL]

6

7 Slot 0 Column 1 Offset 0x4 Length 9

8

9 Salary = 1.00

10

11 Slot 0 Column 2 Offset 0x1c Length 4

12

13 Name =小明14

15 Slot 0 Column 3 Offset 0xd Length 4

16

17 ID = 1

18

19 Slot 0 Column 4 Offset 0x20 Length 6000

20

21 Remark = aaaa

数据页面89

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 DBCC TRACEON(3604,-1)2 GO

3 DBCC PAGE(spool,1,89,3)4 GO

View Code

1 PAGE: (1:89)2

3 Slot 0 Column 1 Offset 0x4 Length 9

4

5 Salary = 2.50

6

7 Slot 0 Column 2 Offset 0x1c Length 4

8

9 Name =小明10

11 Slot 0 Column 3 Offset 0xd Length 4

12

13 ID = 1

14

15 Slot 0 Column 4 Offset 0x20 Length 6000

16

17 Remark = aaa

大家马上会问:为什麽109这个页面不删除他,还存放着旧的记录,留在那里占用空间???

除非你重组聚集索引或者重建聚集索引,不然的话SQLSERVER不会马上删除页面的

当你又插入一条记录,并且这条记录的Salary小于2,那么SQLSERVER就会把这条记录保存到109这个页面

1 INSERT INTO [dbo].[Halloween] ( [Name], [Salary], [Remark])2 SELECT '小新',1,replicate('a', 3000)

看一下Halloween表的页面分配情况

5b4cfb342eb51ac9e2cb484978d76af5.png

还是那几个页面,没有变化

现在看一下109这个页面

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 DBCC TRACEON(3604,-1)2 GO

3 DBCC PAGE(spool,1,109,3)4 GO

View Code

1 PAGE: (1:109)2

3

4 UNIQUIFIER = [NULL]

5

6 Slot 0 Column 1 Offset 0x4 Length 9

7

8 Salary = 1.00

9

10 Slot 0 Column 2 Offset 0x1c Length 4

11

12 Name =小新13

14 Slot 0 Column 3 Offset 0xd Length 4

15

16 ID = 3

17

18 Slot 0 Column 4 Offset 0x20 Length 6000

19

20 Remark = aaa

关于第一张图片的结果

堆表脚本

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 CREATE TABLEHalloween22 (3 ID INT,4 Name VARCHAR(30) ,5 Salary NUMERIC(18, 2),6 Remark NVARCHAR(3000)7 )8 GO

9

10 --插入数据

11 INSERT INTO [dbo].[Halloween2] ([id] ,[Name], [Salary], [Remark])12 SELECT 1, '小明',2,replicate('a', 3000) UNION ALL

13 SELECT 2, '小方',3,replicate('a', 3000)14

15

16

17

18

19 --查询

20 SELECT * FROMHalloween221 GO

22

23 UPDATEHalloween224 SET Salary = id ,[id] =salary25

26 --查询

27 SELECT * FROMHalloween228 GO

View Code

1eb7f8b0a4a2e29e175611fe5035bb91.png

更新时候的执行计划

235ff24436d1367b9fb61e2efc5acba5.png

聚集索引表脚本

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 CREATE TABLEHalloween32 (3 ID INT,4 Name VARCHAR(30) ,5 Salary NUMERIC(18, 2),6 Remark NVARCHAR(3000)7 )8 GO

9

10 --插入数据

11 INSERT INTO [dbo].[Halloween3] ([id] ,[Name], [Salary], [Remark])12 SELECT 1, '小明',2,replicate('a', 3000) UNION ALL

13 SELECT 2, '小方',3,replicate('a', 3000)14

15 --建立聚集索引

16 CREATE CLUSTERED INDEX ix_Halloween ON Halloween3(Salary ASC,[name])17 GO

18

19

20

21 --查询

22 SELECT * FROMHalloween323 GO

24

25 UPDATEHalloween326 SET Salary = id ,[id] =salary27

28 --查询

29 SELECT * FROMHalloween330 GO

View Code

9f7b6e4df9d166e1d70312627e9a2786.png

更新时候的执行计划

5f1633c72f3b19cc2e9f3ed4f4fab3dd.png

非聚集索引表脚本

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 CREATE TABLEHalloween42 (3 ID INT,4 Name VARCHAR(30) ,5 Salary NUMERIC(18, 2),6 Remark NVARCHAR(3000)7 )8 GO

9

10 --插入数据

11 INSERT INTO [dbo].[Halloween4] ([id] ,[Name], [Salary], [Remark])12 SELECT 1, '小明',2,replicate('a', 3000) UNION ALL

13 SELECT 2, '小方',3,replicate('a', 3000)14

15 --建立非聚集索引

16 CREATE NONCLUSTERED INDEX ix_Halloween ON Halloween4(Salary ASC,[name])17 GO

18

19

20

21 --查询

22 SELECT * FROMHalloween423 GO

24

25 UPDATEHalloween426 SET Salary = id ,[id] =salary27

28 --查询

29 SELECT * FROMHalloween430 GO

View Code

77fd1793b0c090261701c29a05a2fbdb.png

更新时候的执行计划

8a1f318265424a4cc0ce82c90f632c91.png

总结

聚集索引也会引起万圣节问题

61b008a6cbc63fb4218c8c4085cacd53.png

万圣节问题:重新排序导致的更新记录错误

聚集索引更新了之后也会重新排序,所以你看到上面聚集索引表的结果

5f1633c72f3b19cc2e9f3ed4f4fab3dd.png

中间也会有一个表假脱机的运算符

而非聚集索引的执行计划为什麽没有呢?

因为非聚集索引那个扫描的是堆里的数据页面,而不是扫描非聚集索引页面,

只有扫描非聚集索引页面才会出现万圣节问题,更新了非聚集索引之后马上进行排序

而堆里的数据页面无论怎麽更新都不会重新排序的

这里归纳一下重新排序的情况

重新排序:扫描聚集索引(聚集索引表)、扫描非聚集索引(非聚集索引表)

不重新排序:扫描堆里的数据页面(非聚集索引表)、堆表

非聚集索引比较特殊,因为索引页面和数据页面是分开的,所以要分两种情况

如有不对的地方,欢迎大家拍砖o(∩_∩)o

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值