当前位置: 首页 > 科技观察

SQLServer中一个隐藏的IO性能杀手_0

时间:2023-03-12 19:07:33 科技观察

存储原理在SQLServer中,当数据以堆的形式存储时,数据是乱序的,所有非聚集索引的指针存储的是指向物理地址的RID.当数据行中的变长列增长到原来的页无法容纳数据行时,数据就会被移动到新的页中,并且在原来的位置留下指向新页的指针。当Record有更新时,所有非聚集索引的指针都不会改变。如图1所示。图1.ForwardedRecord示意图之所以称为ForwardedRecord,是因为在原来的位置只剩下一个指针,指向由于数据更新而产生的新数据页所在的行。ForwardedRecord如何影响IO性能?那么既然ForwardedRecord是一种提升性能的机制,为什么会造成性能问题呢?ForwardedRecord的初衷是在更新堆表时,堆表上存储位置的变化不会造成同时更新非聚集索引的开销。但是对于查找,无论是对堆表进行表扫描还是用于书签查找,额外的IO开销都会成倍增加。让我们看一个例子。CREATETABLEEdbo.HeapTest(idINT,col1VARCHAR(800))DECLARE@indexINTSET@index=0BEGINTRANWHILE@index<100000BEGININSERTIINTOdbo.HeapTest(id,col1)VALUES(@index,NULL)SET@index=@index+1ENDCOMMIT代码列表1。新建堆表并插入10万条数据通过代码清单1创建一张测试表,循环插入10万条数据。此时,我们再看一下堆表占用的存储页数,如图2所示。图2.堆表的空间占用此时更新表,增加原来的行,生成一个ForwardedRecord。这时候再看堆表的存储。如图3所示。图3.生成的8W+条转发记录此时我们注意到,虽然数据只占了590页,但是却有8W+条转发记录。如果我们扫表就会发现,虽然只有590页,但是需要8W+的逻辑IO,大大增加了IO的开销压力。另外,由于转发的记录页和原始页在物理上往往不连续,对IOPS也有挑战。如图4所示。图4.不应该产生的额外IO开销,上面的查询反映在性能计数器中,呈现出图5所示的结果。图5.如何解决ForwardedRecord计数器的增长。当您看到ForwardedRecord计数器时,这意味着数据库中有堆表。在OLTP系统中,所有的表都应该有聚簇索引。所以这个问题可以通过给表加一个聚簇索引来解决。一般来说,只写只读表不设置为堆表比较合适,但是如果看到ForwardedReocord,说明堆表有读操作,然后找到堆表,找到一个在合适的维护窗口时间创建一个堆A表是一个理想的选择。如果因为其他原因无法创建聚簇索引,可以对堆表进行建表。原文链接:http://www.cnblogs.com/CareySon/p/3829019.html