Sql server中内部函数fn_PhysLocFormatter存在解析错误详解

前端之家收集整理的这篇文章主要介绍了Sql server中内部函数fn_PhysLocFormatter存在解析错误详解前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

前言

有网友指出,sql Server 2012中fn_PhysLocFormatter内部函数在解析数据行记录位置时存在错误,见:http://www.itpub.net/thread-1751655-1-1.html,实际测试后发现,一是2008R2中同样存在问题,二是不仅页号解析存在问题,槽号解析也存在同样问题。

下面先查看表NT_SiteInfo的数据行记录位置。

sql;"> select SiteID,%%physloc%%,sys.fn_PhysLocFormatter(%%physloc%%) from NT_SiteInfo

SiteID

%%physloc%%

sys.fn_PhysLocFormatter(%%physloc%%)

1

0xE900000001000000

(1:59648:0)

23

0xE900000001000100

(1:59648:1)

24

0xE900000001000200

(1:59648:2)

</td&gt; <td&gt; <p>......</p> </td&gt; <td&gt; </td&gt; </tr&gt; <tr&gt; <td&gt; <p>149</p> </td&gt; <td&gt; <p>0xE900000001007F00</p> </td&gt; <td&gt; <p>(1:59648:127)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>150</p> </td&gt; <td&gt; <p>0xE900000001008000</p> </td&gt; <td&gt; <p>(1:59648:128)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>151</p> </td&gt; <td&gt; <p>0xE900000001008100</p> </td&gt; <td&gt; <p>(1:59648:33024)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>152</p> </td&gt; <td&gt; <p>0xE900000001008200</p> </td&gt; <td&gt; <p>(1:59648:33280)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; </td&gt; <td&gt; <p>......</p> </td&gt; <td&gt; </td&gt; </tr&gt; <tr&gt; <td&gt; <p>226</p> </td&gt; <td&gt; <p>0xE90000000100CC00</p> </td&gt; <td&gt; <p>(1:59648:52224)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>227</p> </td&gt; <td&gt; <p>0xE90000000100CD00</p> </td&gt; <td&gt; <p>(1:59648:52480)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>228</p> </td&gt; <td&gt; <p>0x4B02000001000000</p> </td&gt; <td&gt; <p>(1:587:0)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>229</p> </td&gt; <td&gt; <p>0x4B02000001000100</p> </td&gt; <td&gt; <p>(1:587:1)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; </td&gt; <td&gt; <p>......</p> </td&gt; <td&gt; </td&gt; </tr&gt; <tr&gt; <td&gt; <p>360</p> </td&gt; <td&gt; <p>0x4B02000001007F00</p> </td&gt; <td&gt; <p>(1:587:127)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>361</p> </td&gt; <td&gt; <p>0x4B02000001008000</p> </td&gt; <td&gt; <p>(1:587:128)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>362</p> </td&gt; <td&gt; <p>0x4B02000001008100</p> </td&gt; <td&gt; <p>(1:587:33024)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>363</p> </td&gt; <td&gt; <p>0x4B02000001008200</p> </td&gt; <td&gt; <p>(1:587:33280)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; </td&gt; <td&gt; <p>......</p> </td&gt; <td&gt; </td&gt; </tr&gt; <tr&gt; <td&gt; <p>422</p> </td&gt; <td&gt; <p>0x4B0200000100BD00</p> </td&gt; <td&gt; <p>(1:587:48384)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>423</p> </td&gt; <td&gt; <p>0x4B0200000100BE00</p> </td&gt; <td&gt; <p>(1:587:48640)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>424</p> </td&gt; <td&gt; <p>0x3C05000001000000</p> </td&gt; <td&gt; <p>(1:1340:0)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>425</p> </td&gt; <td&gt; <p>0x3C05000001000100</p> </td&gt; <td&gt; <p>(1:1340:1)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; </td&gt; <td&gt; <p>......</p> </td&gt; <td&gt; </td&gt; </tr&gt; <tr&gt; <td&gt; <p>552</p> </td&gt; <td&gt; <p>0x3C05000001008000</p> </td&gt; <td&gt; <p>(1:1340:128)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>553</p> </td&gt; <td&gt; <p>0x3C05000001008100</p> </td&gt; <td&gt; <p>(1:1340:33024)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; </td&gt; <td&gt; </td&gt; <td&gt; </td&gt; </tr&gt; <tr&gt; <td&gt; <p>596</p> </td&gt; <td&gt; <p>0x3C0500000100AC00</p> </td&gt; <td&gt; <p>(1:1340:4<a href="/tag/403/" target="_blank" class="keywords">403</a>2)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; <p>597</p> </td&gt; <td&gt; <p>0x9978000001000000</p> </td&gt; <td&gt; <p>(1:39288:0)</p> </td&gt; </tr&gt; <tr&gt; <td&gt; </td&gt; <td&gt; <p>......</p> </td&gt; <td&gt; </td&gt; </tr&gt; <tr&gt; <td&gt; <p>658</p> </td&gt; <td&gt; <p>0x9978000001003D00</p> </td&gt; <td&gt; <p>(1:39288:61)</p> </td&gt; </tr&gt;

下面查看表NT_SiteInfo分配的数据页情况。

sql;"> dbcc ind(wjgk,nt_siteinfo,0)

PagePID

IAMFID

IAMPID

PageType

IndexLevel

NextPagePID

PrevPagePID

238

NULL

NULL

10

NULL

0

0

233

1

238

1

0

587

0

587

1

238

1

0

1340

233

1340

1

238

1

0

30873

587

30873

1

238

1

0

0

1340

Microsoft未公开的伪列%%physloc%%,类型为Binary(8),返回表中记录的RowID,格式是:前4字节表示页号,中间2字节表示文件号,最后2字节表示槽号。

对照上面的实际数据,可以发现sys.fn_PhysLocFormatter在解析记录位置时,既有采用高字节在前的BIG_ENDIAN格式,又有采用低字节在前的LITTLE_ENDIAN格式,造成采用高字节在前的BIG_ENDIAN格式解析的数据错误

页号解析:


E9000000解析为59648(E900),错误,实际应为233(E9)

4B020000解析为576(24B),正确

3C050000解析为1340(53C),正确

99780000解析为39288(9978),错误,实际应为30873(7899)

槽号解析:


8000解析为128(0080),正确

8100解析为33024(8100),错误,应为129(0081)

下面给出错误原因。

先看下sys.fn_PhysLocFormatter函数的定义:

sql;"> select OBJECT_DEFINITION(object_id('sys.fn_PhysLocFormatter')) go

-- Name: sys.fn_PhysLocFormatter

-- Description:
-- Formats the output of %%physloc%% virtual column

-- Notes:

create function sys.fn_PhysLocFormatter (@physical_locator binary (8))
returns varchar (128)
as
begin
declare @page_id binary (4)
declare @file_id binary (2)
declare @slot_id binary (2)
-- Page ID is the first four bytes,then 2 bytes of page ID,then 2 bytes of slot

select @page_id = convert (binary (4),reverse (substring (@physical_locator,1,4)))
select @file_id = convert (binary (2),5,2)))
select @slot_id = convert (binary (2),7,2)))
return '(' + cast (cast (@file_id as int) as varchar) + ':'

  • cast (cast (@page_id as int) as varchar) + ':'
  • cast (cast (@slot_id as int) as varchar) + ')'
    end

再看下reverse函数

(1 行受影响)

select reverse('12345工人')

人工54321

(1 行受影响)

select reverse('工12345人')

人54321工

(1 行受影响)

结论:

问题出在reverse函数上。

reverse函数的作用是字符反转,而不是字节反转,当遇到81-FE之间的字节时,被认为是双字节字符而组合在一起参与反转操作,造成了错误

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对编程之家的支持

猜你在找的MsSQL相关文章