解剖SQLSERVER 第五篇 ?OrcaMDF里讀取Bits類型數(shù)據(jù)(譯)
http://improve.dk/reading-bits-in-orcamdf/
Bits類型的存儲(chǔ)跟SQLSERVER其他定長(zhǎng)數(shù)據(jù)類型的存儲(chǔ)很不一樣。通常,所有定長(zhǎng)列都會(huì)顯示出來(lái),一個(gè)條記錄里定長(zhǎng)數(shù)據(jù)部分的字段數(shù)據(jù)總是一個(gè)挨著一個(gè)
我們可以寫(xiě)入磁盤的最小數(shù)據(jù)單位是一個(gè)字節(jié),存儲(chǔ)位類型數(shù)據(jù)的天真的方法就是使用一整個(gè)(字節(jié)@)來(lái)存儲(chǔ)每一個(gè)位,使用常用的格式去解釋位類型數(shù)據(jù)是很簡(jiǎn)單的
,不過(guò)這會(huì)浪費(fèi)一些空間 ,就像null位圖,如果一個(gè)表只有3列,那么用一個(gè)字節(jié)來(lái)存儲(chǔ)null位圖會(huì)比較浪費(fèi),因?yàn)槠渌?個(gè)位都沒(méi)有用到
@:文章里是用位 ,這里應(yīng)該是用字節(jié)吧
?
在記錄的內(nèi)部位類型是如何存儲(chǔ)的?
一些位類型列的值是存儲(chǔ)在一個(gè)字節(jié)中的,最大可以到8個(gè)位,通常,我們會(huì)有如下表定義
CREATE TABLE BitTest ( A bit B bit C bit D int )
記錄的定長(zhǎng)部分?jǐn)?shù)據(jù)需要占用5個(gè)字節(jié),4個(gè)字節(jié)存儲(chǔ)int 列 ,而另一個(gè)字節(jié)存儲(chǔ)A 、B、C這三列位類型的數(shù)據(jù),只用了字節(jié)里面的3個(gè)位
我們?cè)偬砑右恍┝?
CREATE TABLE BitTest ( A bit B bit C bit D int E bit F bit G bit H smallint I bit J bit K bit )
E到G列按道理來(lái)說(shuō)應(yīng)該存儲(chǔ)在D列的后面,但是他們會(huì)繼續(xù)使用第一個(gè) bit byte,直到第一個(gè) bit byte使用完所有的位空間為止
下面的圖顯示了H列(smallint?)直接存儲(chǔ)在D列的后面,而在D列后面是存儲(chǔ)K列的新bit byte,因?yàn)榈谝粋€(gè)bit byte已經(jīng)滿了
?
當(dāng)讀取行記錄里的位類型時(shí)我們需要知道的狀態(tài)
很明顯,我們一次不能只讀取一個(gè)字段的值,我們讀取固定長(zhǎng)度數(shù)據(jù)類型的時(shí)候還需要讀取定長(zhǎng)數(shù)據(jù)偏移指針
我們需要一些能在讀取的時(shí)候指示我們當(dāng)前讀取到字節(jié)中哪一個(gè)位屬于哪一個(gè)字段的狀態(tài),然后我們讀取一個(gè)新的bit byte
我來(lái)介紹一下RecordReadState類
public class RecordReadState { // We start out having consumed all bits as none have been read private int currentBitIndex = 8 ; private byte bits; public void LoadBitByte( byte bits) { this .bits = bits; currentBitIndex = 0 ; } public bool AllBitsConsumed { get { return currentBitIndex == 8 ; } } public bool GetNextBit() { return (bits & ( 1 << currentBitIndex++)) != 0 ; } }
RecordReadState 類當(dāng)前只需要處理bits,但是將來(lái)我可能還要?jiǎng)?chuàng)建一個(gè)BitReadState 類用來(lái)保存讀取狀態(tài)
RecordReadState 類保存了一個(gè)字節(jié)用來(lái)當(dāng)作指針指出下一個(gè)可用的位在字節(jié)的哪個(gè)地方,如果字節(jié)已經(jīng)用完了存儲(chǔ)滿了所有的位數(shù)據(jù)
(currentBixIndex = 8 (0-7 being the available bits)),方法AllBitsConsumed 就會(huì)返回true,指示我們需要讀取一個(gè)新的?bit byte
GetNextBit方法只是簡(jiǎn)單的從?bit byte中讀取當(dāng)前的bit ,然后將currentBitIndex(bit index)的值加1
demo
using NUnit.Framework; using OrcaMDF.Core.Engine.Records; namespace OrcaMDF.Core.Tests.Engine.Records { [TestFixture] public class RecordReadStateTests { [Test] public void General() { var state = new RecordReadState(); // No bits available Assert.IsTrue(state.AllBitsConsumed); state.LoadBitByte( 0xD2 ); // 11010010 // Bits available Assert.IsFalse(state.AllBitsConsumed); // Reading bit values Assert.IsFalse(state.GetNextBit()); Assert.IsTrue(state.GetNextBit()); Assert.IsFalse(state.GetNextBit()); Assert.IsFalse(state.GetNextBit()); Assert.IsTrue(state.GetNextBit()); Assert.IsFalse(state.GetNextBit()); Assert.IsTrue(state.GetNextBit()); // One bit left Assert.IsFalse(state.AllBitsConsumed); Assert.IsTrue(state.GetNextBit()); // Bits exhausted, ready for next byte Assert.IsTrue(state.AllBitsConsumed); } } }
?
SqlBit實(shí)現(xiàn)
一旦我們實(shí)現(xiàn)了狀態(tài)的讀取,我們就可以實(shí)現(xiàn)SqlBit 類型
public class SqlBit : ISqlType { private readonly RecordReadState readState; public SqlBit(RecordReadState readState) { this .readState = readState; } public bool IsVariableLength { get { return false ; } } public short ? FixedLength { get { if (readState.AllBitsConsumed) return 1 ; return 0 ; } } public object GetValue( byte [] value) { if (readState.AllBitsConsumed && value.Length != 1 ) throw new ArgumentException( " All bits consumed, invalid value length: " + value.Length); if (value.Length == 1 ) readState.LoadBitByte(value[ 0 ]); return readState.GetNextBit(); } }
SqlBit 在構(gòu)造函數(shù)里傳入一個(gè)read state,read state指示當(dāng)前記錄讀取操作的范圍。需要注意的是固定長(zhǎng)度需要依據(jù)read state里的當(dāng)前AllBitsConsumed值
如果字節(jié)里面所有位都被占用,那么意味著需要讀取整個(gè)字節(jié),如果if (readState.AllBitsConsumed)返回0表示不需要讀取整個(gè)字節(jié),但是GetValue方法依然會(huì)被調(diào)用
GetValue方法會(huì)驗(yàn)證一種情況:readState.AllBitsConsumed 返回真,證明 bit byte是有數(shù)據(jù)存儲(chǔ)在里面,但是value.Length返回的長(zhǎng)度是0,那證明有問(wèn)題了
如果我們讀到一個(gè)值,我們會(huì)請(qǐng)求?read state 去裝載一個(gè)新的bit byte ,之后,我們可以調(diào)用GetNextBit 方法返回?read state的當(dāng)前bit
相關(guān)測(cè)試
using NUnit.Framework; using OrcaMDF.Core.Engine.Records; using OrcaMDF.Core.Engine.SqlTypes; namespace OrcaMDF.Core.Tests.Engine.SqlTypes { [TestFixture] public class SqlBitTests { [Test] public void GetValue() { var readState = new RecordReadState(); var type = new SqlBit(readState); // No bytes read - length is one Assert.AreEqual( 1 , type.FixedLength); // Load byte and check length is 0 readState.LoadBitByte( 0xD2 ); Assert.AreEqual( 0 , type.FixedLength); Assert.IsFalse(( bool )type.GetValue( new byte [ 0 ])); Assert.IsTrue(( bool )type.GetValue( new byte [ 0 ])); Assert.IsFalse(( bool )type.GetValue( new byte [ 0 ])); Assert.IsFalse(( bool )type.GetValue( new byte [ 0 ])); Assert.IsTrue(( bool )type.GetValue( new byte [ 0 ])); Assert.IsFalse(( bool )type.GetValue( new byte [ 0 ])); Assert.IsTrue(( bool )type.GetValue( new byte [ 0 ])); // One bit left - length should still be 0 Assert.AreEqual( 0 , type.FixedLength); Assert.IsTrue(( bool )type.GetValue( new byte [ 0 ])); // All bits consumed - length should be 1 Assert.AreEqual( 1 , type.FixedLength); } } }
?
第五篇完
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
