SQL Server 2008 参数化查询

我将讨论如果一个查询可以被参数化,那么SQL Server优化器怎样尝试将其参数化,以及你可以怎样建立你自己的参数化查询.

1.什么是参数化查询?

一个简单理解参数化查询的方式是把它看做只是一个T-SQL查询,它接受控制这个查询返回什么的参数.通过使用不同的参数,一个参数化查询返回不同的结果.要获得一个参数化查询,你需要以一种特定的方式来编写你的代码,或它需要满足一组特定的标准.

有两种不同的方式来创建参数化查询.第一个方式是让查询优化器自动地参数化你的查询.另一个方式是通过以一个特定方式来编写你的T-SQL代码,并将它传递给sp_executesql系统存储过程,从而编程一个参数化查询.这篇文章的后面部分将介绍这个方法.

参数化查询的关键是查询优化器将创建一个可以重用的缓存计划.通过自动地或编程使用参数化查询,SQL Server可以优化类似T-SQL语句的处理.这个优化消除了对使用高贵资源为这些类似T-SQL语句的每一次执行创建一个缓存计划的需求.而且通过创建一个可重用计划,SQL Server还减少了存放过程缓存中类似的执行计划所需的内存使用.

2.现在让我们看看使得SQL Server创建参数化查询的不同方式.

参数化查询是怎样自动创建的?

微软编写查询优化器代码的人竭尽全力地优化SQL Server处理你的T-SQL命令的方式.我想这是查询优化器名称的由来.这些尽量减少资源和最大限度地提高查询优化器执行性能的方法之一是查看一个T-SQL语句并确定它们是否可以被参数化.要了解这是如何工作的,让我们看看下面的T-SQL语句:

SELECT * FROM AdventureWorks.Sales.SalesOrderHeader

WHERE SalesOrderID = 56000;

GO

在这里,你可以看到这个命令有两个特点.第一它简单,第二它在WHERE谓词中包含一个用于SalesOrderID值的指定值.查询优化器可以识别这个查询比较简单以及SalesOrderID有一个参数(“56000”).因此,查询优化器可以自动地参数化这个查询.

如果你使用下面的SELECT语句来查看一个只包含用于上面语句的缓存计划的,干净的缓冲池,那么你会看到查询优化器将T-SQL查询重写为一个参数化T-SQL语句:

SELECT stats.execution_count AS cnt, p.size_in_bytes AS [size], [sql].[text] AS [plan_text]

FROM sys.dm_exec_cached_plans p

OUTER APPLY sys.dm_exec_sql_text (p.plan_handle) sql

JOIN sys.dm_exec_query_stats stats ON stats.plan_handle = p.plan_handle

GO

当我在一个SQL Server 2008实例上运行这个命令时,我得到下面的输出,(注意,输出被重新格式化了,以便它更易读):

如果你看看上面输出中的plan_text字段,你会看到它不像原来的T-SQL文本.如前所述,查询优化器将这个查询重新编写为一个参数化T-SQL语句.在这里,你可以看到它现在有一个数据类型为(int)的变量(@1),它在之前的SELECT语句中被定义的.另外在plan_text的末尾,“56000”被替换为变量@1.既然这个T-SQL语句被重写了,而且被存储为一个缓存计划,那么如果未来一个T-SQL命令和它大致相同,只有SalesOrderID字段被赋的值不同的话,它就可以被用于重用.让我们在动作中看看它.

如果我在我的机器上运行下面的命令:

DBCC FREEPROCCACHE

GO

SELECT * FROM AdventureWorks.Sales.SalesOrderHeader

WHERE SalesOrderID = 56000;

GO

SELECT * FROM AdventureWorks.Sales.SalesOrderHeader

WHERE SalesOrderID = 56001;

GO

SELECT stats.execution_count AS cnt, p.size_in_bytes AS [size], [sql].[text] AS [plan_text]

FROM sys.dm_exec_cached_plans p

OUTER APPLY sys.dm_exec_sql_text (p.plan_handle) sql

JOIN sys.dm_exec_query_stats stats ON stats.plan_handle = p.plan_handle

GO

我从最后的SELECT语句得到下面的输出,(注意,输出被重新格式化以便它更易读):

在这里,我首先释放过程缓存,然后我执行两个不同、但却类似的非参数化查询来看看查询优化器是会创建两个不同的缓存计划还是创建用于这两个查询的一个缓存计划.在这里,你可以看到查询优化器事实上很聪明,它参数化第一个查询并缓存了计划.然后当第二个类似、但有一个不同的SalesOrderID值的查询发送到SQL Server,优化器可以识别已经缓存了一个计划,然后重用它来处理第二个查询.你可以这么说是因为“cnt”字段现在表明这个计划被用了两次.

3.数据库配置选项PARAMETERIZATION可以影响T-SQL语句怎样被自动地参数化.对于这个选项有两种不同的设置,SIMPLEFORCED.PARAMETERIZATION设置被设置为SIMPLE,只有简单的T-SQL语句才会被参数化.要介绍这个,看下下面的命令:

SELECT SUM(LineTotal) AS LineTotal

FROM AdventureWorks.Sales.SalesOrderHeader H

JOIN AdventureWorks.Sales.SalesOrderDetail D ON D.SalesOrderID = H.SalesOrderID

WHERE H.SalesOrderID = 56000

这个查询类似于我前面的示例,除了在这里我添加了一个额外的JOIN标准.当数据库AdventureWorksPARAMETERIZATION选项被设置为SIMPLE,这个查询不会被自动地参数化.SIMPLE PARAMETERIZATION设置告诉查询优化器只参数化简单的查询.但是当选项PARAMETERIZATION被设置为FORCED,这个查询将被自动地参数化.

当你设置数据库选项为使用FORCE PARAMETERIZATION,查询优化器试图参数化所有的查询,而不仅仅是简单的查询.你可能会认为这很好.但是在某些情况下,当数据库设置PARAMETERIZATIONFORCED,查询优化器将选择不是很理想的查询计划.当数据库设置PARAMETERFORCED,它改变查询中的字面常量.这可能导致当查询中涉及计算字段时索引和索引视图不被选中参与到执行计划中,从而导致一个无效的计划.FORCED PARAMETERIZATION选项可能是改进具有大量类似的、传递过来的参数稍有不同的查询的数据库性能的一个很好的解决方案.一个在线销售应用程序,它的客户对你的产品执行大量的类似搜索产品值不同,这可能是一个能够受益于FORCED PARAMETERIZATION的很好的应用程序类型.

不是所有的查询从句都会被参数化.例如查询的TOPTABLESAMPLE HAVINGGROUP BYORDER BYOUTPUT…INTOFOR XML从句不会被参数化.

4.使用sp_execute_sql来参数化你的T-SQL

你不需要依赖于数据库的PARAMETERIZATION选项来使得查询优化器参数化一个查询.你可以参数化你自己的查询.你通过重新编写你的T-SQL语句并使用”sp_executesql”系统存储过程执行重写的语句来实现.正如已经看到的,上面包括一个“JOIN”从句的SELECT语句在数据库的PARAMETERIZATION设置为SIMPLE时没有被自动参数化.让我重新编写这个查询以便查询优化器将创建一个可重用的参数化查询执行计划.

为了说明,让我们看两个类似的、不会被自动参数化的T-SQL语句,并创建两个不同的缓存执行计划.然后我将重新编写这两个查询使得它们都使用相同的缓存参数化执行计划.

让我们看看这个代码:

DBCC FREEPROCCACHE

GO

SELECT SUM(LineTotal) AS LineTotal

FROM AdventureWorks.Sales.SalesOrderHeader H

JOIN AdventureWorks.Sales.SalesOrderDetail D ON D.SalesOrderID = H.SalesOrderID

WHERE H.SalesOrderID = 56000

GO

SELECT SUM(LineTotal) AS LineTotal

FROM AdventureWorks.Sales.SalesOrderHeader H

JOIN AdventureWorks.Sales.SalesOrderDetail D ON D.SalesOrderID = H.SalesOrderID

WHERE H.SalesOrderID = 56001

GO

SELECT stats.execution_count AS cnt, p.size_in_bytes AS [size], [sql].[text] AS [plan_text]

FROM sys.dm_exec_cached_plans p

OUTER APPLY sys.dm_exec_sql_text (p.plan_handle) sql

JOIN sys.dm_exec_query_stats stats ON stats.plan_handle = p.plan_handle

GO

在这里,我释放了过程缓存,然后运行这两个包含一个JOIN的、不同的非简单的T-SQL语句.然后我将检查缓存计划.这是这个使用DMV SELECT语句的输出(注意,输出被重新格式化了,以便它更易读):

正如你从这个输出看到的,这两个SELECT语句没有被查询优化器参数化.优化器创建了两个不同的缓存执行计划,每一个都只被执行了一次.我们可以通过使用sp_executesql系统存储过程来帮助优化器为这两个不同的SELECT语句创建一个参数化执行计划.

下面是上面的代码被重新编写来使用sp_executesql 系统存储过程:

DBCC FREEPROCCACHE

GO

EXEC sp_executesql N’SELECT SUM(LineTotal) AS LineTotal

FROM AdventureWorks.Sales.SalesOrderHeader H

JOIN AdventureWorks.Sales.SalesOrderDetail D ON D.SalesOrderID = H.SalesOrderID

WHERE H.SalesOrderID = @SalesOrderID’, N’@SalesOrderID INT’, @SalesOrderID = 56000

GO

EXEC sp_executesql N’SELECT SUM(LineTotal) AS LineTotal

FROM AdventureWorks.Sales.SalesOrderHeader H

JOIN AdventureWorks.Sales.SalesOrderDetail D ON D.SalesOrderID = H.SalesOrderID

WHERE H.SalesOrderID = @SalesOrderID’, N’@SalesOrderID INT’, @SalesOrderID = 56001

GO

SELECT stats.execution_count AS cnt, p.size_in_bytes AS [size], [sql].[text] AS [plan_text]

FROM sys.dm_exec_cached_plans p

OUTER APPLY sys.dm_exec_sql_text (p.plan_handle) sql

JOIN sys.dm_exec_query_stats stats ON stats.plan_handle = p.plan_handle

GO

如同你所看到的,我重新编写了这两个SELECT语句,使它们通过使用”EXEC sp_executesql”语句来执行.对这些EXEC语句中的每一个,我都传递三个不同的参数.第一个参数是基本的SELECT语句,但是我将SalesOrderID的值用一个变量(@SalesOrderID)替代.在第二个参数中,我确定了@SalesOrderID的数据类型,在这个例子中它是一个integer.然后在最后一个参数中,我传递了SalesOrderID的值.这个参数将控制我的SELECT根据SalesOrderID值所生成的结果.sp_executesql的每次执行中前两个参数都是一样的.但是第三个参数不同,因为每个都有不同的SalesOrderID.

现在当我运行上面的代码时,我从DMV SELECT语句得到下面的输出(注意,输出被重新格式化了,以便它更易读):

从这个输出,你可以看出,我有一个参数化缓存计划,它被执行了两次,为每个EXEC语句各执行了一次.

使用参数化查询来节省资源和优化性能

在语句可以被执行之前,每个T-SQL语句都需要被评估,而且需要建立一个执行计划.创建执行计划会占用宝贵的CPU资源.当执行计划被创建后,它使用内存空间将它存储在过程缓存中.降低CPU和内存使用的一个方法是利用参数化查询.尽管数据库可以被设置为对所有查询FORCE参数化,但是这不总是最好的选择.通过了解你的哪些T-SQL语句可以被参数化然后使用sp_executesql存储过程,你可以帮助SQL Server节省资源并优化你的查询的性能.

DBCC 语句总结

Transact-SQL 编程语言提供 DBCC 语句作为 SQL Server 的数据库控制台命令

数据库控制台命令语句可分为以下类别

命令类别

执行

维护

对数据库、索引或文件组进行维护的任务

杂项

杂项任务,如启用跟踪标志或从内存中删除 DLL

信息

收集并显示各种类型信息的任务

验证

对数据库、表、索引、目录、文件组或数据库页的分配进行的验证操作

 

— I.信息语句

— 1.DBCC INPUTBUFFER 根据session_id显示从客户端发送到 Microsoft SQL Server 实例的一个语句

SELECT @@SPID        — 获得当前会话ID

SELECT * FROM sys.dm_exec_requests WHERE session_id = @@spid        — 跟据当前会话ID获得此次请求信息

DBCC INPUTBUFFER(@@SPID) WITH NO_INFOMSGS        — 显示从客户端发送到 Microsoft SQL Server 实例的一个语句

 

— 2.DBCC SHOWCONTIG 显示指定的表或视图的数据和索引的碎片信息,建议使用 sys.dm_db_index_physical_stats

USE AdventureWorks

GO

DBCC SHOWCONTIG (‘Person.Address’) WITH NO_INFOMSGS        — 显示Person.Address表的数据和索引的碎片信息

GO

— 返回所有数据库中所有对象的信息

SELECT * FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, NULL);

— 返回AdventureWorks数据库中Person.Address表的信息

SELECT * FROM sys.dm_db_index_physical_stats

(DB_ID(N’AdventureWorks’), OBJECT_ID(N’Person.Address’), NULL, NULL , ‘DETAILED’);

GO

 

— 3.DBCC OPENTRAN 确定打开的事务是否存在于事务日志中

DBCC OPENTRAN (0)        — 当前数据库

DBCC OPENTRAN (N’AdventureWorks’) — AdventureWorks数据库

— 创建数据库和表并打开一个事务

USE master

GO

CREATE DATABASE Test

GO

USE Test

GO

CREATE TABLE T1

(col1 INT,

 col2 VARCHAR(10))

GO

BEGIN TRAN

INSERT INTO T1 VALUES (1, ‘Kobe’);

GO

DBCC OPENTRAN;        — 查看此数据库中打开的事务

ROLLBACK TRAN;

GO

DROP TABLE T1;

GO

USE master

GO

DROP DATABASE Test

GO

 

— 4.DBCC SQLPERF 提供所有数据库的事务日志空间使用情况统计信息,也可以用于重置等待和闩锁的统计信息.

DBCC SQLPERF(LOGSPACE) WITH NO_INFOMSGS;        — 显示所有数据库的日志空间信息

GO

DBCC SQLPERF(“sys.dm_os_latch_stats”,CLEAR) WITH NO_INFOMSGS;        — SQL Server 实例重置闩锁统计信息

GO

DBCC SQLPERF(“sys.dm_os_wait_stats”,CLEAR) WITH NO_INFOMSGS;        — SQL Server 实例重置等待统计信息

GO

SELECT * FROM sys.dm_os_latch_stats        — 返回按类组织的所有闩锁等待的相关信息

GO

SELECT * FROM sys.dm_os_wait_stats        — 返回执行的线程所遇到的所有等待的相关信息

GO

 

— 5.DBCC OUTPUTBUFFER 以十六进制和 ASCII 格式返回指定 session_id 的当前输出缓冲区

SELECT @@SPID

DBCC OUTPUTBUFFER (@@SPID) WITH NO_INFOMSGS        — 返回当前进程缓冲区内容

 

— 6.DBCC TRACESTATUS 显示跟踪标志的状态

— 在 SQL Server 中,有两种跟踪标志:会话和全局.会话跟踪标志对某个连接是有效的,只对该连接可见;

— 全局跟踪标志在服务器级别上进行设置,对服务器上的每一个连接都可见.

DBCC TRACESTATUS(-1) WITH NO_INFOMSGS;        — 显示当前全局启用的所有跟踪标志的状态

GO

DBCC TRACESTATUS (2528, 3205) WITH NO_INFOMSGS;        — 显示跟踪标志 2528 和 3205 的状态

GO

DBCC TRACESTATUS (3205, -1) WITH NO_INFOMSGS;        — 以下示例显示跟踪标志 3205 是否是全局启用的

GO

DBCC TRACESTATUS() WITH NO_INFOMSGS;        — 列出针对当前会话启用的所有跟踪标志

GO

 

— 7.DBCC PROCCACHE 以表格格式显示有关过程缓存的信息

— 使用过程缓存来缓存已编译计划和可执行计划,以加快批处理的执行速度.过程缓存中的项处于批处理级别.过程缓存包括以下项:

— A.已编译计划;B.执行计划;C.Algebrizer 树;D.扩展过程

DBCC PROCCACHE WITH NO_INFOMSGS

 

— 8.DBCC USEROPTIONS 返回当前连接的活动(设置)的 SET 选项

DBCC USEROPTIONS WITH NO_INFOMSGS;

GO

 

— 9.DBCC SHOW_STATISTICS 显示索引,统计信息或列的当前查询优化统计信息.根据统计信息对象中存储的数据,显示的相应统计信息包括标题,直方图和密度

USE AdventureWorks;

GO

— 以下示例显示 Person.Address 表的 AK_Product_Name 索引的所有统计信息

DBCC SHOW_STATISTICS (“Person.Address”, AK_Address_rowguid) — WITH NO_INFOMSGS, STAT_HEADER, DENSITY_VECTOR, HISTOGRAM;

GO

DBCC SHOW_STATISTICS (“Person.Address”, PK_Address_AddressID)

GO

 

— II.验证语句

— 1.DBCC CHECKALLOC 检查指定数据库的磁盘空间分配结构的一致性

DBCC CHECKALLOC;        — 不指定此参数或指定了 0 值,则默认值为当前数据库

GO

DBCC CHECKALLOC (N’AdventureWorks’);        — 检查AdventureWorks数据库

GO

— 显示当指定所有其他选项时运行 DBCC CHECKALLOC 所需的估计 tempdb 空间大小

DBCC CHECKALLOC WITH ALL_ERRORMSGS, NO_INFOMSGS, TABLOCK, ESTIMATEONLY

GO

 

— 2.DBCC CHECKFILEGROUP 检查当前数据库中指定文件组中的所有表和索引视图的分配和结构完整性

USE AdventureWorks;

GO

— 不指定此参数或指定了 0 值,则默认值为主文件组

DBCC CHECKFILEGROUP;

GO

— 通过指定主文件组的标识号并指定 NOINDEX,对 AdventureWorks 数据库主文件组(不包括非聚集索引)进行检查

DBCC CHECKFILEGROUP (1, NOINDEX);

GO

— 检查 AdventureWorks 数据库主文件组并指定选项 ESTIMATEONLY,所需的估计 tempdb 空间大小

DBCC CHECKFILEGROUP (1) WITH ESTIMATEONLY;

GO

 

— 3.DBCC CHECKCATALOG 检查指定数据库内的目录一致性.数据库必须联机

DBCC CHECKCATALOG;        — Check the current database.

GO

DBCC CHECKCATALOG (AdventureWorks);        — Check the AdventureWorks database.

GO

 

— 4.DBCC CHECKIDENT 检查指定表的当前标识值,如有必要,则更改标识值.还可以使用 DBCC CHECKIDENT 为标识列手动设置新的当前标识值

USE AdventureWorks;

GO

DBCC CHECKIDENT (“HumanResources.Employee”);        — 据需要重置 AdventureWorks 数据库中 Employee 表的当前标识值

GO

DBCC CHECKIDENT (“HumanResources.Employee”, NORESEED);– 报告 AdventureWorks 数据库的 Employee 表中的当前标识值,但如果该标识值不正确,不会进行更正

GO

DBCC CHECKIDENT (“HumanResources.Employee”, RESEED, 30);– 将 AdventureWorks 数据库的 Employee 表中的当前标识值强制设置为值 30

GO

 

— 5.DBCC CHECKCONSTRAINTS 检查当前数据库中指定表上的指定约束或所有约束的完整性

— 例检查 AdventureWorks 数据库中的 Table1 表的约束完整性

USE AdventureWorks;

GO

CREATE TABLE Table1 (Col1 int, Col2 char (30));

GO

INSERT INTO Table1 VALUES (100, ‘Hello’);

GO

ALTER TABLE Table1 WITH NOCHECK ADD CONSTRAINT chkTab1 CHECK (Col1 > 100);

GO

DBCC CHECKCONSTRAINTS(Table1);

GO

DROP TABLE Table1

GO

DBCC CHECKCONSTRAINTS (“Production.CK_ProductCostHistory_EndDate”);– 检查 CK_ProductCostHistory_EndDate 约束的完整性

GO

DBCC CHECKCONSTRAINTS WITH ALL_CONSTRAINTS;        — 检查当前数据库中所有表上的所有启用和禁用约束的完整性

GO

 

— 6.DBCC CHECKTABLE 检查组成表或索引视图的所有页和结构的完整性

— 若要对数据库中的每个表执行 DBCC CHECKTABLE,请使用 DBCC CHECKDB-

— 对于指定的表,DBCC CHECKTABLE 将检查以下内容:

— A.是否已正确链接索引,行内,LOB 以及行溢出数据页;

— B.索引是否按照正确的顺序排列;

— C.各指针是否一致;

— D.每页上的数据是否合理(包括计算列);

— E.页面偏移量是否合理;

— F.基表的每一行是否在每个非聚集索引中具有匹配的行,以及非聚集索引的每一行是否在基表中具有匹配的行;

— G.已分区表或索引的每一行是否都位于正确的分区中;

— H.使用 FILESTREAM 将 varbinary(max) 数据存储在文件系统中时,文件系统与表之间是否保持链接级一致性;

USE AdventureWorks;

GO

DBCC CHECKTABLE (“HumanResources.Employee”);– 检查 AdventureWorks 数据库中的 HumanResources.Employee 表的数据页完整性

GO

DBCC CHECKTABLE (“HumanResources.Employee”) WITH PHYSICAL_ONLY;– 将以较低的开销检查 AdventureWorks 数据库中的 Employee 表

GO

 

DECLARE @indid int;

SET @indid = (SELECT index_id

              FROM sys.indexes

              WHERE object_id = OBJECT_ID(‘Production.Product’)

                    AND name = ‘AK_Product_Name’);

DBCC CHECKTABLE (“Production.Product”, @indid);        — 将检查通过访问 sys.indexes 获得的特定索引

 

— 7.DBCC CHECKDB

— 通过执行下列操作检查指定数据库中所有对象的逻辑和物理完整性:

— A.对数据库运行 DBCC CHECKALLOC;

— B.对数据库中的每个表和视图运行 DBCC CHECKTABLE;

— C.对数据库运行 DBCC CHECKCATALOG;

— D.验证数据库中每个索引视图的内容;

— E.使用 FILESTREAM 在文件系统中存储 varbinary(max) 数据时,验证表元数据和文件系统目录和文件之间的链接级一致性;

— F.验证数据库中的 Service Broker 数据;

— 这意味着不必从 DBCC CHECKDB 单独运行 DBCC CHECKALLOC,DBCC CHECKTABLE 或 DBCC CHECKCATALOG 命令

 

— Check the current database.

DBCC CHECKDB;

GO

— Check the AdventureWorks database without nonclustered indexes.

DBCC CHECKDB (AdventureWorks, NOINDEX);

GO

DBCC CHECKDB WITH NO_INFOMSGS;        — 检查当前数据库,取消信息性消息

GO

 

— III.维护语句

— 1.DBCC CLEANTABLE 回收表或索引视图中已删除的可变长度列的空间

— DBCC CLEANTABLE 用于在删除可变长度列之后回收空间,可变长度列可以属于下列数据类型之一:varchar,nvarchar,varchar(max),nvarchar(max),varbinary,varbinary(max),text,ntext,image,sql_variant 和 xml.该命令不回收删除固定长度列后的空间.

— 如果删除的列存储在行内,则 DBCC CLEANTABLE 将从表的 IN_ROW_DATA 分配单元回收空间;如果列存储在行外,则将根据已删除列的数据类型从 ROW_OVERFLOW_DATA 或 LOB_DATA 分配单元回收空间;如果从 ROW_OVERFLOW_DATA 或 LOB_DATA 页回收空间时产生空页,DBCC CLEANTABLE 将删除该页

— DBCC CLEANTABLE 作为一个或多个事务运行。如果未指定批大小,则该命令将在一个事务中处理整个表,并在操作过程中以独占方式锁定该表.对于某些大型表,单个事务的长度和所需的日志空间可能太大.如果指定批大小,则该命令将在一系列事务中运行,每个事务包括指定的行数.DBCC CLEANTABLE 不能作为其他事务内的事务运行

— 该操作将被完整地记入日志。

— 系统表或临时表不支持使用 DBCC CLEANTABLE。

— 不应将 DBCC CLEANTABLE 作为日常维护任务来执行.而应在对表或索引视图中的可变长度列进行重要更改之后并且需要立即回收未使用空间时使用 DBCC CLEANTABLE.或者,也可以重新生成表或视图的索引;但是,此操作会耗费更多资源

DBCC CLEANTABLE (AdventureWorks,”Person.Address”, 0) WITH NO_INFOMSGS;

GO

— 创建一个表并用几个可变长度列填充该表.然后删除其中两列,并运行 DBCC CLEANTABLE 以回收未使用空间.在执行 DBCC CLEANTABLE 命令之前和之后,运行查询以验证页计数和已用空间值

USE AdventureWorks;

GO

IF OBJECT_ID (‘dbo.CleanTableTest’, ‘U’) IS NOT NULL

    DROP TABLE dbo.CleanTableTest;

GO

— 创建测试表 CleanTableTest

CREATE TABLE dbo.CleanTableTest

    (DocumentID int Not Null,

    FileName nvarchar(4000),

    DocumentSummary nvarchar(max),

    Document varbinary(max)

    );

GO

— Populate the table with data from the Production.Document table.

INSERT INTO dbo.CleanTableTest

    SELECT DocumentID,

           REPLICATE(FileName, 1000),        — 返回多次复制后的字符表达式

           DocumentSummary,

           Document

    FROM Production.Document;

GO

— Verify the current page counts and average space used in the dbo.CleanTableTest table.

DECLARE @db_id SMALLINT;

DECLARE @object_id INT;

SET @db_id = DB_ID(N’AdventureWorks’);

SET @object_id = OBJECT_ID(N’AdventureWorks.dbo.CleanTableTest’);

SELECT alloc_unit_type_desc,

       page_count,

       avg_page_space_used_in_percent,

       record_count

FROM sys.dm_db_index_physical_stats(@db_id, @object_id, NULL, NULL , ‘Detailed’);

GO

— Drop two variable-length columns from the table.

ALTER TABLE dbo.CleanTableTest

DROP COLUMN FileName, Document;

GO

— Verify the page counts and average space used in the dbo.CleanTableTest table

— Notice that the values have not changed.

DECLARE @db_id SMALLINT;

DECLARE @object_id INT;

SET @db_id = DB_ID(N’AdventureWorks’);

SET @object_id = OBJECT_ID(N’AdventureWorks.dbo.CleanTableTest’);

SELECT alloc_unit_type_desc,

       page_count,

       avg_page_space_used_in_percent,

       record_count

FROM sys.dm_db_index_physical_stats(@db_id, @object_id, NULL, NULL , ‘Detailed’);

GO

— Run DBCC CLEANTABLE.

DBCC CLEANTABLE (AdventureWorks,”dbo.CleanTableTest”);

GO

— Verify the values in the dbo.CleanTableTest table after the DBCC CLEANTABLE command.

DECLARE @db_id SMALLINT;

DECLARE @object_id INT;

SET @db_id = DB_ID(N’AdventureWorks’);

SET @object_id = OBJECT_ID(N’AdventureWorks.dbo.CleanTableTest’);

SELECT alloc_unit_type_desc,

       page_count,

       avg_page_space_used_in_percent,

       record_count

FROM sys.dm_db_index_physical_stats(@db_id, @object_id, NULL, NULL , ‘Detailed’);

GO

 

— 2.DBCC INDEXDEFRAG 指定表或视图的索引碎片整理.下一版本的 Microsoft SQL Server 将删除该功能.建议使用 ALTER INDEX

— DBCC INDEXDEFRAG 对索引的叶级进行碎片整理,以便页的物理顺序与叶节点从左到右的逻辑顺序相匹配,因此可提高索引扫描性能

— 对 AdventureWorks 数据库的 Production.Product 表中的 PK_Product_ProductID 索引的所有分区进行碎片整理。

DBCC INDEXDEFRAG (AdventureWorks, “Production.Product”, PK_Product_ProductID)

GO

— 使用 DBCC SHOWCONTIG 和 DBCC INDEXDEFRAG 对数据库中的索引进行碎片整理

— 该方法可用于对数据库中碎片数量在声明的阈值之上的所有索引进行碎片整理

— Declare variables

SET NOCOUNT ON;

DECLARE @tablename varchar(255);

DECLARE @execstr   varchar(400);

DECLARE @objectid  int;

DECLARE @indexid   int;

DECLARE @frag      decimal;

DECLARE @maxfrag   decimal;

 

— Decide on the maximum fragmentation to allow for.

SELECT @maxfrag = 30.0;

 

— Declare a cursor.

DECLARE tables CURSOR FOR

   SELECT TABLE_SCHEMA + ‘.’ + TABLE_NAME

   FROM INFORMATION_SCHEMA.TABLES

   WHERE TABLE_TYPE = ‘BASE TABLE’;

 

— Create the table.

CREATE TABLE #fraglist (

   ObjectName char(255),

   ObjectId int,

   IndexName char(255),

   IndexId int,

   Lvl int,

   CountPages int,

   CountRows int,

   MinRecSize int,

   MaxRecSize int,

   AvgRecSize int,

   ForRecCount int,

   Extents int,

   ExtentSwitches int,

   AvgFreeBytes int,

   AvgPageDensity int,

   ScanDensity decimal,

   BestCount int,

   ActualCount int,

   LogicalFrag decimal,

   ExtentFrag decimal);

 

— Open the cursor.

OPEN tables;

 

— Loop through all the tables in the database.

FETCH NEXT

   FROM tables

   INTO @tablename;

 

WHILE @@FETCH_STATUS = 0

BEGIN;

— Do the showcontig of all indexes of the table

   INSERT INTO #fraglist

   EXEC (‘DBCC SHOWCONTIG (”’ + @tablename + ”’)

      WITH FAST, TABLERESULTS, ALL_INDEXES, NO_INFOMSGS’);

   FETCH NEXT

      FROM tables

      INTO @tablename;

END;

 

— Close and deallocate the cursor.

CLOSE tables;

DEALLOCATE tables;

 

— Declare the cursor for the list of indexes to be defragged.

DECLARE indexes CURSOR FOR

   SELECT ObjectName, ObjectId, IndexId, LogicalFrag

   FROM #fraglist

   WHERE LogicalFrag >= @maxfrag

      AND INDEXPROPERTY (ObjectId, IndexName, ‘IndexDepth’) > 0;

 

— Open the cursor.

OPEN indexes;

 

— Loop through the indexes.

FETCH NEXT

   FROM indexes

   INTO @tablename, @objectid, @indexid, @frag;

 

WHILE @@FETCH_STATUS = 0

BEGIN;

   PRINT ‘Executing DBCC INDEXDEFRAG (0, ‘ + RTRIM(@tablename) + ‘,

      ‘ + RTRIM(@indexid) + ‘) – fragmentation currently ‘

       + RTRIM(CONVERT(varchar(15),@frag)) + ‘%’;

   SELECT @execstr = ‘DBCC INDEXDEFRAG (0, ‘ + RTRIM(@objectid) + ‘,

       ‘ + RTRIM(@indexid) + ‘)’;

   EXEC (@execstr);

 

   FETCH NEXT

      FROM indexes

      INTO @tablename, @objectid, @indexid, @frag;

END;

 

— Close and deallocate the cursor.

CLOSE indexes;

DEALLOCATE indexes;

 

— Delete the temporary table.

DROP TABLE #fraglist;

GO

— ALTER INDEX index_name ON talbe_name REORGANIZE;

USE AdventureWorks;

GO

ALTER INDEX PK_ProductPhoto_ProductPhotoID ON Production.ProductPhoto REORGANIZE;        `– 重新组织单个聚集索引

GO

 

— 3.DBCC DBREINDEX 对指定数据库中的表重新生成一个或多个索引,下一版本的 Microsoft SQL Server 将删除该功能.建议使用 ALTER INDEX。

— DBCC DBREINDEX 重新生成表的一个索引或为表定义的所有索引.通过允许动态重新生成索引,可以重新生成强制 PRIMARY KEY 或 UNIQUE 约束的索引,而不必删除并重新创建这些约束.这意味着无需了解表的结构或其约束,即可重新生成索引.这可能在将数据大容量复制到表中以后发生

USE AdventureWorks;

GO

— 使用填充因子 80 对 AdventureWorks 数据库中的 Employee 表重新生成 Employee_EmployeeID 聚集索引

DBCC DBREINDEX (“HumanResources.Employee”, PK_Employee_EmployeeID,80);

GO

— ALTER INDEX index_name ON talbe_name REBUILD;

USE AdventureWorks;

GO

ALTER INDEX PK_Employee_EmployeeID ON HumanResources.Employee REBUILD; — 在 Employee 表中重新生成单个索引

GO

 

— 4.DBCC SHRINKDATABASE  收缩指定数据库中的数据文件和日志文件的大小

— 若要收缩特定数据库的所有数据和日志文件,请执行 DBCC SHRINKDATABASE 命令;若要一次收缩一个特定数据库中的一个数据或日志文件,请执行 DBCC SHRINKFILE 命令

— 若要查看数据库中当前的可用(未分配)空间量,请运行 sp_spaceused

EXEC sp_spaceused

DBCC SHRINKDATABASE (AdventureWorks, 10);

GO

 

— 5.DBCC DROPCLEANBUFFERS 从缓冲池中删除所有清除缓冲区

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS

 

— 6.DBCC SHRINKFILE 收缩当前数据库的指定数据或日志文件的大小,或通过将数据从指定的文件移动到相同文件组中的其他文件来清空文件,以允许从数据库中删除该文件.文件大小可以收缩到比创建该文件时所指定的大小更小.这样会将最小文件大小重置为新值

— 将日志文件收缩到指定的目标大小,将 AdventureWorks 数据库中的日志文件收缩到 1 MB.若要允许 DBCC SHRINKFILE 命令收缩文件,首先需要通过将数据库恢复模式设置为 SIMPLE 来截断该文件.

— 将 AdventureWorks 用户数据库中名为 DataFile1 的数据文件的大小收缩到 1 MB。

USE AdventureWorks;

GO

DBCC SHRINKFILE (DataFile1, 1);

GO

 

USE AdventureWorks;

GO

— Truncate the log by changing the database recovery model to SIMPLE.

ALTER DATABASE AdventureWorks

SET RECOVERY SIMPLE;

GO

— Shrink the truncated log file to 1 MB.

DBCC SHRINKFILE (AdventureWorks_Log, 1);

GO

— Reset the database recovery model.

ALTER DATABASE AdventureWorks

SET RECOVERY FULL;

GO

 

— 清空文件以便从数据库中将其删除的步骤

USE AdventureWorks;

GO

— Create a data file and assume it contains data.

ALTER DATABASE AdventureWorks

ADD FILE (

    NAME = Test1data,

    FILENAME = ‘C:/t1data.ndf’,

    SIZE = 5MB

    );

GO

— Empty the data file.

DBCC SHRINKFILE (Test1data, EMPTYFILE);

GO

— Remove the data file from the database.

ALTER DATABASE AdventureWorks

REMOVE FILE Test1data;

GO

 

— 7.DBCC FREEPROCCACHE 删除计划缓存中的所有元素,通过指定计划句柄或 SQL 句柄从计划缓存删除特定计划,或者删除指定资源池中的所有工作负荷组

— 通过指定查询计划句柄从计划缓存中清除查询计划.为了确保示例查询在计划缓存中,首先执行该查询.将查询 sys.dm_exec_cached_plans 和 sys.dm_exec_sql_text 动态管理视图以返回查询的计划句柄.然后,将结果集中的计划句柄值插入 DBCC FREEPROCACHE 语句,以从计划缓存中仅删除该计划

USE AdventureWorks;

GO

SELECT * FROM Person.Address;

GO

SELECT plan_handle, st.text

FROM sys.dm_exec_cached_plans

CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS st

WHERE text LIKE N’SELECT * FROM Person.Address%’;

GO

— Remove the specific plan from the cache.

DBCC FREEPROCCACHE (0x060006001ECA270EC0215D05000000000000000000000000);

GO

 

— 清除计划缓存中的所有计划

— 小心使用 DBCC FREEPROCCACHE 清除计划缓存.释放计划缓存将导致系统重新编译存储过程,而不重用缓存中的存储过程.这会导致查询性能暂时性地突然降低.对于计划缓存中每个已清除的缓存存储区

DBCC FREEPROCCACHE WITH NO_INFOMSGS;

 

— 8.DBCC UPDATEUSAGE 报告目录视图中的页数和行数错误并进行更正

DBCC UPDATEUSAGE (0);        — 为当前数据库中的所有对象更新页数或行数,或同时更新两者

GO

 

USE AdventureWorks;

GO

DBCC UPDATEUSAGE (AdventureWorks) WITH NO_INFOMSGS; — 为 AdventureWorks 更新页数和行数,或同时更新两者,并禁止显示信息性消息

GO

DBCC UPDATEUSAGE (AdventureWorks,”HumanResources.Employee”);– 报告 AdventureWorks 数据库中 Employee 表的已更新页数或行数信息

GO

DBCC UPDATEUSAGE (AdventureWorks, “HumanResources.Employee”, IX_Employee_ManagerID);– 为表中的特定索引更新页数或行数,或同时更新两者

GO

 

— IV.杂项语句

— 1.DBCC dllname (FREE) 从内存中释放指定的扩展存储过程 DLL

— 执行扩展存储过程时,DLL 仍保持由 SQL Server 的实例加载,直到服务器关闭为止.此语句允许从内存中卸载 DLL,而不用关闭 SQL Server

DBCC xpstar ( FREE ) WITH NO_INFOMSGS

 

— 存储过程 sp_helpextendedproc 报告当前定义的扩展存储过程以及该过程(函数)所属的动态链接库(DLL)的名称,后续版本的 Microsoft SQL Server 将删除该功能

USE master;

GO

EXEC sp_helpextendedproc;        — 对所有扩展存储过程进行报告

GO

EXEC sp_helpextendedproc xp_cmdshell;        — 对 xp_cmdshell 扩展存储过程进行报告

GO

 

— 2.DBCC TRACEOFF  禁用指定的跟踪标记

DBCC TRACEOFF (3205) WITH NO_INFOMSGS;        — 禁用跟踪标记 3205

GO

DBCC TRACEOFF (3205, -1) WITH NO_INFOMSGS;        — 全局禁用跟踪标记 3205

GO

DBCC TRACEOFF (3205, 260, -1) WITH NO_INFOMSGS;        — 全局禁用跟踪标记 3205 和 260

GO

 

— 3.DBCC TRACEON 启用指定的跟踪标记

— 在生产服务器上,为了避免意外行为,建议您使用下列方法之一,仅在服务器范围内启用跟踪标记:

— A.使用 Sqlservr.exe 的 -T 命令行启动选项.这是推荐的最佳实践,因为这样可确保将所有语句运行时使用已启用的跟踪标志.这些语句包括启动脚本中的命令

— B.仅在用户或应用程序未对系统以并行方式运行语句时,才使用 DBCC TRACEON ( trace# [, ….n], -1 )

— 跟踪标记用于通过控制 SQL Server 的运行方式来自定义某些特征.启用的跟踪标记将在服务器中一直保持启用状态,

— 直到执行 DBCC TRACEOFF 语句将其禁用为止.在 SQL Server 中,有两种跟踪标志:会话和全局.会话跟踪标志对某个连接是有效的,只对该连接可见;

— 全局跟踪标志在服务器级别上进行设置,对服务器上的每一个连接都可见.若要确定跟踪标记的状态,请使用 DBCC TRACESTATUS.若要禁用跟踪标记,请使用 DBCC TRACEOFF

DBCC TRACEON (3205) WITH NO_INFOMSGS;        — 打开跟踪标记 3205,禁用磁带驱动程序的硬件压缩功能.仅为当前连接打开此标记

GO

DBCC TRACEON (3205, -1) WITH NO_INFOMSGS;        — 全局方式打开跟踪标记 3205

GO

DBCC TRACEON (3205, 260, -1) WITH NO_INFOMSGS;        — 全局方式打开跟踪标记 3205 和 260

GO

 

— 4.DBCC HELP 返回指定的 DBCC 命令的语法信息

DBCC HELP (‘?’);        — 返回可查看其帮助信息的所有 DBCC 语句

GO

DBCC HELP (‘checkdb’);        — 返回 DBCC CHECKDB 的语法信息

GO

 

— V.其它语句

— 1.DBCC FREESESSIONCACHE 刷新针对 Microsoft SQL Server 实例执行的分布式查询所使用的分布式查询连接缓存

USE AdventureWorks;

GO

DBCC FREESESSIONCACHE WITH NO_INFOMSGS;        — 将刷新分布式查询缓存

GO

 

— 2.DBCC FREESYSTEMCACHE 从所有缓存中释放所有未使用的缓存条目.

— SQL Server 数据库引擎会事先在后台清理未使用的缓存条目,以使内存可用于当前条目.但是,可以使用此命令从所有缓存中手动删除未使用的条目

— Clean all the caches with entries specific to the resource pool named “default”.

DBCC FREESYSTEMCACHE (‘ALL’,’default’)        — 清除特定于某个资源调控器资源池的缓存

 

— 3.DBCC PINTABLE 将表标记为驻留,这表示 Microsoft SQL Server 不从内存中刷新表页

— DBCC PINTABLE 不会导致将表读入到内存中.当表中的页由普通的 Transact-SQL 语句读入到高速缓存中时,这些页将标记为内存驻留页.

— 当 SQL Server 需要空间以读入新页时,不会清空内存驻留页.SQL Server 仍然记录对页的更新,并且如有必要,将更新的页写回到磁盘.

— 然而,在使用 DBCC UNPINTABLE 语句使该表不驻留之前,SQL Server 在高速缓存中一直保存可用页的复本.

— DBCC PINTABLE 最适用于将小的,经常引用的表保存在内存中.将小表的页一次性读入到内存中,将来对其数据的所有引用都不需要从磁盘读入.

— 驻留 AdventureWorks 数据库中的 Person.Address 表

DECLARE @db_id int, @tbl_id int

USE AdventureWorks

SET @db_id = DB_ID(‘AdventureWorks’)

SET @tbl_id = OBJECT_ID(‘Person.Address’)

DBCC PINTABLE (@db_id, @tbl_id)

GO

 

— 4.DBCC UNPINTABLE 将表标记为不在内存驻留.将表标记为不在内存驻留后,可以清空高速缓存中的表页

— DBCC UNPINTABLE 不会导致立即将表从数据高速缓存中清空.而指定如果需要空间以从磁盘中读入新页,高速缓存中的表的所有页都可以清空

— 不驻留 AdventureWorks 数据库中的 Person.Address 表

DECLARE @db_id int, @tbl_id int

USE AdventureWorks

SET @db_id = DB_ID(‘AdventureWorks’)

SET @tbl_id = OBJECT_ID(‘Person.Address’)

DBCC UNPINTABLE (@db_id, @tbl_id)

GO