亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

解剖SQLSERVER 第十四篇 Vardecimals 存儲格式揭秘(譯)

2024-07-21 02:48:56
字體:
來源:轉載
供稿:網友
解剖SQLSERVER 第十四篇 Vardecimals 存儲格式揭秘(譯)解剖SQLSERVER 第十四篇 Vardecimals存儲格式揭秘(譯)

http://imPRove.dk/how-are-vardecimals-stored/

在這篇文章,我將深入研究vardecimals 是怎麼存儲在磁盤上的。

作為一般的介紹vardecimals 是怎樣的,什么時候應該使用,怎樣使用,參考這篇文章

vardecimal 存儲格式啟用了嗎?

首先,我們需要看一下vardecimals 是否已經開啟了,因為他會完全改變decimals 的存儲方式。Vardecimal 不是獨立的一種數據類型,所有使用decimals 的列都會使用vardecimals方式來存儲并使用相同的system type(106)。注意在SQLSERVER里面,numeric 跟decimal是完全一樣的。無論我在哪里我提到decimal, 你都可以使用numeric來替代并且會得到相同的結果

你可以執行下面語句來查看給定的表的vardecimal 是否開啟

SELECT OBJECTPROPERTY(OBJECT_ID('MyTable'), 'TableHasVarDecimalStorageFormat')

如果你沒有權限運行上面語句,或者不想使用OBJECTPROPERTY函數,你可以查詢sys.system_internals_partition_columns DMV 獲取同樣的信息。

USE testGOSELECT    COUNT(*)FROM    sys.system_internals_partition_columns PCINNER JOIN    sys.partitions P ON P.partition_id = pc.partition_idINNER JOIN    sys.tables T ON T.object_id = P.object_idWHERE    T.name = 'test_vardecimal' AND    P.index_id <= 1 AND    PC.system_type_id = 106 AND    PC.leaf_offset < 0

固定長度變為可變長度正常的decimal列在記錄里面使用固定長度來存儲。這意味著存儲的是真正的數據。他不需要保存存儲的字節數的長度信息這個長度信息用來計算并存儲在元數據里。

一旦你打開vardecimals, 所有的decimals 不再使用固定長度來存儲,進而用可變長度代替。

將decimal 作為可變長度字段來存儲有一些特別含義1、我們再也不能使用靜態的方法來計算一個給定的值的所需字節數2、會有兩個字節的開銷用來存儲偏移值在可變長度偏移數組里3、如果先前行記錄沒有可變長度列,那么開銷實際上是4個字節因為我們也需要存儲可變長度列的列數量4、decimal 的實際值變成了可變數量的字節 這需要我們去解讀

vardecimal 值由哪些部分組成一旦我們開始解析行記錄然后在可變長度部分檢索vardecimal 的值,我們需要解析里面的數據。

正常的decimals 基本能存儲一個巨大無比的整數(范圍是根據元數據定義的decimal的位置)vardecimals 的存儲使用科學計數法。使用科學計數法,我們需要存儲三個不同的值1、符號(正數/負數)2、指數3、(對數的) 尾數

使用這三個組成部分,我們可以使用下面的公式計算出實際值

(sign) * mantissa * 10<sup>exponent</sup>

例子

假設我們有一個vardecimal(5,2)列,我們存儲的值是123.45。在科學記數法里,將表示為1.2345 * 102。在這種情況下我們有正數符號(1),一個尾數1.2345和一個指數2。SQL Server知道尾數總是有一個固定小數點在第一個數字后面,正因為如此,這會簡單的存儲整數值12345作為尾數,

當指數是2,SQLSERVER知道我們的范圍由指數2來定義,數值向右移動指數的長度,存儲0作為實際的指數

一旦我們讀取這個數,我使用下面的公式計算尾數(注意我們在這里不關心如果尾數是正的還是負的--我們會稍后將他保存到account里)

mantissa / 10<sup>floor(log10(mantissa))</sup>

將我們的值帶入進去,我們得到

12345 / 10<sup>floor(log10(12345))</sup>

通過簡化我們得到

12345 / 10<sup>4</sup>

使用科學計數法得到最終的尾數

1.2345

到目前為止一切順利,我們現在得到尾數的值。在這里我們需要做兩件事1、加上符號位2、根據指數值將decimal的小數點移動到右邊正確的位置。當SQLSERVER知道范圍是2,他將2替代4,并減去指數指定的范圍--允許我們忽略范圍并且只需要直接計算數字

因此我們獲得了我們最終需要計算的最后數字

(sign) * mantissa * 10<sup>exponent</sup> => (1) * 1.2345 * 10<sup>2</sup> => 1.2345 * 10<sup>2</sup> = 123.45

讀取符號位和指數第一個字節包含符號和指數。在先前的例子里面,這些值占用4個字節(包含額外的2個字節的偏移數組)

0xC21EDC20

如果我們觀察第一個字節,并且將他轉換為binary,我們獲得下面信息

最重要的那個位是最左邊的那個位,或者從右開始數第7位(位置編號從0開始)那個位是符號位。如果設置為1表示正數,如果為0表示負數,我們看到是1表示正數

位0 - 6是一個7位的包含指數的值。一個常規的無符號7位值可以包含的范圍是0~127。當decimal 數據類型需要表示一個范圍 –1038+1到 1038-1,我們就需要存儲負數。

我們可以使用7位的其中一位作為符號位,在其余的6位里存儲值,允許的范圍是–64 到 63。然而SQLSERVER會用盡7位去存儲本身的數值,

不過存儲的是一個偏移值64。因此,指數0會被存儲為64 (64-64=0)。指數-1 會存儲63 (63-64=-1),指數1會存儲65 (65-64=1)如此類推。

在我們的例子里,讀取位0-6 將會得到下面的值

66減去64這個偏移值就得出 指數266-64=2(指數)

尾數的chunk存儲余下的字節包含尾數值。我們把他轉換為二進制

Hex: 1E       DC       20Bin: 00011110 11011100 00100000

尾數存儲在10位的chunks里,每一個chunk顯式尾數的3個數字(記住,尾數是一個很大的整數,直到后來我們開始把他作為一個十進制的指針數值 10的n次冪)

把這些字節切割放進去chunks里面 會得到如下的組別

在這種情況下,一個字節8位 SQLSERVER在這里會浪費4位使用這種chunk大小的話。問題來了,為什么要選擇一個chunk大小為10位?那10位 需要顯示所有可能的三位整數(0-999)。

如果我們使用一個chunk的大小來表示一個數字會怎樣?

在這種情況下,一個字節8位 SQLSERVER在這里會浪費4位使用這種chunk大小的話。問題來了,為什么要選擇一個chunk大小為10位?那10位 需要顯示所有可能的三位整數(0-999)。如果我們使用一個chunk的大小來表示一個數字會怎樣?

剛才那樣的情況,我們需要展示數值0-9.那總共需要4個位(0b1001 = 9)。然而,使用4個位的時候我們實際可以展示的最大范圍是0-15(0b1111 = 15) --意味著我們浪費了6個值的空間(15-9=6)這些值永遠不需要的。從百分比來講,我們浪費了6/16=37.5%

讓我們試著畫出不同的chunk大小對應浪費的百分比的圖:

我們看到chunk大小選擇4和選擇7 相比起選擇chunk大小為10 有較大的浪費。在chunk大小為20時,對于0浪費相當接近,但是他還是有2倍浪費率相比起10來說

現在,浪費不是最重要的。對于壓縮來說,最理想的情況是對于絕對必要的數字我們不想使用多余的數字。在chunk大小為10的情況下,可以顯示3個數字,我們浪費了2個數字空間范圍是0-9。

然而,我們只關注范圍100-999。如果我們的chunk大小選擇20個位,每個chunk顯示6個數字,我們浪費了了一些字節 值從0-99999,當我們只關注值1000000-999999。

基本上,這是一個折衷方案,浪費就越少 而且也越好。我們繼續看圖表,粒度越來越少。很明顯 選擇10個位作為chunk的大小是最好的選擇 --這個選擇的浪費是最小的 并且有合適的粒度大小 3個數字

在我們繼續之前還有一些細節。想象一下我們需要存儲的尾數值為4.12,有效的整數值是412

Dec: 412Bin: 01100111 00Hex: 67       0

在這種情況下,我們會浪費8位在第二個字節,因為我們只需要一個塊,但我們需要兩個字節來表示這10位。在這種情況下,鑒于過去兩位不設置,SQL Server會截斷最后一個字節。因此,如果你正在讀一塊,你的磁盤上,你可以假設其余部分不設置。

在這種情況下,我在第二個字節浪費8個位,因為我們只需要一個chunk,不過我們需要兩個字節來顯示這個位。在這種情況下,多余的兩個位不會進行設置,SQLSERVER會簡單的截斷最后一個字節。因此,如果你讀取一個chunk并且位數已經超出了磁盤的范圍,你可以假設剩余的位并沒有設置

解析一個vardecimal值最后,我們準備去解析一個vardecimal 值(使用C#實現)!我們將使用先前的例子,存儲123.45值使用decimal(5,2)列。在磁盤上,我們讀取下面的字節數組根據調用的順序

Hex: C2       1E       DC       20Bin: 11000010 00011110 11011100 00100000

讀取符號位讀取符號位相對來說比較簡單。我們將只需要在第一個字節上讀取:

通過位運算符我們將右移7位,剩下的位是最重要的位。這意味著我們將得到值1 表示正數的符號位,如果是0表示負數

decimal sign = (value[0] >> 7) == 1 ? 1 : -1;

讀取指數下面(技術上來講這7個位是緊跟著符號位的)的7位包含了指數值

將十六進制值0b1000010 轉換為進制值得到的結果是66.我們知道指數總是有偏移值64,我們需要將存儲的值減去64從而得到實際值:

Exponent = 0b1000010 – 0n64 <=> Exponent = 66 – 64 = 2

讀取尾數接下來就是尾數值。前面提到,我們需要讀取一個10個位的chunk,并且需要注意那些被截斷的部分

首先,我們需要知道有多少有用的位。這樣做很簡單,我們只需簡單的將尾數的字節數(除了第一個字節之外的所有字節)乘以8

int totalBits = (value.Length - 1) * 8;

一旦我們知道有多少位是可用的(在這個例子里 2個chunk 24位=3個字節* 8位),我們可以計算chunks的數目

int mantissaChunks = (int)Math.Ceiling(totalBits / 10d);

因為每個塊占用10位,我們只需要的比特總數除以10。如果有填充最后,匹配一個字節邊界,它將是0的,不會改變最終的結果。因此為2字節尾數我們將有8位備用,將非標準都是0。

對于一個3字節尾數我們將有4位,再次添加0尾數總額。

因為每個chunk占用10個位,我們只需要除以將位的總數除以10。如果在結尾有占位,為了匹配位的邊界,SQLSERVER會填充0但是這個不會影響上面公式得出的結果。

因此,對于一個2個字節的尾數我們會有8bit(這里作者是不是錯了?應該是6bit吧) 是剩余的,這些剩余位都會被無意義的0填充。對于一個3字節 的尾數我們會有4bit 剩余,

再一次在總的尾數值上填充0

這里我們準備讀取chunk的值。在讀取之前,我們需要分配兩個變量

decimal mantissa = 0;int bitPointer = 8;

可變長的尾數值是由尾數值進行累加的,每次我們讀取一個新10-bit chunk值就累加一次。bitPointer 是一個指針指向當前讀取到的位。我們不準備讀取第一個字節,我們會從第8位開始讀?。◤?開始數,因此第8位 =第二個字節的第一位)

看一下這些位 他們可以簡單的看成是一條long stream --我們只需要從左到右進行讀取,對吧?不完全是,你可否記得,最右邊的位是最重要的,因此最右邊的位應該是我們最先要讀取的。然而,我們需要一次讀取一個字節。同樣,整體的方向是按chunk為單位的話是從左到右讀取。

一旦我們達到chunk的位置,我們每次就需要一個字節一個字節地讀取。bits1-8 在第一個字節里讀取,bits9-10 在第二個字節里讀取,

下面圖片中橙色的箭頭(最大的那個箭頭指示字節讀取順序(chunkwise)從左向右,而每個獨立的字節內部的讀取順序是小箭頭那個 從右向左)

為了方便訪問所有的bits,和避免做太多的人工的位移操作,我實例化一個BitArray 類 ,這個類包含了所有的數據位:

var mantissaBits = new BitArray(value);

使用這個類,你必須知道bit 數組如何跟字節進行映射。形象的描述,他會像下面那樣,mantissaBits 數組指針在圖片的上面:

我知道這看起來很復雜,不過所有這些復雜的事情只不過是需要知道指針的指向。我們的代碼里面是字節數組。我們訪問每一個獨立的bits的方式是通過mantissaBits 數組,這個數組只是一個很大的指向獨立的bits的數組指針。

看一下第一個8 bits,manitssaBits 數組按照我們的讀取方向很好地排列。第一個條目(mantissaBits[0])指向第一個字節的最右一位。第二個條目指向第二個字節,以此類推。因此,第一個8 bits是直接讀取的。然而,后面的兩個,在manitssaBits 數組里面他們需要我們跳過6個條目以至于我們讀取條目14

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久999精品| 亚洲自拍偷拍视频| 国产99久久精品一区二区 夜夜躁日日躁| 日韩视频欧美视频| 日韩中文字幕国产精品| 91精品久久久久久| 国产激情999| 5252色成人免费视频| 亚洲第一av网站| 在线看欧美日韩| 欧美午夜视频一区二区| 亚洲第一免费播放区| 国产区精品在线观看| 欧美日韩性视频在线| 青青草精品毛片| 日韩av手机在线观看| 日韩av成人在线| 日本乱人伦a精品| 国产精品亚洲欧美导航| 欧美激情第一页xxx| 成人网在线免费看| 91日韩在线播放| 91夜夜揉人人捏人人添红杏| 欧美性猛交丰臀xxxxx网站| 久久99久国产精品黄毛片入口| 亚洲一区二区久久久| 日韩av电影免费观看高清| 日韩美女写真福利在线观看| 久久亚洲精品国产亚洲老地址| 国产aⅴ夜夜欢一区二区三区| 日韩欧美国产激情| 理论片在线不卡免费观看| 亚洲一区二区三区成人在线视频精品| 成人免费视频97| 91精品久久久久久久久青青| 欧美成人全部免费| 国产成人avxxxxx在线看| 97视频在线观看网址| 欧美日韩国产精品一区二区三区四区| 国产日韩精品在线观看| 欧美成人免费全部观看天天性色| 日韩av在线导航| 亚洲一区中文字幕在线观看| 在线视频中文亚洲| 国产精品精品久久久| 欧美成人精品在线视频| 一区二区在线视频| 国产偷国产偷亚洲清高网站| 国产精品视频网站| 国产欧美在线播放| 国产在线久久久| 日韩成人av网址| 91精品国产综合久久香蕉最新版| 日韩美女福利视频| 国产精品白丝av嫩草影院| 日韩精品在线观看一区二区| 欧美性在线视频| 欧洲中文字幕国产精品| 亚洲自拍av在线| 性欧美在线看片a免费观看| 一区二区亚洲欧洲国产日韩| 久久99亚洲精品| 日韩av一区二区在线观看| 国产视频在线观看一区二区| 亚洲成人在线视频播放| 国产亚洲人成网站在线观看| 性欧美视频videos6一9| 亚洲第一精品自拍| 久久久久一本一区二区青青蜜月| 亚洲欧美成人网| 奇门遁甲1982国语版免费观看高清| 欧美在线xxx| 成人中文字幕+乱码+中文字幕| 不卡在线观看电视剧完整版| 国模私拍一区二区三区| 久久精品视频亚洲| 欧美亚洲在线播放| 成人午夜一级二级三级| 色www亚洲国产张柏芝| 亚洲奶大毛多的老太婆| 中文字幕亚洲一区二区三区| 欧美久久精品午夜青青大伊人| 国内免费久久久久久久久久久| 国产成人精品日本亚洲专区61| 色播久久人人爽人人爽人人片视av| 91美女片黄在线观| 精品国产美女在线| 亚洲大胆美女视频| 日韩美女av在线免费观看| 欧美激情日韩图片| 国产精品96久久久久久又黄又硬| 日本电影亚洲天堂| 久久人体大胆视频| 欧美激情第三页| 美女久久久久久久久久久| 国产成人久久久| 日本高清视频一区| 55夜色66夜色国产精品视频| 黄色一区二区在线| 黑人巨大精品欧美一区二区一视频| 成人一区二区电影| 欧美精品久久久久久久久久| 亚洲欧美一区二区精品久久久| 亚洲精品在线不卡| 国产亚洲精品激情久久| 美乳少妇欧美精品| 国产欧美一区二区三区久久人妖| 国产精品美乳在线观看| 日韩av理论片| 亚洲精品乱码久久久久久金桔影视| 久久人人97超碰精品888| 亚洲精品乱码久久久久久按摩观| 欧美成人午夜剧场免费观看| 超碰97人人做人人爱少妇| 国产精国产精品| 久久人人爽亚洲精品天堂| 国产精品极品在线| 中文字幕欧美专区| 欧美成人高清视频| 国产精品久久999| www.亚洲天堂| 精品国产欧美一区二区三区成人| 国产亚洲一区精品| 91在线观看免费高清| 成人精品aaaa网站| 国产精品第七十二页| 国产91成人在在线播放| 亲爱的老师9免费观看全集电视剧| 成人高h视频在线| 国产精品男女猛烈高潮激情| 久久久久成人网| 欧美影院成年免费版| 欧美资源在线观看| 麻豆乱码国产一区二区三区| 久久国产加勒比精品无码| 一区国产精品视频| 久久久久亚洲精品国产| 欧美成aaa人片免费看| 91香蕉嫩草神马影院在线观看| 欧美另类高清videos| 欧美激情精品久久久久久变态| 久久久99久久精品女同性| 在线观看日韩视频| 欧美日韩亚洲精品内裤| 亚洲人午夜精品| 欧洲成人在线观看| 日韩av片电影专区| 亚洲成avwww人| 亚洲精品成人久久电影| 97精品国产97久久久久久春色| 国产69精品久久久久9999| 97免费视频在线| 国产精品久久久av| 日韩av在线免费| 日韩在线免费观看视频| 日本一区二区三区四区视频| 久久天堂av综合合色| 亚洲成人网在线| 久久精品久久久久久国产 免费| 欧美精品激情视频| 欧美性生活大片免费观看网址| 久久91亚洲精品中文字幕| 国产精品久久久亚洲| 国产成+人+综合+亚洲欧洲|