SQL Server的查询优化器在select查询执行的时候产生一个高效的查询执行计划。若是优化器不能选择最优的计划,那么就须要检查查询计划、统计信息、支持的索引等,而经过使用提示能够改变优化器选择查询计划的工程,使优化器生成一个更好的执行计划。sql
一、联接提示数据库
<join_hint> ::= { LOOP | HASH | MERGE | REMOTE }express
--没有提示的查询 select * from Production.Product p inner join production.productreview r on r.productid = p.productid --Loop适合:当一个表很小另外一个表很大、在关联的列上有索引时 select * from Production.Product p inner loop join production.productreview r on r.productid = p.productid --merge适合:按照关联列排序的中等或者大的表 select * from Production.Product p inner merge join production.productreview r on r.productid = p.productid --hash适合:没有排序的大的表 select * from Production.Product p inner hash join production.productreview r on r.productid = p.productid
二、查询提示与表提示架构
<query_hint > ::= { { HASH | ORDER } GROUP | { CONCAT | HASH | MERGE } UNION | { LOOP | MERGE | HASH } JOIN | EXPAND VIEWS | FAST number_rows | FORCE ORDER | IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX | KEEP PLAN | KEEPFIXED PLAN | MAXDOP number_of_processors | MAXRECURSION number | OPTIMIZE FOR ( @variable_name { UNKNOWN | = literal_constant } [ , ...n ] ) | OPTIMIZE FOR UNKNOWN | PARAMETERIZATION { SIMPLE | FORCED } | RECOMPILE | ROBUST PLAN | USE PLAN N'xml_plan' | TABLE HINT ( exposed_object_name [ , <table_hint> [ [, ]...n ] ] ) } <table_hint> ::= [ NOEXPAND ] { INDEX ( index_value [ ,...n ] ) | INDEX = ( index_value ) | FORCESEEK [( index_value ( index_column_name [,... ] ) ) ] | FORCESCAN | HOLDLOCK | NOLOCK | NOWAIT | PAGLOCK | READCOMMITTED | READCOMMITTEDLOCK | READPAST | READUNCOMMITTED | REPEATABLEREAD | ROWLOCK | SERIALIZABLE | SPATIAL_WINDOW_MAX_CELLS = integer | TABLOCK | TABLOCKX | UPDLOCK | XLOCK
查询提示的参数并发
OPTIMIZE FOR 能够抵消优化器的默认参数检测行为,也可在建立计划指南时使用。有关详细信息,请参阅从新编译存储过程。
OPTIMIZE FOR UNKNOWN指示查询优化器在编译和优化查询时使用全部局部变量的统计数据而不是初始值,包括使用强制参数化建立的参数。
若是在同一查询提示中使用 OPTIMIZE FOR @variable_name = literal_constant 和 OPTIMIZE FOR UNKNOWN,则查询优化器对特定值使用指定的 literal_constant,而对其他变量值使用 UNKNOWN。 这些值仅用于查询优化期间,而不会用于查询执行期间。
PARAMETERIZATION { SIMPLE | FORCED }指定在编译查询时 SQL Server 查询优化器应用于此查询的参数化规则。
![]() |
---|
PARAMETERIZATION 查询提示只能在计划指南中指定。 不能直接在查询中指定该查询提示。 |
SIMPLE 用于指示查询优化器尝试进行简单参数化。 FORCED 用于指示优化器尝试进行强制参数化。 PARAMETERIZATION 查询提示用于覆盖计划指南中 PARAMETERIZATION 数据库 SET 选项的当前设置。有关详细信息,请参阅使用计划指南指定查询参数化行为。
RECOMPILE指示 SQL Server 数据库引擎在执行为查询生成的计划后将其丢弃,从而在下次执行同一查询时强制查询优化器从新编译查询计划。若是未指定 RECOMPILE,数据库引擎将缓存查询计划并从新使用它们。在编译查询计划时,RECOMPILE 查询提示将使用查询中任意本地变量的当前值,若是查询位于存储过程当中,这些当前值将传递给任意参数。
在只须从新编译存储过程当中的一部分查询,而不是从新编译整个存储过程时,RECOMPILE 是建立使用 WITH RECOMPILE 子句的存储过程的颇有用的替代方法。有关详细信息,请参阅从新编译存储过程。在建立计划指南时,RECOMPILE 也颇有用。
ROBUST PLAN强制查询优化器尝试一个计划,该计划可能以性能为代价得到最大可能的行大小。 处理查询时,中间表和运算符可能须要存储和处理比输入行宽的行。 在有些状况下,行可能很宽,以至某个运算符没法处理行。若是发生这种状况,数据库引擎将在查询执行过程当中生成错误。经过使用 ROBUST PLAN,能够指示查询优化器不考虑可能会遇到该问题的全部查询计划。
若是不能使用这样的计划,查询优化器将返回错误而不是延迟对查询执行的错误检测。行能够包含可变长度列;数据库引擎容许将行大小定义为超过数据库引擎处理能力的最大可能的大小。一般,应用程序存储实际大小在数据库引擎处理能力范围内的行,而无论最大可能大小。若是数据库引擎遇到过长的行,则返回执行错误。
USE PLAN N'xml_plan'强制查询优化器对查询使用由 'xml_plan' 指定的现有查询计划。不能使用 INSERT、UPDATE、MERGE 或 DELETE 语句来指定 USE PLAN。
TABLE HINT (exposed_object_name [, <table_hint> [ [, ]...n] ])将指定的表提示应用到与 exposed_object_name 对应的表或视图。咱们建议仅在计划指南的上下文中将表提示用做查询提示。
exposed_object_name 能够为如下引用之一:
当对查询的 FROM 子句中的表或视图使用别名时,exposed_object_name 就是别名。
若是不使用别名,exposed_object_name 与 FROM 子句中引用的表或视图彻底匹配。例如,若是使用由两部分组成的名称引用了表或视图,则exposed_object_name 就是这个由两部分组成的名称。
若是指定了 exposed_object_name 但未指定表提示,则将忽略在查询中指定为对象表提示的一部分的任何索引,并由查询优化器来决定索引的使用。当您没法修改原始查询时,可使用此方法来消除 INDEX 表提示的影响。请参阅示例 J。
<table_hint> ::= { [ NOEXPAND ] { INDEX ( index_value [ ,...n] ) | INDEX = (index_value ) | FORCESEEK [(index_value(index_column_name [,...])) ]| FORCESCAN | HOLDLOCK | NOLOCK | NOWAIT | PAGLOCK | READCOMMITTED | READCOMMITTEDLOCK | READPAST | READUNCOMMITTED | REPEATABLEREAD | ROWLOCK | SERIALIZABLE |SPATIAL_WINDOW_MAX_CELLS | TABLOCK | TABLOCKX | UPDLOCK | XLOCK }要做为查询提示应用于与 exposed_object_name对应的表或视图的表提示。有关这些提示的说明,请参阅表提示 (Transact-SQL)。
不容许将非 INDEX、FORCESCAN 和 FORCESEEK 的表提示用做查询提示,除非该查询已经具备一个指定该表提示的 WITH 子句。有关详细信息,请参阅备注。
![]() |
---|
指定带参数的 FORCESEEK 限制优化器能够考虑的计划数大于指定不带参数的 FORCESEEK 时的计划数。这可能致使在更多状况下出现“没法生成计划”错误。在将来的版本中,对优化器进行内部修改后可容许考虑更多计划。 |
只有在 INSERT 语句中使用了 SELECT 子句时,才能在该语句中指定查询提示。
只能在顶级查询中指定查询提示,不能在子查询指定。 将表提示指定为查询提示时,能够在顶级查询或子查询中指定此提示,但为 TABLE HINT 子句中的 exposed_object_name 指定的值必须与该查询或子查询中公开的名称彻底匹配。
咱们建议仅在计划指南的上下文中将 INDEX、FORCESCAN 或 FORCESEEK 表提示用做查询提示。当您没法修改原始查询时(例如,因为它是第三方应用程序),计划指南将颇有用。计划指南中指定的查询提示在查询编译和优化前添加到查询中。对于即席查询,仅在测试计划指南语句时才应使用 TABLE HINT 子句。对于全部其余即席查询,建议仅将这些提示指定为表提示。
若是将 INDEX、FORCESCAN 和 FORCESEEK 表提示指定为查询提示,它们会对如下对象有效:
表
视图
索引视图
公用表表达式(必须在其结果集填充公用表表达式的 SELECT 语句中指定提示)
动态管理视图
命名子查询
能够为没有任何现有表提示的查询指定 INDEX、FORCESCAN 和 FORCESEEK 表提示做为查询提示,这些提示也可用于分别替换查询中的现有 INDEX、FORCESCAN 或 FORCESEEK 提示。不容许将非 INDEX、FORCESCAN 和 FORCESEEK 的表提示用做查询提示,除非该查询已经具备一个指定该表提示的 WITH 子句。这种状况下,还必须使用 OPTION 子句中的 TABLE HINT 来将匹配的提示指定为查询提示,以保留查询的语义。例如,若是查询包含表提示 NOLOCK,则计划指南的@hints 参数中的 OPTION 子句必须也包含 NOLOCK 提示。请参见示例 K。当经过使用 OPTION 子句中的 TABLE HINT 指定了非 INDEX、FORCESCAN 或 FORCESEEK 的表提示,而未指定匹配的查询提示时,或指定了后者而未指定前者,则会引起错误 8702,表示 OPTION 子句会致使查询的语义发生变化,该查询将失败。
declare @a table (v varchar(100),vid int) insert into @a select 'abc' as v,1 as vid union all select 'cde',123 union all select 'cd',2 union all select 'abc',12 union all select 'def',123 union all select 'cde',12 union all select 'def',2 union all select 'cde',1 union all select 'cdef',1 --1.group --1.1hash select v, COUNT(vid) from @a group by v option(hash group) --1.2order select v, COUNT(vid) from @a group by v option(order group) --1.3能够用在distinct中 select distinct * from @a option(order group) --2.union --2.1hash select 'abc' as v,1 as vid union select 'cd',123 union select 'cd',2 union select 'abc',1 option(hash union) --2.2merge select 'abc' as v,1 as vid union select 'cd',123 union select 'cd',2 union select 'abc',1 option(merge union) --2.3concat select 'abc' as v,1 as vid union select 'cd',123 union select 'cd',2 union select 'abc',1 option(concat union) --3.join --3.1hash select * from ( select 'abc' as v,1 as vid union all select 'cd',2 )a inner join ( select 'cd' as v,2 as vid union all select 'abc',1 )b on a.vid = b.vid option(hash join) --3.2merge select * from ( select 'abc' as v,1 as vid union all select 'cd',2 )a inner join ( select 'cd' as v,2 as vid union all select 'abc',1 )b on a.vid = b.vid option(merge join) --3.3loop select * from ( select 'abc' as v,1 as vid union all select 'cd',2 )a inner join ( select 'cd' as v,2 as vid union all select 'abc',1 )b on a.vid = b.vid option(loop join) --4.expand views --建表 select * into wc_objects from sys.objects --添加主键约束 alter table wc_objects add constraint pk_wc_objectid primary key(object_id) --建立视图 create view select_wc_objects with schemabinding as select name, object_id, type, type_desc from dbo.wc_objects go --建立惟一的汇集索引做为视图索引(也就是视图对应的索引) create unique clustered index uni_select_wc_objects on select_wc_objects(object_id) --这里会展开视图,直接引用底层的原始表wc_objects select * from select_wc_objects --不会展开,直接使用惟一汇集索引uni_select_wc_objects中的数据 select * from select_wc_objects with(noexpand) --5.fast n:对查询进行优化,以便快速检索前n行 select o.OrderDate, o.SalesOrderNumber from sales.SalesOrderHeader o inner join sales.SalesOrderDetail d on o.SalesOrderID =d.SalesOrderID option(fast 100) --在返回前n行后,查询继续执行并生成完整的结果集 --6.force order:通常不建议使用,应该由SQL Server来决定联接顺序 SELECT * FROM sales.SalesOrderHeader o INNER JOIN sales.SalesOrderDetail m ON O.salesorderid = m.salesorderid inner join production.Product e on m.ProductID = e.ProductID option(force order) --用了这个致使查询更慢 --7.keep plan:强制查询优化器对查询放宽估计的从新编译阈值 SELECT * FROM sales.SalesOrderHeader o INNER JOIN sales.SalesOrderDetail m ON O.salesorderid = m.salesorderid inner join production.Product e on m.ProductID = e.ProductID option(keep plan) --8.keepfixed plan:强制查询优化器不因统计信息的更改而从新编译查询 --可确保只有更改基础表的架构或在那些表上执行sp_recompile时才从新编译查询 SELECT * FROM sales.SalesOrderHeader o INNER JOIN sales.SalesOrderDetail m ON O.salesorderid = m.salesorderid inner join production.Product e on m.ProductID = e.ProductID option(keepfixed plan) /*================================= 9.maxrecursion自动产生大量连续的数字 ==================================*/ WITH t AS ( SELECT 1 AS r UNION ALL SELECT r+1 FROM t WHERE r < 10000 ) SELECT * FROM t OPTION(maxrecursion 10000) --限制最大递归数字 --10.MAXDOP --对于指定了max degree of parallelism配置选项的查询, --会覆盖sp_configure 和资源调控器的该选项 SELECT * FROM sales.SalesOrderHeader o INNER JOIN sales.SalesOrderDetail m ON O.salesorderid = m.salesorderid inner join production.Product e on m.ProductID = e.ProductID option(maxdop 2) --11.OPTIMIZE FOR declare @name nvarchar(50) declare @id int select @name ='a', @id =500 SELECT * FROM sales.SalesOrderHeader o INNER JOIN sales.SalesOrderDetail m ON O.salesorderid = m.salesorderid inner join production.Product e on m.ProductID = e.ProductID where e.Name like @name +'%' and e.ProductID >= @id option(optimize for(@name='a',@id unknown)) --12.OPTIMIZE FOR UNKNOWN declare @name1 nvarchar(50) declare @id1 int select @name1 ='a', @id1 =500; SELECT * FROM sales.SalesOrderHeader o INNER JOIN sales.SalesOrderDetail m ON O.salesorderid = m.salesorderid inner join production.Product e on m.ProductID = e.ProductID where e.Name like @name1 +'%' and e.ProductID >= @id1 option(optimize for unknown) --12.use plan create table txt(id numeric(10,0) primary key, v varchar(20), vv int ) create index txt_v on txt(v) insert into txt select object_id, type_desc, schema_id from sys.objects where LEN(type_desc) < 20 --取得xml格式的执行计划 set statistics xml on select * from txt where id > 1000 and vv > 2 set statistics xml off select * from txt option( use plan '<ShowPlanXML xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan" Version="1.1" Build="10.50.1600.1"> <BatchSequence><Batch><Statements> <StmtSimple StatementText="SELECT * FROM [txt] WHERE [id]>@1 AND [vv]>@2" StatementId="1" StatementCompId="1" StatementType="SELECT" StatementSubTreeCost="0.00429444" StatementEstRows="42.2945" StatementOptmLevel="TRIVIAL" QueryHash="0xA4E0AA4B0A87F88B" QueryPlanHash="0x3325250D8A42F500"> <StatementSetOptions QUOTED_IDENTIFIER="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" NUMERIC_ROUNDABORT="false"/> <QueryPlan DegreeOfParallelism="1" CachedPlanSize="16" CompileTime="1" CompileCPU="1" CompileMemory="136"><RelOp NodeId="0" PhysicalOp="Clustered Index Seek" LogicalOp="Clustered Index Seek" EstimateRows="42.2945" EstimateIO="0.00386574" EstimateCPU="0.0004287" AvgRowSize="34" EstimatedTotalSubtreeCost="0.00429444" TableCardinality="292" Parallel="0" EstimateRebinds="0" EstimateRewinds="0"> <OutputList><ColumnReference Database="[test2]" Schema="[dbo]" Table="[txt]" Column="id"/><ColumnReference Database="[test2]" Schema="[dbo]" Table="[txt]" Column="v"/> <ColumnReference Database="[test2]" Schema="[dbo]" Table="[txt]" Column="vv"/> </OutputList><RunTimeInformation><RunTimeCountersPerThread Thread="0" ActualRows="5" ActualEndOfScans="1" ActualExecutions="1"/> </RunTimeInformation><IndexScan Ordered="1" ScanDirection="FORWARD" ForcedIndex="0" ForceSeek="0" NoExpandHint="0"><DefinedValues> <DefinedValue><ColumnReference Database="[test2]" Schema="[dbo]" Table="[txt]" Column="id"/> </DefinedValue><DefinedValue><ColumnReference Database="[test2]" Schema="[dbo]" Table="[txt]" Column="v"/></DefinedValue><DefinedValue> <ColumnReference Database="[test2]" Schema="[dbo]" Table="[txt]" Column="vv"/></DefinedValue></DefinedValues> <Object Database="[test2]" Schema="[dbo]" Table="[txt]" Index="[PK__txt__3213E83F4D1564AE]" IndexKind="Clustered"/> <SeekPredicates><SeekPredicateNew><SeekKeys> <StartRange ScanType="GT"><RangeColumns> <ColumnReference Database="[test2]" Schema="[dbo]" Table="[txt]" Column="id"/></RangeColumns><RangeExpressions><ScalarOperator ScalarString="CONVERT_IMPLICIT(numeric(10,0),[@1],0)"><Identifier> <ColumnReference Column="ConstExpr1003"><ScalarOperator> <Convert DataType="numeric" Precision="10" Scale="0" Style="0" Implicit="1"> <ScalarOperator><Identifier><ColumnReference Column="@1"/> </Identifier></ScalarOperator></Convert></ScalarOperator> </ColumnReference></Identifier></ScalarOperator> </RangeExpressions></StartRange></SeekKeys></SeekPredicateNew> </SeekPredicates><Predicate><ScalarOperator ScalarString="[test2].[dbo].[txt].[vv]>CONVERT_IMPLICIT(int,[@2],0)"><Compare CompareOp="GT"> <ScalarOperator><Identifier><ColumnReference Database="[test2]" Schema="[dbo]" Table="[txt]" Column="vv"/></Identifier></ScalarOperator><ScalarOperator> <Identifier><ColumnReference Column="ConstExpr1004"><ScalarOperator> <Convert DataType="int" Style="0" Implicit="1"><ScalarOperator> <Identifier><ColumnReference Column="@2"/></Identifier> </ScalarOperator></Convert></ScalarOperator></ColumnReference> </Identifier></ScalarOperator></Compare></ScalarOperator> </Predicate></IndexScan></RelOp><ParameterList> <ColumnReference Column="@2" ParameterCompiledValue="(2)" ParameterRuntimeValue="(2)"/> <ColumnReference Column="@1" ParameterCompiledValue="(1000)" ParameterRuntimeValue="(1000)"/></ParameterList></QueryPlan> </StmtSimple></Statements></Batch></BatchSequence></ShowPlanXML>') --14.PARAMETERIZATION { SIMPLE | FORCED } --PARAMETERIZATION查询提示只能在计划指南中指定,不能直接在查询中指定该查询提示 --14.1运行多条相似的查询 select * from txt where id = 8 select * from txt where id = 9 --14.2经过查询缓存的计划所对应的sql文本,发现不少都是相同的 --并且大部分的objtype都是proc,adhoc,prepared. SELECT * FROM SYS.dm_exec_cached_plans E CROSS APPLY SYS.dm_exec_sql_text(E.plan_handle)EE WHERE EE.text LIKE '%select * from txt where id =%' declare @sqltext nvarchar(max) declare @parameter nvarchar(max) --14.3获取查询的参数化形式以及查询的参数,放入变量中 exec sp_get_query_template @querytext = N'select * from txt where id = 8', @templatetext= @sqltext output, @parameters = @parameter output --14.4使用模板来建立计划指南 exec sp_create_plan_guide @name = 'plan_guide_txt_template', @stmt = @sqltext, @type = 'template', @module_or_batch = null, @params = @parameter, @hints = 'option(parameterization forced)' --14.5再次查询发现多条执行计划已经变为一条,usecounts计数增长 SELECT * FROM SYS.dm_exec_cached_plans E CROSS APPLY SYS.dm_exec_sql_text(E.plan_handle)EE WHERE EE.text LIKE '%select * from txt where id =%' --15.ROBUST PLAN --查询优化器尝试一个计划,该计划可能以性能为代价得到最大可能的行大小 SELECT * FROM sales.SalesOrderHeader o INNER JOIN sales.SalesOrderDetail m ON O.salesorderid = m.salesorderid inner join production.Product e on m.ProductID = e.ProductID option(ROBUST PLAN) --16.RECOMPILE SELECT * FROM sales.SalesOrderHeader o INNER JOIN sales.SalesOrderDetail m ON O.salesorderid = m.salesorderid inner join production.Product e on m.ProductID = e.ProductID option(recompile) --若是是存储过程,能够经过下面的方式来显式的从新编译 exec 存储过程名称 with recompile
表提示的参数
能够经过如下方式指定 FORCESEEK 提示。
语法 |
示例 |
说明 |
---|---|---|
没有索引或 INDEX 提示 |
FROM dbo.MyTable WITH (FORCESEEK) |
查询优化器仅考虑执行索引查找操做以经过任意相关索引访问表或视图。 |
与 INDEX 提示组合使用 |
FROM dbo.MyTable WITH (FORCESEEK, INDEX (MyIndex)) |
查询优化器仅考虑执行索引查找操做以经过指定的索引访问表或视图。 |
经过指定索引和索引列进行参数化 |
FROM dbo.MyTable WITH (FORCESEEK (MyIndex (col1, col2, col3))) |
查询优化器仅考虑执行索引查找操做,以经过指定的索引(至少使用指定的索引列)访问表或视图。 |
使用 FORCESEEK 提示(具备或不带索引参数)时,考虑如下准则。
该提示能够指定为表提示或查询提示。 有关查询提示的详细信息,请参阅查询提示 (Transact-SQL)。
若要将 FORCESEEK 应用到索引视图,还必须指定 NOEXPAND 提示。
对每一个表或视图最多应用该提示一次。
不能为远程数据源指定该提示。 带索引提示指定 FORCESEEK 时,将返回错误 7377;不带索引提示使用 FORCESEEK 时,将返回错误 8180。
若是 FORCESEEK 致使找不到计划,将返回错误 8622。
使用索引参数指定 FORCESEEK 时,遵循如下准则和限制。
该提示不能与 INDEX 提示或另外一个 FORCESEEK 提示一块儿指定。
至少必须指定一个列且该列为第一个键列。
能够指定其余索引列,可是不能跳过键列。 例如,若是指定的索引包含键列 a、b 和 c,则有效的语法应包含 FORCESEEK (MyIndex (a)) 和 FORCESEEK (MyIndex (a, b)。 无效的语法应包含FORCESEEK (MyIndex (c)) 和FORCESEEK (MyIndex (a, c)。
在提示中指定的列名顺序必须与引用的索引中列的顺序匹配。
不能指定不在索引键定义中的列。 例如,在非汇集索引中,只能指定定义的索引键列。 不能指定自动包含在索引中的汇集键列,可是优化器可使用这些列。
xVelocity 内存优化的列存储索引不能做为索引参数指定。 返回错误 366。
修改索引定义(例如经过添加或删除列)可能须要修改引用该索引的查询。
该提示阻止优化器考虑表的任何空间或 XML 索引。
该提示不能与 FORCESCAN 提示一块儿指定。
对于分区的索引,不能在 FORCESEEK 提示中指定 SQL Server 隐式添加的分区列。
![]() |
---|
指定带参数的 FORCESEEK 限制优化器能够考虑的计划数大于指定不带参数的 FORCESEEK 时的计划数。这可能致使在更多状况下出现“没法生成计划”错误。在将来的版本中,对优化器进行内部修改后可容许考虑更多计划。 |
此提示在 SQL Server 2008 R2 SP1 中引入,它指定查询优化器仅将索引扫描操做做为引用的表或视图的访问路径。对于优化器低估受影响的行数并选择一个查找操做而非扫描操做的查询,FORCESCAN 提示颇有用。出现这样的状况时,授予该操做的内存量过小,查询性能将受影响。
指定 FORCESCAN 时有无 INDEX 提示都可。 与索引提示组合使用 (INDEX = index_name, FORCESCAN) 时,查询优化器在访问引用的表时仅考虑经过指定的索引扫描访问路径。能够带索引提示 INDEX(0) 指定 FORCESCAN,以强制对基表执行表扫描操做。
对于分区的表和索引,在经过查询谓词评估消除分区后应用 FORCESCAN。这意味着扫描仅适用于剩余分区而非整个表。
FORCESCAN 提示存在如下限制。
不能为做为 INSERT、UPDATE 或 DELETE 语句的目标的表指定该提示。
该提示不能与一个以上的索引提示一块儿使用。
该提示阻止优化器考虑表的任何空间或 XML 索引。
不能为远程数据源指定该提示。
该提示不能与 FORCESEEK 提示一块儿指定。
等同于 SERIALIZABLE。 有关详细信息,请参阅本主题后面的 SERIALIZABLE。 HOLDLOCK 仅应用于那些为其指定了 HOLDLOCK 的表或视图,而且仅在使用了 HOLDLOCK 的语句定义的事务的持续时间内应用。HOLDLOCK 不能被用于包含 FOR BROWSE 选项的 SELECT 语句。
IGNORE_CONSTRAINTS只适用于 INSERT 语句(当 BULK 选项与 OPENROWSET 一块儿使用时)。
指定大容量导入操做将忽略对表的任何约束。 默认状况下,INSERT 将检查惟一约束和 CHECK 约束和主键和外键约束。当为大容量导入操做指定 IGNORE_CONSTRAINTS 时,INSERT 必须忽略对目标表的这些约束。注意,您没法禁用 UNIQUE、PRIMARY KEY 或 NOT NULL 约束。
若是输入数据包含违反约束的行,则您可能但愿禁用 CHECK 和 FOREIGN KEY 约束。经过禁用 CHECK 和 FOREIGN KEY 约束,能够导入数据,而后使用 Transact-SQL 语句清除该数据。
不过,若是忽略了 CHECK 和 FOREIGN KEY 约束,在执行操做后,表上的每一个忽略的约束将在sys.check_constraints 或sys.foreign_keys 目录视图中标记为is_not_trusted。在某一时刻,应该检查全表约束。若是在大容量导入操做以前表不为空,则从新验证约束的开销可能超过对增量数据应用 CHECK 和 FOREIGN KEY 约束的开销。
IGNORE_TRIGGERS只适用于 INSERT 语句(当 BULK 选项与 OPENROWSET 一块儿使用时)。
指定大容量导入操做将忽略为表定义的全部触发器。 默认状况下,INSERT 将应用触发器。
仅当应用程序不依赖任何触发器,而且必须最大程度地提升性能时,才使用 IGNORE_TRIGGERS。
NOLOCK等同于 READUNCOMMITTED。 有关详细信息,请参阅本主题后面的 READUNCOMMITTED。
![]() |
---|
对于 UPDATE 或 DELETE 语句:后续版本的 Microsoft SQL Server 将删除该功能。请避免在新的开发工做中使用该功能,并着手修改当前还在使用该功能的应用程序。 |
指示数据库引擎在遇到表的锁时,当即返回一条消息。 NOWAIT 等同于将特定表的 SET LOCK_TIMEOUT 值指定为 0。
PAGLOCK在一般行或键采用单个锁的地方,或者一般采用单个表锁的地方,请采用页锁。 默认状况下,请使用与操做相对应的锁模式。 在从 SNAPSHOT 隔离级别操做的事务中指定时,除非将 PAGLOCK 与须要锁的其余表提示(例如,UPDLOCK 和 HOLDLOCK)组合,不然不会取得页锁。
READCOMMITTED指定读操做使用锁定或行版本控制来遵循有关 READ COMMITTED 隔离级别的规则。若是数据库选项 READ_COMMITTED_SNAPSHOT 为 OFF,数据库引擎将在读取数据时获取共享锁,在读操做完成后释放这些锁。若是数据库选项 READ_COMMITTED_SNAPSHOT 为 ON,则数据库引擎不获取锁,并使用行版本控制。有关隔离级别的详细信息,请参阅SET TRANSACTION ISOLATION LEVEL (Transact-SQL)。
![]() |
---|
对于 UPDATE 或 DELETE 语句:后续版本的 Microsoft SQL Server 将删除该功能。请避免在新的开发工做中使用该功能,并着手修改当前还在使用该功能的应用程序。 |
指定读操做使用锁定来遵循有关 READ COMMITTED 隔离级别的规则。不管 READ_COMMITTED_SNAPSHOT 数据库选项的设置如何,数据库引擎都将在读取数据时获取共享锁,在读操做完成后释放这些锁。有关隔离级别的详细信息,请参阅SET TRANSACTION ISOLATION LEVEL (Transact-SQL)。不能对 INSERT 语句的目标表指定此提示;将返回错误 4140。
READPAST指定数据库引擎不读取由其余事务锁定的行。 若是指定了 READPAST,将跳过行级锁。 也就是说,数据库引擎将跳过这些行,而不是阻塞当前事务直到锁被释放。例如,假设表T1 包含一个单精度整数列,其值为 一、二、三、4 和 5。若是事务 A 将值 3 更改成 8,但还没有提交,则 SELECT * FROM T1 (READPAST) 将生成值 一、二、4 和 5。使用 SQL Server 表实现工做队列时,READPAST 主要用于减小锁定争用。使用 READPAST 的队列读取器会跳过被其余事务锁定的队列项,跳至下一个可用的队列项,而不是等待其余事务释放锁。
可为 UPDATE 或 DELETE 语句中以及 FROM 子句中引用的任何表指定 READPAST。若是 READPAST 是在 UPDATE 语句中指定的,则仅当读取数据以标识要更新的记录时才应用 READPAST,而不考虑语句中指定 READPAST 的位置。不能为 INSERT 语句的 INTO 子句中的表指定 READPAST。 使用 READPAST 的读操做不会发生阻塞。读取外键或索引视图或者修改辅助索引时,使用 READPAST 的更新或删除操做可能发生阻塞。
仅可在运行于 READ COMMITTED 或 REPEATABLE READ 隔离级别的事务中指定 READPAST。在从 SNAPSHOT 隔离级别操做的事务中指定时,READPAST 必须与须要锁的其余表提示(例如,UPDLOCK 和 HOLDLOCK)组合。
当 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON 而且知足如下条件之一时,没法指定 READPAST 表提示。
会话的事务隔离级别为 READ COMMITTED。
查询中也指定了 READCOMMITTED 表提示。
若要在上述状况下指定 READPAST 提示,请删除 READCOMMITTED 表提示(若是存在),而后在查询中包括 READCOMMITTEDLOCK 表提示。
READUNCOMMITTED指定容许脏读。 不发布共享锁来阻止其余事务修改当前事务读取的数据,其余事务设置的排他锁不会阻碍当前事务读取锁定数据。 容许脏读可能产生较多的并发操做,但其代价是读取之后会被其余事务回滚的数据修改。 这可能会使您的事务出错,向用户显示从未提交过的数据,或者致使用户两次看到记录(或根本看不到记录)。
READUNCOMMITTED 和 NOLOCK 提示仅适用于数据锁。 全部查询(包括那些带有 READUNCOMMITTED 和 NOLOCK 提示的查询)都会在编译和执行过程当中获取 Sch-S(架构稳定性)锁。 所以,当并发事务持有表的 Sch-M(架构修改)锁时,将阻塞查询。 例如,数据定义语言 (DDL) 操做在修改表的架构信息以前获取 Sch-M 锁。全部并发查询(包括那些使用 READUNCOMMITTED 或 NOLOCK 提示运行的查询)都会在尝试获取 Sch-S 锁时被阻塞。相反,持有 Sch-S 锁的查询将阻塞尝试获取 Sch-M 锁的并发事务。
不能为经过插入、更新或删除操做修改过的表指定 READUNCOMMITTED 和 NOLOCK。SQL Server 查询优化器忽略 FROM 子句中应用于 UPDATE 或 DELETE 语句的目标表的 READUNCOMMITTED 和 NOLOCK 提示。
![]() |
---|
在 SQL Server 的将来版本中,将再也不支持在 FROM 子句中使用应用于 UPDATE 或 DELETE 语句目标表的 READUNCOMMITTED 和 NOLOCK 提示。请避免在新的开发工做上下文中使用这些提示,并计划修改当前使用它们的应用程序。 |
能够经过使用如下任意一种方法,在保护事务避免对未提交的数据修改进行脏读的同时最大程度地减小锁争用:
READ COMMITTED 隔离级别,其中 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON。
SNAPSHOT 隔离级别。
有关隔离级别的详细信息,请参阅 SET TRANSACTION ISOLATION LEVEL (Transact-SQL)。
![]() |
---|
若是在指定了 READUNCOMMITTED 的状况下收到 601 号错误消息,则按解决死锁错误 (1205) 的方法解决该错误,而后重试语句。 |
指定事务在 REPEATABLE READ 隔离级别运行时,使用相同的锁定语义执行一次扫描。有关隔离级别的详细信息,请参阅SET TRANSACTION ISOLATION LEVEL (Transact-SQL)。
ROWLOCK指定一般采用页锁或表锁时,采用行锁。 若是在 SNAPSHOT 隔离级别运行的事务中指定了行锁,除非将 ROWLOCK 与须要锁的其余表提示(例如,UPDLOCK 和 HOLDLOCK)组合使用,不然不会采用行锁。
SPATIAL_WINDOW_MAX_CELLS = integer指定在分割 geometry 或 geography 对象时使用的最大单元格数。number 是 1 到 8192 之间的值。
经过使用此选项,能够在主要和辅助筛选器执行时间之间权衡性能以微调查询执行时间。较大的数字将减小辅助筛选器执行时间,但会增长主要筛选器执行时间,而较小的数字恰相反。对于较密的空间数据,较大的数字经过为主要筛选器提供更好的近似值并减小辅助筛选器执行时间,从而缩短了执行时间。对于较稀疏的数据,较小的数字将减小主要筛选器执行时间。
此选项适用于手动和自动网格分割。
SERIALIZABLE等同于 HOLDLOCK。 经过将共享锁一直保持到事务完成,使共享锁具备更大的限制性;而不是在再也不须要所需的表或数据页时当即释放共享锁,而不管事务是否完成。 执行扫描时所用的语义与在 SERIALIZABLE 隔离级别运行的事务的语义相同。 有关隔离级别的详细信息,请参阅 SET TRANSACTION ISOLATION LEVEL (Transact-SQL)。
TABLOCK指定在表级别应用获取的锁。 获取的锁类型取决于正在执行的语句。 例如,SELECT 语句可能获取一个共享锁。经过指定 TABLOCK,将该共享锁应用到整个表而非在行或页级别应用。若是同时指定了 HOLDLOCK,则会一直持有表锁,直至事务结束。
在经过使用 INSERT INTO <target_table> SELECT <columns> FROM <source_table> 语句将数据导入某一堆时,可经过为目标表指定 TABLOCK 提示,实现语句的优化的日志记录和锁定。此外,数据库的恢复模式必须设置为简单或大容量日志模式。有关详细信息,请参阅INSERT (Transact-SQL)。
在与 OPENROWSET 大容量行集提供程序一块儿使用以将数据导入表的时候,TABLOCK 将启用多个客户端,以并发方式将数据加载到具备优化日志记录和锁定的目标表中。有关详细信息,请参阅在大容量导入中按最小方式记录日志的前提条件。
TABLOCKX指定对表采用排他锁。
UPDLOCK指定采用更新锁并保持到事务完成。 UPDLOCK 仅对行级别或页级别的读操做采用更新锁。 若是将 UPDLOCK 与 TABLOCK 组合使用或出于一些其余缘由采用表级锁,将采用排他 (X) 锁。
指定 UPDLOCK 时,忽略 READCOMMITTED 和 READCOMMITTEDLOCK 隔离级别提示。例如,若是将会话的隔离级别设置为 SERIALIZABLE 且查询指定 (UPDLOCK, READCOMMITTED),则忽略 READCOMMITTED 提示且使用 SERIALIZABLE 隔离级别运行事务。
XLOCK指定采用排他锁并保持到事务完成。 若是同时指定了 ROWLOCK, PAGLOCK 或 TABLOCK,则排他锁将应用于相应的粒度级别。
若是查询计划不访问表,则将忽略表提示。 这多是因为优化器选择了彻底不访问该表,也多是由于改为了访问索引视图。 在后一种状况中,使用 OPTION (EXPAND VIEWS) 查询提示可阻止访问索引视图。
全部锁提示将传播到查询计划访问的全部表和视图,其中包括在视图中引用的表和视图。另外,SQL Server 还将执行对应的锁一致性检查。
获取行级别锁的锁提示 ROWLOCK、UPDLOCK 和 XLOCK 可能对索引键而不是实际的数据行采用锁。例如,若是表具备非汇集索引,并且由涵盖索引处理使用锁提示的 SELECT 语句,则得到的锁针对的是涵盖索引中的索引键,而不是基表中的数据行。
若是表包含计算列,而该计算列是由访问其余表中的列的表达式或函数计算的,则不在这些表中使用表提示,而且不会传播这些提示。例如,在查询的表中指定 NOLOCK 表提示。此表包含的计算列是由访问另外一表中的列的表达式和函数组合计算的。表达式和函数引用的表在被访问时将不使用 NOLOCK 表提示。
对于 FROM 子句中的每一个表,SQL Server 不容许存在多个来自如下各个组的表提示:
粒度提示:PAGLOCK、NOLOCK、READCOMMITTEDLOCK、ROWLOCK、TABLOCK 或 TABLOCKX。
隔离级别提示:HOLDLOCK、NOLOCK、READCOMMITTED、REPEATABLEREAD 和 SERIALIZABLE。
筛选索引可用做表提示,但若是未涵盖查询选择的全部行,则会致使查询优化器产生错误 8622。下面是一个无效筛选索引提示的示例。该示例建立了筛选索引FIBillOfMaterialsWithComponentID,而后将其用做 SELECT 语句的索引提示。筛选索引谓词包含 ComponentID 为 53三、324 和 753 的数据行。查询谓词也包含 ComponentID 为 53三、324 和 753 的数据行,但它扩展告终果集,使之包含 ComponentID 为 855 和 924 的数据行,而筛选索引中则不包含这两行。所以,查询优化器没法使用此筛选索引提示,并产生错误 8622。有关详细信息,请参阅建立筛选索引。
USE AdventureWorks2012; GO IF EXISTS (SELECT name FROM sys.indexes WHERE name = N'FIBillOfMaterialsWithComponentID' AND object_id = OBJECT_ID(N'Production.BillOfMaterials')) DROP INDEX FIBillOfMaterialsWithComponentID ON Production.BillOfMaterials; GO CREATE NONCLUSTERED INDEX "FIBillOfMaterialsWithComponentID" ON Production.BillOfMaterials (ComponentID, StartDate, EndDate) WHERE ComponentID IN (533, 324, 753); GO SELECT StartDate, ComponentID FROM Production.BillOfMaterials WITH( INDEX (FIBillOfMaterialsWithComponentID) ) WHERE ComponentID in (533, 324, 753, 855, 924); GO
若是 SET 选项不包含筛选索引所需的值,查询优化器将不考虑使用索引提示。有关详细信息,请参阅CREATE INDEX (Transact-SQL)。
NOEXPAND 仅适用于索引视图。索引视图是包含为其建立的惟一汇集索引的视图。若是查询包含对同时存在于索引视图和基表中的列的引用,并且查询优化器肯定执行查询的最佳方法是使用索引视图,则查询优化器将对视图使用索引。此功能称为“索引视图匹配”。仅在特定版本的 SQL Server 中支持查询优化器自动使用索引视图。有关 SQL Server 的版本支持的功能的列表,请参阅SQL Server 2012 各个版本支持的功能 (http://go.microsoft.com/fwlink/?linkid=232473)。
可是,为了使优化器考虑使用索引视图进行匹配,或者使用经过 NOEXPAND 提示引用的索引视图,则必须将如下 SET 选项设置为 ON。
ANSI_NULLS |
ANSI_WARNINGS |
CONCAT_NULL_YIELDS_NULL |
ANSI_PADDING |
ARITHABORT1 |
QUOTED_IDENTIFIERS |
1 若是 ANSI_WARNINGS 设置为 ON,则 ARITHABORT 将隐式设置为 ON。所以,没必要手动调整此设置。
另外,必须将 NUMERIC_ROUNDABORT 选项设置为 OFF。
若要强制优化器对索引视图使用索引,请指定 NOEXPAND 选项。 仅当查询中也命名了此视图时才能使用此提示。 若是某个查询没有在 FROM 子句中直接命名特定索引视图,则 SQL Server 不提供用于在此查询中强制使用此视图的提示;可是,即便查询中未直接引用索引视图,查询优化器仍会考虑使用索引视图。
也可使用 OPTION (TABLE HINT) 子句将表提示指定为查询提示。咱们建议仅在计划指南的上下文中将表提示用做查询提示。对于即席查询,请将这些提示仅指定为表提示。有关详细信息,请参阅查询提示 (Transact-SQL)。