解剖SQLSERVER 第五篇 OrcaMDF里读取Bits类型数据(译)
解剖SQLSERVER 第五篇 OrcaMDF里读取Bits类型数据(译)
http://improve.dk/reading-bits-in-orcamdf/
Bits类型的存储跟SQLSERVER其他定长数据类型的存储很不一样。通常,所有定长列都会显示出来,一个条记录里定长数据部分的字段数据总是一个挨着一个
我们可以写入磁盘的最小数据单位是一个字节,存储位类型数据的天真的方法就是使用一整个(字节@)来存储每一个位,使用常用的格式去解释位类型数据是很简单的
,不过这会浪费一些空间 ,就像null位图,如果一个表只有3列,那么用一个字节来存储null位图会比较浪费,因为其他的5个位都没有用到
@:文章里是用位 ,这里应该是用字节吧
在记录的内部位类型是如何存储的?
一些位类型列的值是存储在一个字节中的,最大可以到8个位,通常,我们会有如下表定义
CREATE TABLE BitTest
(
A bit
B bit
C bit
D int
)
记录的定长部分数据需要占用5个字节,4个字节存储int 列 ,而另一个字节存储A 、B、C这三列位类型的数据,只用了字节里面的3个位

我们再添加一些列
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列按道理来说应该存储在D列的后面,但是他们会继续使用第一个 bit byte,直到第一个 bit byte使用完所有的位空间为止
下面的图显示了H列(smallint )直接存储在D列的后面,而在D列后面是存储K列的新bit byte,因为第一个bit byte已经满了

当读取行记录里的位类型时我们需要知道的状态
很明显,我们一次不能只读取一个字段的值,我们读取固定长度数据类型的时候还需要读取定长数据偏移指针
我们需要一些能在读取的时候指示我们当前读取到字节中哪一个位属于哪一个字段的状态,然后我们读取一个新的bit byte
我来介绍一下RecordReadState类
public class RecordReadState
{
// We start out having consumed all bits as none have been read
private int currentBitIndex = ;
private byte bits; public void LoadBitByte(byte bits)
{
this.bits = bits;
currentBitIndex = ;
} public bool AllBitsConsumed
{
get { return currentBitIndex == ; }
} public bool GetNextBit()
{
return (bits & ( << currentBitIndex++)) != ;
}
}
RecordReadState 类当前只需要处理bits,但是将来我可能还要创建一个BitReadState 类用来保存读取状态
RecordReadState 类保存了一个字节用来当作指针指出下一个可用的位在字节的哪个地方,如果字节已经用完了存储满了所有的位数据
(currentBixIndex = 8 (0-7 being the available bits)),方法AllBitsConsumed 就会返回true,指示我们需要读取一个新的 bit byte
GetNextBit方法只是简单的从 bit byte中读取当前的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实现
一旦我们实现了状态的读取,我们就可以实现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 ; return ;
}
} public object GetValue(byte[] value)
{
if(readState.AllBitsConsumed && value.Length != )
throw new ArgumentException("All bits consumed, invalid value length: " + value.Length); if (value.Length == )
readState.LoadBitByte(value[]); return readState.GetNextBit();
}
}
SqlBit 在构造函数里传入一个read state,read state指示当前记录读取操作的范围。需要注意的是固定长度需要依据read state里的当前AllBitsConsumed值
如果字节里面所有位都被占用,那么意味着需要读取整个字节,如果if (readState.AllBitsConsumed)返回0表示不需要读取整个字节,但是GetValue方法依然会被调用
GetValue方法会验证一种情况:readState.AllBitsConsumed 返回真,证明 bit byte是有数据存储在里面,但是value.Length返回的长度是0,那证明有问题了
如果我们读到一个值,我们会请求 read state 去装载一个新的bit byte ,之后,我们可以调用GetNextBit 方法返回 read state的当前bit
相关测试
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(, type.FixedLength); // Load byte and check length is 0
readState.LoadBitByte(0xD2);
Assert.AreEqual(, type.FixedLength); Assert.IsFalse((bool)type.GetValue(new byte[]));
Assert.IsTrue((bool)type.GetValue(new byte[]));
Assert.IsFalse((bool)type.GetValue(new byte[]));
Assert.IsFalse((bool)type.GetValue(new byte[]));
Assert.IsTrue((bool)type.GetValue(new byte[]));
Assert.IsFalse((bool)type.GetValue(new byte[]));
Assert.IsTrue((bool)type.GetValue(new byte[])); // One bit left - length should still be 0
Assert.AreEqual(, type.FixedLength); Assert.IsTrue((bool)type.GetValue(new byte[])); // All bits consumed - length should be 1
Assert.AreEqual(, type.FixedLength);
}
}
}
第五篇完
解剖SQLSERVER 第五篇 OrcaMDF里读取Bits类型数据(译)的更多相关文章
- 解剖SQLSERVER 第四篇 OrcaMDF里对dates类型数据的解析(译)
解剖SQLSERVER 第四篇 OrcaMDF里对dates类型数据的解析(译) http://improve.dk/parsing-dates-in-orcamdf/ 在SQLSERVER里面有几 ...
- 解剖SQLSERVER 第十篇 OrcaMDF Studio 发布+ 特性重温(译)
解剖SQLSERVER 第十篇 OrcaMDF Studio 发布+ 特性重温(译) http://improve.dk/orcamdf-studio-release-feature-recap/ ...
- 解剖SQLSERVER 第八篇 OrcaMDF 现在支持多数据文件的数据库(译)
解剖SQLSERVER 第八篇 OrcaMDF 现在支持多数据文件的数据库(译) http://improve.dk/orcamdf-now-supports-databases-with-mult ...
- 解剖SQLSERVER 第七篇 OrcaMDF 特性概述(译)
解剖SQLSERVER 第七篇 OrcaMDF 特性概述(译) http://improve.dk/orcamdf-feature-recap/ 时间过得真快,这已经过了大概四个月了自从我最初介绍我 ...
- 解剖SQLSERVER 第六篇 对OrcaMDF的系统测试里避免regressions(译)
解剖SQLSERVER 第六篇 对OrcaMDF的系统测试里避免regressions (译) http://improve.dk/avoiding-regressions-in-orcamdf-b ...
- 解剖SQLSERVER 第十三篇 Integers在行压缩和页压缩里的存储格式揭秘(译)
解剖SQLSERVER 第十三篇 Integers在行压缩和页压缩里的存储格式揭秘(译) http://improve.dk/the-anatomy-of-row-amp-page-compre ...
- 解剖SQLSERVER 第十七篇 使用 OrcaMDF Corruptor 故意损坏数据库(译)
解剖SQLSERVER 第十七篇 使用 OrcaMDF Corruptor 故意损坏数据库(译) http://improve.dk/corrupting-databases-purpose-usin ...
- 解剖SQLSERVER 第十一篇 对SQLSERVER的多个版本进行自动化测试(译)
解剖SQLSERVER 第十一篇 对SQLSERVER的多个版本进行自动化测试(译) http://improve.dk/automated-testing-of-orcamdf-against ...
- 解剖SQLSERVER 第三篇 数据类型的实现(译)
解剖SQLSERVER 第三篇 数据类型的实现(译) http://improve.dk/implementing-data-types-in-orcamdf/ 实现对SQLSERVER数据类型的解 ...
随机推荐
- 网络-->监控-->OID-->BGP
说明:暂时发现只适合cisco设备,h3c的交换机只支持部分OID(支持版本.AS号.ROUTER-ID)
- 2.jenkins配置邮件提醒
1.前言 在Jenkins的使用中邮件提醒是一个常用功能,Jenkins默认安装了Mailer Plugin插件用于实现此功能. 2.邮件服务器配置 首先在Jenkins的"系统管理&quo ...
- WebApi Put方法出现MethodNotAllowed解决方法
WebApi Put方法提交数据的时候总提示MethodNotAllowed,在网上查了很多资料才发现是因为IIS安装了一项服务“WebDAV”,在IIS中把“WebDAV”前面的勾去掉,重新启动电脑 ...
- .NET平台开发Mongo基础知识
NoSQL简介 NoSQL相关的技术最近越来越受欢迎,Mongo本身就是基于NoSQL实现的.关于NoSQL你需要了解 什么是NoSQL NoSQL和传统的关系型数据库有什么区别 NoSQL的优缺点 ...
- GitHub安装配置
GitHub安装配置1.安装Git-1.9.5-preview20141217 2.配置config文件Windows(在命令行下)cd /d %userprofile%if not exist &q ...
- SVN使用总结
## 常用命令 建立分支 --- svn copy/cp svn cp http://example.com/repos/myproject/trunk http://example.com/repo ...
- javascript总结
javascript:它是一种script脚本语言 脚本语言:就是可以和HTML混合在一起使用的语言,可以用来在IE的客 户端进行程序编制,从 ...
- seaJS 简单例子,理解seaJS
学习心得: 记得第一次学underscore的时候,去的官网(不管什么都是官网好),呼啦一长列语法,我就一个个看,看完也不知道underscore是做什么的.就是现在underscore我也用不上,学 ...
- linux 项目环境搭建配置
经过三天加一上午的努力折腾,本地项目终于跑起来了,linux系统,重装后需要安装基本的php,nginx,mysql.php扩展需要安装curl ,memcache,memcached等.然后就是修改 ...
- mybatis多数据源配置
项目目录如下: 按照顺序配置吧 首先是配置config jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/a ...