解剖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ì)您有幫助就好】元

