国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > 綜合 > 正文

解剖SQLSERVER 第十三篇 Integers在行壓縮和頁壓縮里的存儲格式揭秘(譯)

2024-07-21 02:48:55
字體:
供稿:網(wǎng)友
解剖SQLSERVER 第十三篇 Integers在行壓縮和頁壓縮里的存儲格式揭秘(譯)解剖SQLSERVER 第十三篇 Integers在行壓縮和頁壓縮里的存儲格式揭秘(譯)

http://imPRove.dk/the-anatomy-of-row-amp-page-compressed-integers/

當(dāng)解決OrcaMDF對行壓縮的支持的時候,視圖解析整數(shù)的時候遇到了一些挑戰(zhàn)。

和正常的未壓縮整數(shù)存儲不同的是這些都是可變長度--這意味著1個整數(shù)的值50只占用1個字節(jié),而不是通常的4個字節(jié)。

這些不是新功能了,大家可以看一下vardecimal他被存儲為可變長度。然而不同的是兩者存儲在磁盤上的數(shù)據(jù)的方式。

注意雖然我只是實現(xiàn)行壓縮,他跟頁面壓縮中使用的行壓縮是一樣的,并沒有區(qū)別

大家可以看一下《深入解析SQL Server 2008 筆記》里面有行壓縮和頁壓縮的詳細(xì)解釋

TinyintTinyint在壓縮后和壓縮前基本是一樣的(tinyint:從0到255的整數(shù)數(shù)據(jù),存儲大小為 1 字節(jié))只有一個例外情況,當(dāng)數(shù)值是0的時候如果開啟了行壓縮將不占用任何字節(jié),

如果是非壓縮存儲將會存儲0x0,并且占用一個字節(jié)。所有的整形類型(tinyint,smallint,int,bigint)對于0這個數(shù)值都是同等對待,數(shù)值由壓縮行元數(shù)據(jù)進(jìn)行描述并且不存儲任何值

Smallint讓我們開始通過觀察正常的未壓縮的smallint數(shù)值, 對于 -2,-1,1,2這些值的存儲,0不會存儲任何東西。注意,所有這些值會準(zhǔn)確的存放在磁盤上,在這種情況下他們使用小字節(jié)序來存儲

-2    =    0xFEFF-1    =    0xFFFF1    =    0x01002    =    0x0200

Little-Endian

從1,2 這兩個值開始,他們很直接很簡單的轉(zhuǎn)換為decimal和你想要的實際數(shù)值。然而,-1有點不一樣,顯示0xFEFF 將他轉(zhuǎn)換為decimal是65.535 --我們能存儲的最大的無符號整形值是2個字節(jié),

SQLSERVER對于一個smallint 的范圍是–32768 to 32767

計算實際值依賴于所使用的整數(shù)溢出。看看下面的C#代碼片段:

unchecked{    Console.WriteLine(0 + (short)32767);    Console.WriteLine(0 + (short)32768);    Console.WriteLine(0 + (short)32769);    // ...    Console.WriteLine(0 + (short)65534);    Console.WriteLine(0 + (short)65535);}

輸出如下:

32767-32768-32767-2-1

如果我們這樣計算 0+有符號short的最大值,那么最大值就是有符號短整型 32767,很明顯負(fù)數(shù)就是-32767,

然而,如果我們這樣計算 0+32.768=32768,那么就會超出short的范圍,我們將最高位翻轉(zhuǎn)變成負(fù)數(shù) -32768 卻不會溢出。

因為這些數(shù)都是常數(shù),編譯器不允許溢出--除非我們將代碼封裝在uncheck {}section里面

你可能曾經(jīng)聽過虛構(gòu)的符號位。基本上它的最高位被用于指示一個數(shù)是正數(shù)還是負(fù)數(shù)。

從上面的例子應(yīng)該很明顯的顯示符號位不是那么特別--通過查詢這個符號位決定一個給定的數(shù)的符號。看一下當(dāng)溢出的時候符號位會怎樣

32767    =    0b0111111111111111-32768    =    0b1000000000000000-32767    =    0b1000000000000001

對于由于太大而引起溢出的數(shù)字,最高位“sign bit”需要進(jìn)行設(shè)置。這不神奇,它只是用來引起溢出。

那么,我們有一些背景知識知道一個常規(guī)的非壓縮integers 是如何存儲的。現(xiàn)在看一下那些同樣數(shù)值的smallint 是如何存儲在行壓縮表里的

-2    =    0x7E-1    =    0x7F1    =    0x812    =    0x82

讓我們嘗試將這些值轉(zhuǎn)換為decimal,我做如下轉(zhuǎn)換

-2    =    0x7E    =    -128 + 126-1    =    0x7F    =    -128 + 1271    =    0x81    =    -128 + 1292    =    0x82    =    -128 + 130

很明顯,這些值會以另一種方式進(jìn)行存儲。最明顯的不同是我們現(xiàn)在只使用一個字節(jié)--由于變成了可變長度存儲。當(dāng)我們解析這些值的時候,我們需要簡單的看一下這些數(shù)字的字節(jié)存儲。如果只使用一個字節(jié),我們知道這表示0到255(對于tinyint來講) 或者對于smallint 數(shù)值是 -128到127 。當(dāng)smallint 存儲的那個值范圍在-128到127 就會使用一個字節(jié)來存儲

如果我們使用相同的方法,我們明顯會獲得錯誤的結(jié)果 。1 <> 0 + 129 訣竅是在本例中將存儲的值作為無符號整數(shù),然后最小值作為偏移量而不是使用0來作為偏移,我們將使用有符號 的一個字節(jié)最小值-128 作為偏移

-2    =    0x7E    =    -128 + 126-1    =    0x7F    =    -128 + 1271    =    0x81    =    -128 + 1292    =    0x82    =    -128 + 130

這意味著一旦我們超出有符號 的1個字節(jié)的范圍 我們將需要用2個字節(jié)來存儲,對嗎?

一個非常重要的區(qū)別是,非壓縮值會永遠(yuǎn)使用小字節(jié)序來存儲,然而使用了行壓縮的整數(shù)值卻使用大字節(jié)序來存儲!所以,他們不只使用不同的偏移值,而使用不同的字節(jié)序。但是最終的結(jié)果都是相同的,不過計算方式卻有很大的不同

Int 和 bigint一旦我找到字節(jié)序的規(guī)律和行壓縮整型值的數(shù)值架構(gòu),int和bigint的實現(xiàn)就很簡單了。和其他類型一樣,他們也是可變長度的所以你有可能會碰到5字節(jié)長的bigint值和1字節(jié)長的int值。下面是SqlBigInt 類型的主要解析代碼

switch (value.Length){    case 0:        return 0;    case 1:        return (long)(-128 + value[0]);    case 2:        return (long)(-32768 + BitConverter.ToUInt16(new[] { value[1], value[0] }, 0));    case 3:        return (long)(-8388608 + BitConverter.ToUInt32(new byte[] { value[2], value[1], value[0], 0 }, 0));    case 4:        return (long)(-2147483648 + BitConverter.ToUInt32(new[] { value[3], value[2], value[1], value[0] }, 0));    case 5:        return (long)(-549755813888 + BitConverter.ToInt64(new byte[] { value[4], value[3], value[2], value[1], value[0], 0, 0, 0 }, 0));    case 6:        return (long)(-140737488355328 + BitConverter.ToInt64(new byte[] { value[5], value[4], value[3], value[2], value[1], value[0], 0, 0 }, 0));    case 7:        return (long)(-36028797018963968 + BitConverter.ToInt64(new byte[] { value[6], value[5], value[4], value[3], value[2], value[1], value[0], 0 }, 0));    case 8:        return (long)(-9223372036854775808 + BitConverter.ToInt64(new[] { value[7], value[6], value[5], value[4], value[3], value[2], value[1], value[0] }, 0));    default:        throw new ArgumentException("Invalid value length: " + value.Length);}

可變長度的值是一個包含字節(jié)數(shù)據(jù)的字節(jié)數(shù)組存儲在磁盤上。如果長度是0,沒有東西存儲因此我們知道他的值為0。

對于每一個剩余的有效長度,簡單的使用最小的顯示值作為偏移并且添加上存儲的值

對于非壓縮值我們可以使用BitConverter 類直接將輸入值使用系統(tǒng)字節(jié)序轉(zhuǎn)為期望值,對于大多數(shù)的英特爾和AMD系統(tǒng),一般都是小字節(jié)序(意味著OrcaMDF 不會運行在一個大字節(jié)序的系統(tǒng)上)。然而,當(dāng)壓縮值使用大字節(jié)序進(jìn)行壓縮,我必須重新映射輸入的數(shù)組為小端字節(jié)格式,并且在字節(jié)尾補上0 以便匹配short,int和long的大小

對于shorts和ints 我將無符號數(shù)值讀取進(jìn)來,因為這是我所感興趣的。工作原理是將int 和uint強制轉(zhuǎn)換為long值。我不能對long類型做同樣的事情因為沒有其他數(shù)據(jù)類型比long 更大了。對于long的最大值為9.223.372.036.854.775.807,在磁盤里實際存儲為0xFFFFFFFFFFFFFFFF。解析有符號long型使用BitConverter得出的結(jié)果 -1 由于會導(dǎo)致溢出。由于額外的負(fù)數(shù)溢出這有可能會導(dǎo)致出錯

-9.223.372.036.854.775.808 + 0xFFFFFFFFFFFFFF =>-9.223.372.036.854.775.808 + -1 =9.223.372.036.854.775.807

結(jié)論通常我有很多的有趣的嘗試通過執(zhí)行一個select語句去找出數(shù)值在磁盤上以哪一個字節(jié)結(jié)束。這不會花很長的時間去實現(xiàn),技術(shù)內(nèi)幕的書只是作為引導(dǎo),還有很多東西需要我們深入挖掘

第十三篇完


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 河曲县| 江北区| 松潘县| 元朗区| 郎溪县| 渭南市| 泸定县| 景泰县| 缙云县| 子洲县| 马关县| 宜兴市| 京山县| 罗江县| 长宁县| 永和县| 兴隆县| 富平县| 霍山县| 秦皇岛市| 禄劝| 日照市| 民权县| 喀喇| 抚州市| 金川县| 会东县| 江源县| 大余县| 莱阳市| 龙海市| 老河口市| 玉溪市| 高雄县| 静乐县| 青州市| 富宁县| 外汇| 邹城市| 吴江市| 肥东县|