SQLSERVER备份事务日志的作用
事务日志备份有以下3种类型
(1)纯日志备份:仅包含相隔一段时间的事务日志记录,而不包含任何大容量更改
(2)大容量操作日志备份.包括由大容量操作更改的日志和数据页,不支持时间点恢复
(3)尾日志备份:从可能已破坏的数据库创建,用于捕获尚未备份的日志记录。在失败后创建尾日志备份可以防止工作损失,
并且,尾日志备份可以包含纯日志或大容量日志数据
必须至少有一个完整备份或一个等效文件备份集,才能进行任何日志备份。通常DBA定期(如每周)创建数据库完整备份,
以更短的间隔(如每天)创建差异备份,并会频繁(如每10分钟)创建事务日志备份。
最恰当的备份间隔取决于一系列因素,如数据的重要性、数据库的大小和服务器的工作负荷
如果事务日志损坏,则将丢失自最新的日志备份后所执行的工作。
为此,建议经常对关键数据进行日志备份,并注意将日志文件存储在容错存储设备中
事务日志备份顺序独立于完整备份。可以生成一个事务日志备份顺序,然后定期生成用于开始还原操作的完整备份
------------------------------------------------华丽的分割线-----------------------------------------------------
最佳实践
每10分钟:事务日志备份
每天:差异备份
每周:完整备份
备份日志尾部失败后执行尾日志备份,以防止丢失所做工作,在失败之后并且在开始还原数据库之前,或者在故障转移到辅助数据库时,
备份活动日志(尾日志备份)。选择此选项等效于在TSQL 中backup log 语句中指定norecovery选项
1 BACKUP LOG [GPOSDB] To disk='D:\GPOSDB_logbackup_201207160152.bak' 2 GO
事务日志备份有时会比数据库备份大。例如,数据库的事务处理很多,从而导致事务日志迅速增大。
在这种情况下,应该经常地创建日志备份并清理事务日志
----------------------------------------------华丽的分割线----------------------------------------------------------------
清理事务日志
如果从来没有从事务日志中删除日志记录,逻辑日志就会一直增长,直到填满容纳物理日志文件的磁盘上的所有可用空间。
为了减少逻辑日志的大小,应定期截断事务日志。在SQLSERVER的最早版本中,截断事务日志意味着将进行数据库恢复或还原不再需要的日志记录物理删除。
但是,在最近的版本中,截断过程只是做标记,以便重新使用旧日志记录使用过的空间。此空间中的日志记录将最终被新的日志记录覆盖。
在事务日志已满的情况下,满的情况根据你的磁盘的容量大小,用户不能更新数据。backup log语句有双重的目的,
不仅可以备份事务日志,并且在事务日志满的时候,用户还可以利用他清理事务日志,移去事务日志中不活动的部分
截断并不减少物理日志文件大小,而是减少逻辑日志文件的大小并释放磁盘空间以供重新使用。
减少物理日志文件大小需要收缩事务日志文件
DBCC SHRINKFILE适用于当前数据库中的文件。要收缩的数据库不必在单用户模式下,收缩文件时,其他用户也可使用该数据库
1 --例如:截断AdventureWorks数据库的事务日志,然后将日志文件收缩到10MB 2 USE [AdventureWorks] 3 GO 4 BACKUP LOG [AdventureWorks] WITH no_log 5 GO 6 EXEC [sys].[sp_helpdb] @dbname = 'AdventureWorks' -- sysname 7 GO 8 9 DBCC SHRINKFILE(AdventureWorks_Log,10) 10 GO
注意:清理事务日志的时候,不产生日志备份副本.考虑到数据库的恢复工作可能需要使用日志备份,应该先做日志备份,再清理事务日志!!
最后附上配图

SQLSERVER备份系统数据库以及何时备份系统数据库
系统数据库存储了服务器配置信息,用户登录信息,用户数据库信息和作业信息
在更改服务器配置和修改系统数据库前后,应当及时备份他们
要备份的系统数据库有:master,msdb,model,distribution分发
备份这些数据库后就可以在发生系统故障,例如硬盘故障时还原和恢复整个SQLSERVER
---------------------------------------华丽的分割线-------------------------------------------------------------
何时备份系统数据库
1、修改master数据库之后
master数据库记录了SQLSERVER系统的所以系统级信息。必须经常备份master,以便根据业务需要充分保护数据。
建议使用定期备份计划,这样,在大量更新后可以补充更多的备份当用户创建用户数据库,
创建和修改用户登录帐号或在执行任何语句更改master数据库中的信息的时候,都应当备份master数据库
2、修改msdb数据库之后
msdb是SQLSERVER代理用来安排警报和作业的,以及记录操作员信息的数据库。
在修改警报、作业和操作员信息之后应该备份他。如果用户没有及时备份msdb数据库,
系统出现故障后,用户就必须重建各个警报、作业和操作员
3、修改model数据库之后
model数据库是系统中所有数据库的模版。如果用户修改model数据库来调整所有新用户数据库的默认配置,
就必须备份model数据库以满足业务需要
4、配置复制服务之后
只有将服务器配置为复制分发服务器时才存在distribution数据库。
此数据库存储元数据、各种复制的历史记录数据,以及用于事务复制的事务。用户配置了复制服务之后,
应该及时备份distribution数据库以保护复制的相关信息
就这麽多了,可能大家平时都只备份自己的业务库,而忽略了系统库,所以以后要多多注意啦 o(∩_∩)o
SQL PROMPT5.3.4.1的一些设置选项
我使用的是5.3.4.1版本

sql prompt这个工具安装好之后就可以在SSMS里使用代码提示功能
园子里非常多的文章:例如SQLSERVER开发利器XXXXXX
http://www.cnblogs.com/VAllen/archive/2012/09/08/SQLPrompt.html
http://www.cnblogs.com/keepfool/archive/2012/05/27/2519839.html
不过大家都是只提供个软件下载、怎麽破解sql prompt还有简单的使用方法,但是具体怎样使用和设置真的没有
昨天本人无聊研究了一下SQL PROMPT的设置,发现也有一些学问
大家想想,当我们在网上或者同事丢给我们一个sql代码,我们会把代码粘贴到SSMS里面看呢,但是每个人写的代码风格不一样
从网上粘贴进来的代码会有行号这些,特别代码非常长的时候,格式化都不知道怎么格式化了,这个时候就需要sql prompt的代码格式化功能了
使用sql prompt的代码格式化功能很简单,选中你要格式化的代码或者你直接在查询窗口按右键-》formate sql,
那么你选中的那部分代码或者整个sql脚本都会自动formate,这样就方便自己观看了。
但是sql prompt默认的代码格式化格式可能不适合大部分人,其实sql prompt提供了代码格式化的选项设置让大家去设置,只需要几分钟
个人感觉这些设置才是精粹,代码提示功能只是一小部分而已,还有sql prompt实验室提供的创新功能
redgate公司真的厉害,一个简单sql prompt集成了这麽多功能,可能大家以为我帮redgate公司卖广告,不过我相信大部分人都是使用破解的吧 o(∩_∩)o
-----------------------------------------------------华丽的分割线-------------------------------------------------------
说一下菜单中的选项,基本上菜单选项我很少用到,因为里面全部功能对我本人没有用,或者对你们有用 呵呵
除了一个非常重要的选项:启用/禁用代码提示功能,SQL prompt共有两处地方可以设置启用/禁用代码提示功能的开关
一个是这里,另一个是“option”-》Main-》behavior第一个选项就见到啦


---------------------------------------------------华丽的分割线-------------------------------------------------------------
下面对option菜单里面的选项逐个简单介绍

-----------------------------------------------华丽的分割线--------------------------------------------------------------
首先是Main->behavior 软件行为


输入对象之后马上显示对象的定义




其实大家可以按照我的设置去设置,一般我用到的基本上都是大家用到的
------------------------------------------------华丽的分割线------------------------------------------------------------------
Suggestions->types of suggestion 输入和代码提示建议

解密已经加密了的对象还真的有用,比如我加密了一个存储过程,那么我想看这个存储过程是怎麽写的,使用下面sql语句是看不出的
1 USE [pratice] 2 GO 3 EXEC [sys].[sp_helptext] @objname = N'dbo.creat_test_Encryption'
1 对象 'dbo.creat_test_Encryption' 的文本已加密。
但是使用sql prompt就可以看到存储过程的内容


Suggestions->join conditions 连接条件

这个表连接的代码提示设置,可以根据你输入的是数据类型还是列名来进行提示,非常方便
例如我输入的是数据类型,他就会弹出在这个表里符号你输入的数据类型的字段
比如我输入datetime类型

输入列名
1 USE [GPOSDB] 2 GO 3 SELECT * FROM [dbo].[CT_FuelingData] AS a INNER JOIN [dbo].[CT_InhouseCard] AS b ON a.[VC_FD_Cardno]=b.[VC_IC_CardNO]


-----------------------------------------------------华丽的分割线---------------------------------------------------------
Inserted Code->Objects&statements 对象和语句

Inserted Code->Qualification 限定名

像我在图片中说到那样,不知道为什么你输入表名. ,代码提示还是会显示出具有相同列名的表出来

不过这个地方还是有好处的,不如你查一个视图,但是不知道某个视图里的某列的意思
我举个简单的例子吧
比如我想知道 [sys].[sysprotects]这个系统视图中的uid列对应是哪个用户或角色,但是我不知道哪个表或者视图包含有uid这个列的
那么我可以输入下面语句就会显示包括uid列的表或者视图,虽然会显示多个表都包含这个列,但是你想一下
[sys].[sysprotects]这个视图会跟用户、权限的表有关,那么很自然就会想到sysuser这个系统视图

输入下面的语句关联看一下就知道uid对应[sysuser]视图里的哪个用户了
1 SELECT a.*, b.[name] 2 FROM [sys].[sysprotects] AS a 3 LEFT JOIN [sys].[sysusers] AS b ON a.[uid] = b.[uid] 4 ORDER BY a.[id]

Inserted Code->Aliases 别名

Inserted Code->Special characters 特殊符号

-----------------------------------------------------华丽的分割线------------------------------------------------------------------------
到代码格式化了!!
注意,在Formate这个选项下面的所有设置,都要在查询编辑器里选中需要格式化的代码 然后右键-》formate sql 才看到效果的,
不是你输入代码之后sqlprompt马上会自动帮你formate,是手动的喔。

Formate->Styles 风格

这里Styles应该是给你看的,反正我是编辑不了,可以导出XML格式的style文件,但是我也不知道怎么编辑,抱歉抱歉
大家E文比较好的话可以看redgate的官方网站解释,但是我看了里面好像没有说到怎麽编辑,太杯具了~
网站链接:https://documentation.red-gate.com/display/SP53/Options+for+formatting+your+code
导出的style文件
1 <?xml version="1.0" encoding="utf-16" standalone="yes"?> 2 <!----> 3 <LayoutOptions version="1" type="LayoutOptions"> 4 <ReservedWordsCasing>1</ReservedWordsCasing> 5 <BuiltInFunctionCasing>1</BuiltInFunctionCasing> 6 <BuiltInDataTypeCasing>1</BuiltInDataTypeCasing> 7 <DelimitIdentifiers>False</DelimitIdentifiers> 8 <IndentationAmount>4</IndentationAmount> 9 <UseTabs>False</UseTabs> 10 <ReformatExpressions>True</ReformatExpressions> 11 <FirstColumnOnNewLine>False</FirstColumnOnNewLine> 12 <CommasAtStart>False</CommasAtStart> 13 <MultilineSpacesAfterCommas>False</MultilineSpacesAfterCommas> 14 <MultilineSpacesBeforeCommas>True</MultilineSpacesBeforeCommas> 15 <MultilineAlignCommasWithStatement>True</MultilineAlignCommasWithStatement> 16 <OperatorsOnNewline>True</OperatorsOnNewline> 17 <OperatorsAtStart>True</OperatorsAtStart> 18 <IndentBeginToken>True</IndentBeginToken> 19 <IndentWithExpressionBrackets>True</IndentWithExpressionBrackets> 20 <IndentWithParameterBrackets>True</IndentWithParameterBrackets> 21 <IndentWithQueryBrackets>True</IndentWithQueryBrackets> 22 <CloseBracketsOnNewLine>True</CloseBracketsOnNewLine> 23 <OpenBracketsOnNewLine>False</OpenBracketsOnNewLine> 24 <Wrap>True</Wrap> 25 <WrapWidth>78</WrapWidth> 26 <ShortLength>15</ShortLength> 27 <CreateBracketsAtStartOfLines>False</CreateBracketsAtStartOfLines> 28 <ParameterBracketOnNewline>True</ParameterBracketOnNewline> 29 <CloseParameterBracketsOnNewLine>True</CloseParameterBracketsOnNewLine> 30 <CompactShortStatements>False</CompactShortStatements> 31 <SinglelineSpacesAfterCommas>True</SinglelineSpacesAfterCommas> 32 <SinglelineSpacesBeforeCommas>False</SinglelineSpacesBeforeCommas> 33 <SpacesAroundOperators>True</SpacesAroundOperators> 34 <SpacesAroundComparisons>True</SpacesAroundComparisons> 35 <FirstParameterDefinitionOnNewLine>True</FirstParameterDefinitionOnNewLine> 36 <SpacesAfterBrackets>True</SpacesAfterBrackets> 37 <LayoutSelectStatements>True</LayoutSelectStatements> 38 <LayoutCreateStatements>True</LayoutCreateStatements> 39 <QueryNewlineAfterOpenBracket>False</QueryNewlineAfterOpenBracket> 40 <QueryNewlineBeforeCloseBracket>True</QueryNewlineBeforeCloseBracket> 41 <JoinConditionsOnNewline>False</JoinConditionsOnNewline> 42 <AlignConditionsWithJoins>False</AlignConditionsWithJoins> 43 <AlignJoinsWithFrom>False</AlignJoinsWithFrom> 44 <IndentByKeywordWidth>False</IndentByKeywordWidth> 45 <ColumnsOnSingleLine>False</ColumnsOnSingleLine> 46 <DoNotIndentProcedureContents>False</DoNotIndentProcedureContents> 47 <ExecuteParametersOnSingleLine>True</ExecuteParametersOnSingleLine> 48 <UseSpacesInsteadOfTabs>False</UseSpacesInsteadOfTabs> 49 <IndentSelectSubclauses>False</IndentSelectSubclauses> 50 </LayoutOptions>
Formate->Case 大小写

Formate->Schema statements 结构语句

Formate->Data statements 数据语句

Formate->Expressions 表达式

Formate->Commas&parentheses 逗号和双引号

Formate->Tabs&wrapping 自动换行和tabs键缩进量

经过以上设置,我用formate sql功能格式化了一下今天同事给我的一个sql脚本,还算比较舒服的格式化了之后
1 /* 2 @StartDate 3 @EndDate 4 */ 5 ALTER PROCEDURE [dbo].[CT_FuelingData_ICCardGatherReport] 6 ( 7 @StartDate VARCHAR(50) , 8 @EndDate VARCHAR(50) 9 ) 10 AS 11 BEGIN 12 DECLARE @i INT 13 DECLARE @totalcount INT 14 DECLARE @tmpOilTypeName VARCHAR(50) 15 DECLARE @tmpInAmount DECIMAL 16 DECLARE @tmpOutAmount DECIMAL 17 TRUNCATE TABLE Rep_ICFueling 18 CREATE TABLE #TmpOilTypeName 19 ( 20 IndexId INT IDENTITY(1, 1) 21 NOT NULL , 22 VC_OT_OilTypeName VARCHAR(50) 23 ) 24 INSERT INTO #TmpOilTypeName ( VC_OT_OilTypeName ) 25 SELECT VC_OT_OilTypeName 26 FROM DP_OilType 27 ORDER BY VC_OT_OilTypeName ASC 28 SET @totalcount = @@rowcount 29 SET @i = 1 30 WHILE ( @i <= @totalcount ) 31 BEGIN 32 SET @tmpInAmount = NULL 33 SET @tmpOutAmount = NULL 34 SELECT @tmpOilTypeName = VC_OT_OilTypeName 35 FROM #TmpOilTypeName 36 WHERE IndexId = @i 37 SELECT @tmpInAmount = SUM(ISNULL(a.DE_FD_Amount, 0)) 38 FROM CT_FuelingData a , 39 CT_OuterCard b 40 WHERE ( a.I_FD_TypeCode <> 1 ) AND ( a.I_FD_TypeCode <> 5 ) AND ( b.VC_OC_Company = '' ) AND ( D_FD_DateTime BETWEEN @StartDate AND @EndDate ) AND a.VC_FD_Cardno = b.VC_OC_Cardno AND a.VC_FD_OilType = @tmpOilTypeName 41 GROUP BY a.VC_FD_OilType 42 SELECT @tmpOutAmount = SUM(ISNULL(a.DE_FD_Amount, 0)) 43 FROM CT_FuelingData a , 44 CT_OuterCard b 45 WHERE ( a.I_FD_TypeCode <> 1 ) AND ( a.I_FD_TypeCode <> 5 ) AND ( b.VC_OC_Company <> '' ) AND ( D_FD_DateTime BETWEEN @StartDate AND @EndDate ) AND a.VC_FD_Cardno = b.VC_OC_Cardno AND a.VC_FD_OilType = @tmpOilTypeName 46 GROUP BY a.VC_FD_OilType 47 INSERT INTO Rep_ICFueling ( OilTypeStr, InAmount, OutAmount ) 48 VALUES ( @tmpOilTypeName, ISNULL(@tmpInAmount, 0), 49 ISNULL(@tmpOutAmount, 0) ) 50 SET @i = @i + 1 51 END 52 53 SELECT * 54 FROM Rep_ICFueling 55 --select * from #TmpOilTypeName 56 DROP TABLE #TmpOilTypeName 57 END
----------------------------------------------------华丽的分割线--------------------------------------------------------------
至此,sql prompt的格式设置完了,大家可以格式化一下你们的代码试一下符合自己的要求不
最后说一下实验室里的一个自动刷新功能,这个自动刷新功能对于多人修改同一个数据库脚本,例如同一个存储过程,函数
是很有用的。应该大家都有用版本管理软件吧,例如:Visual SourceSafe 就可以管理sqlserver数据库里的一个库里的所有sql脚本
不多说了,看一下这个刷新功能,先启用这个功能啦第一步

然后在SSMS里新建两个查询窗口,第一个查询窗口在tempdb数据库里新建一个表,然后在第二个查询窗口就可以马上看到新建的表



写完了,要睡了,祝大家好梦!!
SQLSERVER改变已有数据表中的列
包括改变字段的位置,增加列,更改列名称,更改列数据类型,列长度,增加标识列,增加主键,约束
上面这些在做数据库升级或者迁移的时候很多时候都要用到的
1.改变字段位置,只需要在表设计器中拖动字段到其他地方



2.添加新列
例如为adventurworks数据库中employees表添加备注列(Comment),数据类型为字符型(变长型,长度50字符),该列允许为空
1 ALTER TABLE table_name 2 ADD column_name data_type NULL
1 USE [AdventureWorks] 2 GO 3 ALTER TABLE [HumanResources].[Employee] 4 ADD Comment CHAR(50) NULL 5 GO
3.更改列名称
更改列名称不会影响列中的数据,但如果其他数据库对象引用了已修改的列,则用户必须同时做相应的修改
1 --将表test13中的列名由e重命名为x 2 --语法:exec sp_rename '表名.原列名','新列名','column'; 3 USE [pratice] 4 GO 5 exec sp_rename 'dbo.test13.e','x','column';
4.更改列的数据类型以及长度
当表中有数据的时候,要注意转换的时候的长度和精度,以及转换的规则
1 --语法 2 ALTER TABLE table_name 3 ALTER COLUMN column_name data_type
1 --例如:将Employees表中的备注列Remark的数据类型更改为字符型(变长型,长度为255字符) 2 USE [AdventureWorks] 3 GO 4 ALTER TABLE [HumanResources].[Employee] 5 ALTER COLUMN Remark VARCHAR(255)
5.增加标识列
一个表只能有一个列定义为IDENTITY属性,而且该列必须以tinyint,smallint,int,bigint,numeric,decimal数据类型定义,标识符列
不允许空值。按需指定种子和增量值,二者默认值均为1。
1 --给Employees表添加一个员工编号(EmployeesCode)列,并将其设置为标识列 2 USE [AdventureWorks] 3 GO 4 ALTER TABLE [HumanResources].[Employee] 5 ADD EmployeesCode INT IDENTITY(1,1) NOT NULL
6.定义主键
每张表都应该有一个主键,主键可以由一列或者多列组成(复合主键),标识数据的唯一性,提高查询和排序速度
如果是复合主键,那么这些列的里的数据都不能重复,不单只是某一列
1 --使用TSQL语句为表定义主键约束保证数据完整性 2 --为Employees表添加主键约束,将EmployeeID,LoginID,ManagerID列设置为复合主键 3 USE [AdventureWorks] 4 GO 5 ALTER TABLE [HumanResources].[Employee] 6 ADD CONSTRAINT PK_EMPLOYEES 7 PRIMARY KEY CLUSTERED([EmployeeID],[LoginID],[ManagerID])
上个星期在客户那里因为要修改主键,忘记了TSQL怎麽写,要看着SSMS来设置,感觉慢了,所以写TSQL是最快的个人感觉
当然有添加也会有删除啦 把ADD 改为DROP
1 USE [AdventureWorks] 2 GO 3 ALTER TABLE [HumanResources].[Employee] 4 DROP CONSTRAINT PK_EMPLOYEES
7.删除列
当表中的某些列确定不再需要时,可以删除该列。在删除前,必须首先删除基于该列的索引和约束
1 --语法 2 ALTER TABLE table_name 3 DROP COLUMN [COLUMN_NAME]
1 --删除Employees表的Lastname列 2 USE [AdventureWorks] 3 GO 4 ALTER TABLE [HumanResources].[Employee] 5 DROP COLUMN [LastName]
这篇文章非常基础,我也只是做一些笔记 o(∩_∩)o
对于索引假脱机的一点理解
在SQLSERVER执行计划里不知道大家有没有看过“索引假脱机”这个运算符
在QQ群里综合了各位大侠的解释:假脱机 有索引假脱机 和 表假脱机两种
先来运行一下下面的SQL代码:
1 USE [tempdb] 2 GO 3 create table #tb(aa int,bb char(1)) 4 GO 5 insert #tb values(1,'A') 6 insert #tb values(1,'B') 7 insert #tb values(1,'C') 8 insert #tb values(1,'D') 9 10 insert #tb values(2,'E') 11 insert #tb values(2,'F') 12 insert #tb values(2,'G') 13 insert #tb values(2,'H') 14 15 insert #tb values(3,'I') 16 insert #tb values(3,'J') 17 insert #tb values(3,'K') 18 insert #tb values(3,'L')
1 --SQL1 2 SELECT * FROM #tb a 3 WHERE bb IN 4 ( 5 SELECT TOP 1 bb FROM #tb 6 WHERE aa=a.aa 7 ORDER BY NEWID() 8 ) 9 10 --SQL2 11 SELECT * FROM #tb a 12 WHERE bb = 13 ( 14 SELECT TOP 1 bb FROM #tb 15 WHERE aa=a.aa 16 ORDER BY NEWID() 17 ) 18 19 --drop table tb
你会发现SQL1的执行计划和SQL2的执行计划很不一样
SQL1的执行计划

SQL2的执行计划

对于执行计划的解释,MSDN论坛里面的邹建大侠说:
1 据楼主的语句, 第一个使用的是IN, 所以IN 里面的, 被查询优化器判定为 subquery (子查询) 2 3 而第二个使用的是 =, 所以查询优化器判定 = 后面的是一个表达式 4 5 因此在判定查询方法的时候, 产生了差异, 对于查询, 查询优化器认为具有不确定性, 所以每条记录都要去执行一次子查询; 而对于表达式, 查询优化器认为它具有确定性, 所以对于每个 aa, 计算一次就行了 6 7 如果把楼主的第一个查询中的 IN, 也改成表达式, 则可以看到会使用与查询2一样的执行计划, 结果也也查询2一样, 有固定的记录数
但是还是有些云里雾里,然后听了QQ群里面的某位大侠的解释
1 XXXX(17478043) 9:28:19 2 索引假脱机是 系统在查询的时候表和数据放入tempdb里然后临时创建一个索引 3 ,表假脱机是为了避免 重复更新某些列,从而提高性能, 4 估计是把整张表放入tempdb,因为那张表更新频繁, 5 所以SQL决定把整个表放入tempdb做下一步的排序或者其他操作, 6 不受其他的更新插入操作影响,这是我的个人理解
而出现索引假脱机的时候,那么表明需要做一些优化,例如加索引
1 XXXXXX(17478043) 9:29:18 2 出现索引假脱机说明你缺少某些很重要的索引 3 创建它就可以了 4 XXXXXXX 9:30:08 5 我看你昨天那个有个 排序 运算符,一般这样的运算需要使用排序或者索引
回到上面的例子,为什麽SQL1没有索引假脱机呢?
因为SQL1里使用in具有不确定性,而SQL2使用=具有确定性,然后SQL认为每次运行都需要排序干脆加一个索引算了
所以SQL2才有了“索引假脱机”这个运算符
在MSDN上找到了tempdb的其中一个用途:
1 tempdb 系统数据库是一个全局资源,可供连接到 SQL Server 实例的所有用户使用,并可用于保存下列各项: 2 3 4 •SQL Server 2005 数据库引擎创建的内部对象,例如,用于存储假脱机或排序的中间结果的工作表。
刚好QQ群里的某君也遇到“索引假脱机”

大家看了这个执行计划之后都解释了出现索引假脱机的原因:
聊天记录:
1 数据库认为帮你建一个索引再查找还快过直接扫描 2 XXXXX<huangzj1985@qq.com> 16:06:03 3 XXXXXXX,那如何优化? 4 XXXXXXXXX17478043) 16:06:37 5 建一个索引呗。。 6 XXXXXXXXX(17478043) 16:07:07 7 建了消除这个索引假脱机运算符了 8 9 XXXXXXXXXXXX(17478043) 16:07:51 10 一般情况下 需要用到聚合的列都应该有对应的索引 11 12 XXXXXXXXX(17478043) 16:08:15 13 因为聚合的第一步就是排序
14 缺少索引就会容易出现哈希运算
后来大家都给出了解决方案建议之后确实消除了这个“索引假脱机”了
1 seek 谓词 就是 索引列,这里应该是组合索引, 2 输出放到 include列 3 当然,组合顺序得考虑数据的分布情况,还有查询的语句,为了DML的性能考虑 ,可以把一些 选择性差的列放到 include 列 4 包含性索引列 5 6 7 XXXXXX 刚才那个 我加了索引和include 包含性索引列 8 确实不会有 索引假脱机了 9 10 XXXXXXXX<huangzj1985@qq.com> 9:50:39 11 速度方面呢? 12 XXXXXXXXXX(771021218) 9:50:44 13 索引假脱机 变成了 索引查找 消耗55%

现在加了索引性能好多了
所以以后大家看到“索引假脱机”不要以为SQLSERVER的索引没有起作用了,脱机了~
总结
其实关于脱机还有很多情况的,包括:lazy spool、Eagar spool、table spool、non clustered index spool...
在磁盘或tempdb缓存用来处理一致性和避免hit
最后有两个问题想请教一下各位大侠,因为MSDN里面对索引假脱机的文章真的稀少,希望知道大侠可以告知一声 ,谢谢啦o(∩_∩)o
(1)断言这个运算符有什么用呢?
(2)索引假脱机分为Lazy spool 和Eager spool,那么这两种类型有什么区别呢?
要睡了,非常困得很~~
