标签:winform style blog http color io os 使用 ar
这一系列,我们一起来解剖SQLSERVER
在系列的第一篇文章里本人可能会得罪某些人,但是作为一位SQLSERVER MVP,在我的MVP任期内希望可以对大家作出一些贡献
在第一篇里面涉及到某些内容可能不会以详细的方式给出截图并且和大家讲解,毕竟第一篇的篇幅比较长,希望大家见谅。。
在第一篇文章开始之前,先说三个题外话
第一个题外话 更新丢失
首先要做的事情是,跟大家道歉
在之前《SQLSERVER走起》的微信公众帐号里推送了一篇文章,题目是《RDS-SQLSERVER的READ COMMITTED与READ_COMMITTED_SNAPSHOT的区别及各自优缺点》
由于当时没有仔细看,就给大家推送了,文章里面的建议确实是误导了大家
文章里面这样说道
举个例子描述这个场景:
T1事务发起一个修改,读取原库存是10,需求修改库存减1,原库存应该变成9,因为是READ_COMMITTED_SNAPSHOT隔离级别,所以数据库会在tempdb里生成一个快照,但是事务未提交,在这时发起了第二事务T2,也来修改库存,因为看到事务T1未提交,所以他不能获取未提交事务修改的值9(如果获取9就是脏读了),而是他获取的是最后提交版本的库存为10,而正巧T2未提交前,T1先提交了,实际库存应该变9而不是10,但T2事务获取库存值是10,假设T2的需求是减库2,那么最后T2提交后,会覆盖T1事务所做的修改,库存变成了8(我们实际期望的是10-1-2=7),这样就造成了逻辑混乱。
实际上,这种情况不是逻辑混乱,这种情况是属于 “更新丢失”,大家随便拿起一本SQLSERVER教科书,里面都会有说到更新丢失这种现象
文章里面说的解决方案基本上是错误的
错误一:提高事务隔离级别将会造成更加多的死锁
错误二:没有对“更新丢失”进行错误处理
我的好朋友高继伟(博客园里的shanks_gao大牛)跟这个阿里云SQLSERVER经理说过这个问题,但是最后他还是没有改过来
解决方案有两种,都是在默认隔离级别 READ COMMITTED下,不需要修改默认隔离级别
第一种:使用try catch捕获更新丢失
--示例 CREATE TABLE kucun(id INT PRIMARY KEY,qty INT,product NVARCHAR(20))
--插入一些测试数据 SELECT * FROM dbo.kucun ----------------------------------------------- --session 1 BEGIN TRAN DECLARE @qty INT SELECT @qty=qty FROM kucun WITH(UPDLOCK) WHERE [product]=‘牙膏‘ SELECT @qty UPDATE kucun SET qty=@qty-1 WHERE [product]=‘牙膏‘ COMMIT TRAN ------------------------------------------ --session 2 BEGIN TRAN DECLARE @qty INT SELECT @qty=qty FROM kucun WITH(UPDLOCK) WHERE [product]=‘牙膏‘ --阻塞 SELECT @qty --session 1提交之后才可以读,但是后面的update语句不会执行,这个时候更新丢失,使用try catch机制来捕获更新丢失 UPDATE kucun SET qty=@qty-1 WHERE [product]=‘牙膏‘ COMMIT TRAN
第二种: 如果使用的是SQLSERVER2008 可以使用merge语句来执行这个原子操作
--session 1 BEGIN TRAN MERGE [dbo].[kucun] AS TGT USING [dbo].[kucun] AS SRC ON TGT.product = SRC.product AND TGT.id = SRC.id AND TGT.product = ‘牙膏‘ WHEN MATCHED THEN UPDATE SET TGT.qty = TGT.qty - 1; COMMIT TRAN SELECT * FROM [dbo].[kucun] WHERE product = ‘牙膏‘
--session 2 --当session 1没有提交的时候就会阻塞,当session 1提交的时候 session 2 也能成功update记录 ,不会造成更新丢失 BEGIN TRAN MERGE [dbo].[kucun] AS TGT USING [dbo].[kucun] AS SRC ON TGT.product = SRC.product AND TGT.id = SRC.id AND TGT.product = ‘牙膏‘ WHEN MATCHED THEN UPDATE SET TGT.qty = TGT.qty - 1; COMMIT TRAN
希望大家升级一下SQLSERVER,使用SQLSERVER2008提供的最新的merge语句,因为merge语句确实能够减少很多不必要的麻烦,而且性能也会有提升
看到这里,可能大家对这种最基础最基础的知识不以为然,但是大家试想一下,恰好这种最基础的东西就有可能带来致命的后果
例子:
比如你的银行账户里有100万,你取出来了20万,还剩下80万
但是刚好遇到更新丢失,你的账户里面可能已经取出了钱但是系统里面没有扣取你的钱又或者扣除多了 、扣除少了
后果可大可小
还有库存系统,这里就不说了
大家可能觉得“桦仔想借用这个例子,趁机贬低他人来抬高自己” 。实际上,我对于这个经理也是很理解,
当你管理成千成万台服务器的时候,你的脑子里就会想到数据库架构、集群搭建、容灾、业务连续性。。。
这是数据库架构师要做的事,很难会顾及到这些基础的东西,我自己也是管理着公司很多的数据库
但是作为数据库专家,你给客户的建议应该要足够专业吧???
第二个题外话 估计行数
脚本
USE [sss] SELECT @@VERSION --Microsoft SQL Server 2005 - 9.00.4035.00 (X64) --Nov 24 2008 16:17:31 --Copyright (c) 1988-2005 Microsoft Corporation --Developer Edition (64-bit) on Windows NT 6.1 (Build 7601: Service Pack 1) CREATE TABLE teststat(id INT,name NVARCHAR(20)) --首先插入5条记录 INSERT INTO teststat SELECT 1 ,‘nihao‘ UNION ALL SELECT 2 ,‘dajiahao‘ UNION ALL SELECT 3 ,‘nihao‘ UNION ALL SELECT 4 ,‘dajiahao‘ UNION ALL SELECT 5 ,‘nihao‘ --显示实际执行计划 SELECT * FROM teststat --预估行数5条 --查看缓存的执行计划 SELECT [cacheobjtype] , [objtype] , [usecounts] , [sql] FROM sys.[syscacheobjects] WHERE [sql] NOT LIKE ‘%cache%‘ AND [sql] LIKE ‘%INSERT INTO%‘ --再插入100条记录 INSERT INTO teststat(id,name) SELECT 6,‘dajiahao‘ GO 100 --查询缓存的执行计划 SELECT [cacheobjtype] , [objtype] , [usecounts] , [sql] FROM sys.[syscacheobjects] WHERE [sql] NOT LIKE ‘%cache%‘ AND [sql] LIKE ‘%INSERT INTO%‘ --显示实际执行计划 SELECT * FROM teststat --预估行数还是5条 --清空编译计划 DBCC FREEPROCCACHE GO --显示实际执行计划 SELECT * FROM teststat --预估行数变成105条
第一次查看缓存的执行计划
第二次查看缓存的执行计划
清空plan cache之后
注意:DBCC FREEPROCCACHE是清空实例级别的计划缓存,请不要随意在生产环境下执行
第三个题外话 性能太差的SQLSERVER
某一天,开发又抱怨了:“SQLSERVER很慢,查询要差不多9秒,这个问题怎麽彻底解决!”
这个例子不是证明SQLSERVER多牛逼,只是为了说明数据量大的时候,SQLSERVER也可以应付
开发查询的是一张xxclassifyxx表,表数据1.8亿+
查询语句如下
SELECT TOP 500 * FROM DBO.xxCLASSIFYxx with (nolock) WHERE ID>5102332830 ORDER BY ID
表情况:
聚集索引建立在ID列上
上面的查询大概需要8秒
大家看到这个SQL语句可能一开始并没有什么头绪,但大家会发现,聚集索引既然建立在ID这一列上,那么ORDER BY ID是不是有点多余呢???
语句修改之前
执行时间 8秒 (500 行受影响) 表 ‘xxClassifyxx‘。扫描计数 113,逻辑读取 619665 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
语句修改之后,只是去掉了ORDER BY ID
SELECT TOP 500 * FROM DBO.xxCLASSIFYxx with (nolock) WHERE ID>5102332830
(500 行受影响) 表 ‘xxClassifyxx‘。扫描计数 1,逻辑读取 32 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
修改之后所用时间
在这里,加ORDER BY ID和不加ORDER BY ID对于SQLSERVER来看是不同的
正题
在日常生产环境中,遇到数据库损坏是很正常的事情,数据库损坏的原因多种多样,很多时候,由于不能使用数据库内建的命令或工具
来修复数据库,由此催生了数据恢复这个行业
这些数据恢复软件商一般会把自己的数据恢复软件产品和数据库恢复技术吹得要多牛逼就有多牛逼
我们一起来看一下他们的广告吧~
北京某数据恢复商
广州某数据恢复商
深圳某数据恢复商
看到上面DBCC BUG这句话,其实我心里想说一句话“有本事你不用DBCC 命令来修复数据库!”
DBCC CHECKDB确实为了我们做了很多事情,而且这些事情也比较复杂,有兴趣的同学可以看一下《深入解析SQL Server 2008 笔记》第11章
DBCC 是由Paul Randal大神编写的,他是我敬重的人
《【译】SQL Server误区30日谈-Day2-DBCC CHECKDB会导致阻塞》
我承认搞数据库恢复真的很好赚,前段时间博客园里某位园友找我,用的是用友U8的系统,磁盘阵列损坏了,数据库大小900MB
数据很重要,他找到论坛里一位搞用友系统的人,那个人不是数据库恢复公司的,平时帮搞一下用友的系统,他使用替换物理数据文件的方法
结果搞不定,于是那位园友来找我,我跟他说了一些方法,但是不保证一定能修复好,因为我也不是神仙,后来听说那个人将数据库修复好了
而且还收了500大洋,包开发票,具体怎么修复好我就不清楚了。。
其实,数据恢复并不难,只要遵循格式,例如文件系统有文件系统的格式,jpg图片有jpg图片的格式,mdf文件有mdf文件的格式,只要按照格式,读出数据并不难
数据恢复我自己定义大概分两种:1、软件恢复 2、人工恢复
人工恢复这里就不说了,我这里说一下软件恢复,一般为了效率,数据库软件恢复商都会开发数据恢复软件
而据我所知,国内的大部分数据恢复软件商都是小作坊式的,一个软件由1到2个人开发
由于这样,导致了开发不出像《Recovery for SQL Server》这样的靠谱的产品
我说一下这些数据库软件恢复商不靠谱的地方
不靠谱的地方1
如果你对SQLSERVER有深入研究就知道, SQLSERVER从创建数据库到第一次进行数据库完整备份这段期间里是一直处于简单模式的
也就是说,如果你从来没有进行过完整备份,那么日志就会截断,即使你做过数据库完整备份,在数据库创建到第一次完整备份这段期间
的日志是找不到的,你不能通过ldf文件来恢复这段期间的数据,正确的做法还是要保留第一次的完整备份,还有想再说一次,备份真的很重要
DBCC CHECKDB属于强硬修理数据库(简称:硬修),而将数据库拿到数据库恢复商那里去修理就更加暴力了,除非真的万不得已。。。
相关文章《 您真的理解了SQLSERVER的日志链了吗?》
不靠谱的地方2
微软并没有公开页面checksum校验的算法,那意味着,你恢复出来的数据很有可能是不正确的
不靠谱的地方3
对“极速SQL数据库修复软件预览”这款软件进行测试
以查看“极速SQL数据库修复软件预览” 对SQLSERVER数据存储新格式的支持情况
软件下载地址:
测试脚本
USE testnewformat GO CREATE TABLE DBCCResult ( PageFID NVARCHAR(200) , PagePID NVARCHAR(200) , IAMFID NVARCHAR(200) , IAMPID NVARCHAR(200) , ObjectID NVARCHAR(200) , IndexID NVARCHAR(200) , PartitionNumber NVARCHAR(200) , PartitionID NVARCHAR(200) , iam_chain_type NVARCHAR(200) , PageType NVARCHAR(200) , IndexLevel NVARCHAR(200) , NextPageFID NVARCHAR(200) , NextPagePID NVARCHAR(200) , PrevPageFID NVARCHAR(200) , PrevPagePID NVARCHAR(200) ) --测试稀疏列的表-------------------------------------------------------------------- CREATE TABLE test_sparse(id INT ,name CHAR(10) SPARSE,city CHAR(10) SPARSE) GO DECLARE @i INT SET @i =1 WHILE @i <6 BEGIN INSERT test_sparse SELECT @i,‘小四@‘ ,‘广州@‘ SET @i=@i+1 END DECLARE @i INT SET @i =1 WHILE @i <6 BEGIN INSERT test_sparse SELECT @i,NULL ,‘广州@‘ SET @i=@i+1 END DECLARE @i INT SET @i =1 WHILE @i <100 BEGIN INSERT test_sparse SELECT @i,‘小四@‘ ,NULL SET @i=@i+1 END DECLARE @i INT SET @i =1 WHILE @i <6 BEGIN INSERT test_sparse SELECT @i,NULL ,NULL SET @i=@i+1 END SELECT * FROM test_sparse --测试vardecimal的表--------------------------------------------------------------------- CREATE TABLE test_vardecimal(id INT ,qty DECIMAL(10,6)) GO --打开vardecimal storage format选项 EXEC sys.[sp_tableoption] @TableNamePattern = N‘test_vardecimal‘, -- nvarchar(776) @OptionName = ‘vardecimal storage format‘, -- varchar(35) @OptionValue = ‘1‘ -- varchar(12) DECLARE @i INT SET @i =1 WHILE @i <10 BEGIN INSERT test_vardecimal SELECT @i,36.2693222+@i SET @i=@i+1 END --使用DBCC PAGE测试 --decimal数据类型变成变长列 30|00|0800 01000000 |0200|00|01 00|1400|c1 5d2b5378 37.26932220 SELECT * FROM test_vardecimal --测试 页面压缩的表------------------------------------------------------------------------------------ CREATE TABLE test_pagecompress(id INT PRIMARY KEY IDENTITY,name CHAR(2000),city CHAR(2000),qty DECIMAL(10,6)) GO ALTER INDEX [PK__test_pag__3213E83F4B15C9A5] ON [test_pagecompress] REBUILD WITH (DATA_COMPRESSION= PAGE) DECLARE @i INT SET @i =1 WHILE @i <10000 BEGIN INSERT test_pagecompress([name],[city],[qty]) SELECT REPLICATE(‘你好!藏123‘,100),REPLICATE(‘大家好好!藏123‘,100),36.269322+@i SET @i=@i+1 END SELECT * FROM [test_pagecompress] INSERT INTO DBCCResult EXEC (‘DBCC IND(testnewformat,test_pagecompress,-1) ‘) SELECT * FROM DBCCResult DBCC TRACEON(3604,-1) GO DBCC PAGE([testnewformat],1,739,3) GO ------------------------------------------------------------- --新建数据库测试Filestream EXEC sys.[sp_configure] @configname = ‘filestream access level‘, -- varchar(35) @configvalue = 1 -- int RECONFIGURE WITH OVERRIDE CREATE DATABASE MyFilestreamDB ON PRIMARY (NAME=ROWDATA1,FILENAME=‘D:\MSSQL\Data\ROWDATA1.MDF‘), FILEGROUP FILESTREAMGROUP1 CONTAINS FILESTREAM DEFAULT (NAME=FSDATA1,FILENAME=‘D:\MSSQL\Data\FILESTREAM1‘), FILEGROUP FILESTREAMGROUP2 CONTAINS FILESTREAM (NAME=FSDATA2,FILENAME=‘D:\MSSQL\Data\FILESTREAM2‘) LOG ON (NAME=FSDBLOG,FILENAME=‘D:\MSSQL\Data\FSDB_LOG.LDF‘) --新建Filestream表RECORDS USE MyFilestreamDB CREATE TABLE MyFILESTREAMDB.DBO.RECORDS ( ID UNIQUEIDENTIFIER ROWGUIDCOL NOT NULL UNIQUE , SERIALNUMBER INTEGER UNIQUE , CHART_PRIMARY VARBINARY(MAX) FILESTREAM NULL , CHART_SEONDARY VARBINARY(MAX) FILESTREAM NULL ) FILESTREAM_ON FILESTREAMGROUP1 USE MyFilestreamDB INSERT INTO [dbo].[RECORDS] SELECT NEWID() , 24 , CAST(REPLICATE(CONVERT(VARCHAR(MAX), ‘base data‘), 10000) AS VARBINARY(MAX)) , 0x SELECT *,CAST([CHART_PRIMARY] AS VARCHAR(MAX)) AS ‘CHART_PRIMARY‘ FROM [dbo].[RECORDS]
测试结果
稀疏列
vardecimal
页面压缩
Filestream
地理空间类型
USE [AdventureWorks2008R2] GO SELECT TOP 100 * FROM [Person].[Address]
可以看到,除了稀疏列格式之外,软件对其他格式都歇菜了。。。
不靠谱的地方4
数据库恢复软件的性能一般都比较差,对于VLDB(very large database)一般都会崩溃
我用一个200G+的数据库进行测试
软件运行了5个小时之后就中途崩溃了
这些软件使用的扫描数据的方式一般是扫objectid然后根据objectid扫所属objectid的页面,如果系统表损坏效率就更低了
而数据装载的方式一般都是使用使用bulk行集提供程序
不靠谱的地方5
--查看用户库中的内部表 USE [CT_DB] SELECT * FROM sys.[internal_tables]
为什麽我要强调隐藏表,大家可能觉得这些隐藏表里的数据不太重要,例如 service broker队列技术 我们都没有用到
那你错了,你没有用到不代表没有人用,据我说知,新蛋网就是利用service broker队列将一部分数据从美国传送到中国
还有扣减库存也使用到service broker
所以,大家一定要清楚认识一点“无论什么表,表里面的数据需不需要恢复,取决于表里面存储的公司的业务数据是否重要!!”
数据恢复的两大难处
第一难处:
无论什么表都会遇到这两大难处,第一难处,在你发现数据库出现损坏的时候,最好先备份一下数据库,然后再运行相关命令
如果不是VLDB,这一点很容易做到,在备份数据库的时候,你可以选择只备份主文件组又或者完整备份整个数据库
备份主文件组:大家知道SQLSERVER会把各个表的行记录数记录在系统表sysindexes里面
当大家使用《分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间)》这篇文章提供的脚本
来查看表记录数的时候,实际上读取的是sysindexes表里的rowcnt,所以速度会很快
当我们修复完数据库之后,只需要还原主文件组,然后比较一下修复前和修复后的数据量的差异就可以了,但是这种方法不准确
完整备份数据库:先玩着备份数据库,然后运行命令修复数据库
修复完数据库之后,还原完整备份,保证每张表都有一个not null 字段,然后在修复后的数据库上的每张表上
和还原出来的数据库上的每张表使用 SELECT COUNT(NOT NULL 字段) 来检查丢失多少数据
实际上,这种方法也不太靠谱,不但效率低,而且如果有页面损坏,SELECT COUNT也不一定能读取页面
无论哪一种方式,要精确统计丢失的数据量都很难,你只有不停的备份数据,在数据库损坏前有一个完好
的数据库备份,这个数据库备份里面是没有数据损坏的,在第一时间发现数据库损坏之后,马上停库,然后正确还原备份比较出丢失的数据量
这里再穿插一个题外话
在SQLSERVER内部存在大量的计数器,这些计数器有各种各样的用途
例如 数据页面头上的slotcnt,保存页面上的行记录数
这个slotcnt计数器用来在checkdb的时候将扫描到的页面上的记录数和这个slotcnt计数器保存的记录数进行比较
要验证页面上保存的记录数是否是正确的
还有刚才提到sysindexes表里的rowcnt,rowcnt这个计数器用来保存表的总记录数,这样就不需要实际去读取表的页面
来统计表的总记录数,实际上很多时候,SQLSERVER利用计数器都是为了性能方面的考虑,就比如既然有OLTP数据库
为什麽还要存在数据仓库。
第二难处:
验证丢失数据的正确性难,大家知道,SQLSERVER引入了TORN_PAGE和CHECKSUM来验证页面上的数据的正确性
如果页面数据不正确就有可能引发著名的823和824错误
按照公式 逻辑页面号 * 8192 来算出偏移位置
这个计算公式没有错,只是,如果你真的要靠这个公式来找数据页面,很多时候会找不到
例如没有考虑到逻辑碎片的问题,而且我们平时搜索数据的时候一般都不会使用这个公式
还有大家在研究的时候不要将DBCC PAGE的输出中左边的偏移值和winhex中左边的偏移值对应起来
DBCC PAGE
WINHEX
测试脚本
create database testpage go use testpage go create table testpagevs(id int identity primary key,name nchar(10)) go INSERT INTO testpagevs SELECT N‘中国‘ UNION ALL SELECT ‘nihao‘ SELECT * FROM testpagevs CREATE TABLE DBCCResult ( PageFID NVARCHAR(200) , PagePID NVARCHAR(200) , IAMFID NVARCHAR(200) , IAMPID NVARCHAR(200) , ObjectID NVARCHAR(200) , IndexID NVARCHAR(200) , PartitionNumber NVARCHAR(200) , PartitionID NVARCHAR(200) , iam_chain_type NVARCHAR(200) , PageType NVARCHAR(200) , IndexLevel NVARCHAR(200) , NextPageFID NVARCHAR(200) , NextPagePID NVARCHAR(200) , PrevPageFID NVARCHAR(200) , PrevPagePID NVARCHAR(200) ) TRUNCATE TABLE DBCCResult INSERT INTO DBCCResult EXEC (‘DBCC IND(testpage,testpagevs,-1) ‘) SELECT * FROM DBCCResult SELECT * FROM testpagevs DBCC TRACEON(3604,-1) GO DBCC PAGE([testpage],1,89,2) GO
我们看下怎么用VS查看数据文件内容
我们使数据库脱机,然后把mdf文件拖入VS
用winhex修改数据,选中要修改的数据的字节区域,然后右键—》edit-》你可以选择剪切、添加字节、填充零等等
用Visual Studio修改数据更简单,选中要修改的字节区域,然后直接输入16进制数就可以了
在修改数据之前,把页面校验设置为NONE
ALTER DATABASE [sss] SET PAGE_VERIFY NONE
如果你修改数据页头的话,在修改完毕之后数据库还可以联机,但是你修改数据行的话,问题就严重了
消息 824,级别 24,状态 2,第 1 行 SQL Server 检测到基于一致性的逻辑 I/O 错误 校验和不正确(应为: 0xb70c8233,但实际为: 0xb7438233)。在文件 ‘E:\DataBase\sss.mdf‘ 中、偏移量为 0x0000000009a000 的位置对数据库 ID 8 中的页 (1:77) 执行 读取 期间,发生了该错误。SQL Server 错误日志或系统事件日志中的其他消息可能提供了更详细信息。这是一个威胁数据库完整性的严重错误条件,必须立即纠正。请执行完整的数据库一致性检查(DBCC CHECKDB)。此错误可以由许多因素导致;有关详细信息,请参阅 SQL Server 联机丛书。
消息 5028,级别 16,状态 4,第 1 行 系统无法激活足够的数据库来重建日志。 sss的 DBCC 结果。 CHECKDB 在数据库 ‘sss‘ 中发现 0 个分配错误和 0 个一致性错误。 消息 7909,级别 20,状态 1,第 1 行 紧急模式修复失败。您必须从备份中还原。 消息 601,级别 12,状态 3,第 1 行 由于数据移动,无法继续以 NOLOCK 方式扫描。 消息 926,级别 14,状态 1,第 1 行 无法打开数据库 ‘sss‘。恢复操作已将该数据库标记为 SUSPECT。有关详细信息,请参阅 SQL Server 错误日志。 消息 5069,级别 16,状态 1,第 1 行 ALTER DATABASE 语句失败。 消息 5125,级别 24,状态 2,第 1 行 文件 ‘E:\DataBase\sss.mdf‘ 似乎已被操作系统截断。其大小应为 3072 KB,但实际大小为 3064 KB。 消息 3414,级别 21,状态 1,第 1 行 恢复期间出 错,导致数据库 ‘sss‘ (数据库 ID 8)无法重新启动。请诊断并纠正这些恢复错误,或者从已知的正确备份中还原。如果无法更正错误,或者为意外错误,请与技术支持人员联系。
分享某位牛人的代码
无论系统表、DMV、用户表、系统存储过程、系统视图都可以读取出来
附加到SQLSERVER之后,查看数据库属性,作者使用的是微软的标准示例数据库adventureworkoltp来做的测试
这几个库的版本号是611,655,661,706
我们可以自己新建一个数据库,然后测试一下
牛人的博客地址:http://improve.dk/
项目代码已经放上去GITHUB:https://github.com/improvedk/OrcaMDF
分享SQLSERVER技术内幕系列图书笔记
本人把一些SQLSERVER技术内幕读书笔记分享出来,其实也不算是分享,因为这些笔记一直躺在我的博客里
大家可以对我做的笔记进行搜索,技术内幕系列图书最大的一个特征是 :Microsoft Press 权威性不可忽视
笔记地址
《Microsoft SQL Server 6.5 技术内幕 笔记》
《Microsoft SQL Server 2005技术内幕:T-SQL查询笔记》
《Microsoft SQL Server 2005技术内幕:存储引擎笔记》
《Microsoft SQL Server 2005技术内幕 查询、调整和优化笔记》
《Microsoft SQL Server 2005技术内幕: T-SQ程序设计 笔记》
《Microsoft SQL Server 2008技术内幕:T-SQL查询 笔记》
《MICROSOFT SQL SERVER 2008技术内幕:T-SQL语言基础 笔记》
EXEC sys.[sp_helpconstraint] @objname = N‘[dbo].[nums]‘, -- nvarchar(776) @nomsg = ‘‘ -- varchar(5) select object_id, type, name,[parent_object_id] from sys.objects where parent_object_id = OBJECT_ID(‘customer‘) and type in (‘C ‘,‘PK‘,‘UQ‘,‘F ‘, ‘D ‘) -- ONLY 6.5 sysconstraints objects
《SQLSERVER2005存储引擎》
SQLSERVER2005存储引擎里面把cachestore翻译为 存储仓库
还有SQLOS
SQLSERVER的工作线程是映射到Windows的线程池,SQLSERVER每条工作线程内存的分配都是由Windows来分配
SQL2005引入SQLOS,开始由SQLSERVER自己来调度线程,而先前是由Windows来调度
《SQLSERVER2005: T-SQ程序设计》
人们总是说游标性能不好,这本书里面解释了游标实际上也有他的优势的地方
《SQLSERVER2008 TSQL查询》
《深入解析SQLSERVER2008 》
DBCC的工作原理解释得很清楚,大部分内容跟《SQLSERVER2005存储引擎》有重叠
在最后一章DBCC 揭秘,译者把鬼影记录翻译为备份记录,搞到一头雾水
一边看书,一边思考
例如这篇文章《大表分批删除脚本》 作者为什么要写 DELETE TOP (5000) 呢? 有可能是5000行锁升级到表锁的原因
还有这一篇文章《恢复SQLSERVER被误删除的数据》
大家看完书本之后,看一下存储过程的代码,自己是否理解里面代码的意思
结尾
解剖SQLSERVER系列目录
解剖SQLSERVER 第四篇 OrcaMDF里对dates类型数据的解析(译)
解剖SQLSERVER 第五篇 OrcaMDF里读取Bits类型数据(译)
解剖SQLSERVER 第六篇 对OrcaMDF的系统测试里避免regressions (译)
解剖SQLSERVER 第七篇 OrcaMDF 特性概述(译)
解剖SQLSERVER 第八篇 OrcaMDF 现在支持多数据文件的数据库(译)
解剖SQLSERVER 第九篇 OrcaMDF现在能通过系统DMVs显示元数据(译)
解剖SQLSERVER 第十篇 OrcaMDF Studio 发布+ 特性重温(译)
解剖SQLSERVER 第十一篇 对SQLSERVER的多个版本进行自动化测试(译)
解剖SQLSERVER 第十二篇 OrcaMDF 行压缩支持(译)
解剖SQLSERVER 第十三篇 Integers在行压缩和页压缩里的存储格式揭秘(译)
解剖SQLSERVER 第十四篇 Vardecimals 存储格式揭秘(译)
解剖SQLSERVER 第十五篇 SQLSERVER存储过程的源文本存放在哪里?(译)
解剖SQLSERVER 第十六篇 OrcaMDF RawDatabase --MDF文件的瑞士军刀(译)
解剖SQLSERVER 第十七篇 使用 OrcaMDF Corruptor 故意损坏数据库(译)
解剖SQLSERVER 完结篇 关于Internals Viewer源代码
由于本人精力有限而且E文水平不太好,翻译过程可能有错漏,望大家见谅
建议先看一下技术内幕的书,否则一头栽进代码你会理解不了
通过阅读这些译文大家可能会觉得SQLSERVER的新存储格式比较复杂,要赶上SQLSERVER的步伐不太容易,
改天微软推出一个SQLSERVER补丁包,并在补丁包里面添加新的存储格式你的软件可能又要歇菜了~
而我写这系列文章并不是要与这些数据库恢复软件商作对,而是让大家知道他们能够恢复哪些数据,有哪些数据超出了他们的数据恢复能力
Mark S. Rasmussen大牛的PPT:
标签:winform style blog http color io os 使用 ar
原文地址:http://www.cnblogs.com/lyhabc/p/3900229.html