SQL Server的查询优化器在select查询执行的时候产生一个高效的查询执行计划。如果优化器不能选择最优的计划,那么就需要检查查询计划、统计信息、支持的索引等,而通过使用提示可以改变优化器选择查询计划的工程,使优化器生成一个更好的执行计划。
1、联接提示
<join_hint> ::= { LOOP | HASH | MERGE | REMOTE }
LOOP | HASH | MERGE
指定查询中的联接应使用循环、哈希或合并。 使用 LOOP |HASH | MERGE JOIN 在两个表之间强制执行特定联接。 不能同时将 LOOP 与 RIGHT(或 FULL)指定为联接类型。
REMOTE
指定联接操作在右表处执行。 这在左表是本地表而右表是远程表的情况下很有用。 只在左表的行数少于右表行数时才能使用 REMOTE。
如果右表为本地表,则联接在本地执行。 如果两个表均为远程表但来自不同的数据源,则 REMOTE 将使联接在右表处执行。 如果两个表均为远程表且来自相同数据源,则不需要使用 REMOTE。
如果使用 COLLATE 子句将联接谓词中比较的值中的一个值转换成了不同的排序规则,则不能使用 REMOTE。REMOTE 只可用于 INNER JOIN 操作。
- --没有提示的查询
- 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
-
--没有提示的查询
-
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
2、查询提示与表提示
<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
查询提示的参数
指定在查询的 GROUP BY 或 DISTINCT 子句中所说明的聚合应使用哈希或排列。
{ MERGE | HASH | CONCAT } UNION
指定所有 UNION 运算由合并、哈希或串联 UNION 集执行。 如果指定了多个 UNION 提示,查询优化器就会从这些指定的提示中选择开销最少的策略。
{ LOOP | MERGE | HASH } JOIN
指定整个查询中的所有联接操作由 LOOP JOIN、MERGE JOIN 或 HASH JOIN 执行。如果指定了多个联接提示,则优化器从允许的联接策略中选择开销最少的联接策略。
如果在同一查询中的 FROM 子句中还为一对特定的表指定了联接提示,则尽管仍须遵守查询提示,但该联接提示将优先联接这两个表。因此,这对表的联接提示可能只限制选择查询提示中允许的联接方法。有关详细信息,请参阅联接提示 (Transact-SQL)。
EXPAND VIEWS
指定展开索引视图,而且查询优化器不将任何索引视图看作是查询中任何部分的替代。当视图名称由查询文本中的视图定义替换时,视图将展开。
实际上,该查询提示不允许在查询计划中直接使用索引视图和直接在索引视图上使用索引。
只有在查询的 SELECT 部分中直接引用视图,而且指定了 WITH (NOEXPAND) 或 WITH (NOEXPAND, INDEX(index_value [,...n ] ) ) 时,才不展开索引视图。有关查询提示 WITH (NOEXPAND) 的详细信息,请参阅FROM。
只有语句的 SELECT 部分中的视图(包括 INSERT、UPDATE、MERGE 和 DELETE 语句中的视图)才受提示影响。
FAST <span class="parameter">number_rows</span>
指定对查询进行优化,以便快速检索第一个 number_rows.。该值是非负整数。在返回第一个number_rows 后,查询继续执行并生成完整的结果集。
FORCE ORDER
指定在查询优化过程中保持由查询语法指示的联接顺序。 使用 FORCE ORDER 不会影响查询优化器可能的角色逆转行为。
![]() |
---|
在 MERGE 语句中,如果未指定 WHEN SOURCE NOT MATCHED 子句,则按照默认的联接次序,先访问源表再访问目标表。如果指定 FORCE ORDER,则保留此默认行为。 |
KEEP PLAN
强制查询优化器对查询放宽估计的重新编译阈值。 当通过运行 UPDATE、DELETE、MERGE 或 INSERT 语句对表进行的索引列更改数目达到估计数目时,会自动重新编译查询,该估计数目即为估计的重新编译阈值。指定 KEEP PLAN 可确保当表有多个更新时不会频繁地对查询进行重新编译。
KEEPFIXED PLAN
强制查询优化器不因统计信息的更改而重新编译查询。 指定 KEEPFIXED PLAN 可确保仅当更改基础表的架构或在那些表上执行 sp_recompile 时才重新编译查询。
IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX
可防止查询使用非聚集的 xVelocity 内存优化的列存储索引。 如果查询包含避免使用 columnstore 索引的查询提示以及有关使用 columnstore 索引的索引提示,则这些提示将发生冲突,查询将返回错误。
MAXDOP <span class="parameter">number</span>
对于指定了 max degree of parallelism 配置选项的查询,会覆盖sp_configure 和资源调控器的该选项。MAXDOP 查询提示可以超出使用 sp_configure 配置的值。如果 MAXDOP 超出使用资源调控器配置的值,则数据库引擎会使用资源调控器 MAXDOP 值(如ALTER WORKLOAD GROUP (Transact-SQL) 中所述)。当使用 MAXDOP 查询提示时,所有和max degree of parallelism 配置选项一起使用的语义规则均适用。有关详细信息,请参阅配置 max degree of parallelism 服务器配置选项。
![]() |
---|
如果 MAXDOP 设置为零,服务器将选择最大并行度。 |
MAXRECURSION <span class="parameter">number</span>
指定该查询允许的最大递归数。 number 是介于 0 至 32767 之间的非负整数。 如果指定 0,则没有限制。 如果未指定此选项,则对服务器的默认限制为 100。
当在查询执行期间达到指定或默认的 MAXRECURSION 数量限制时,将结束查询并返回错误。
由于此错误,该语句的所有结果都被回滚。 如果该语句为 SELECT 语句,则可能会返回部分结果或不返回结果。 所返回的任何部分结果都可能无法包括超过指定最大递归级别的递归级别上的所有行。
有关详细信息,请参阅 WITH common_table_expression (Transact-SQL)。
OPTIMIZE FOR ( <span class="parameter">@variable_name</span> { UNKNOWN | =<span class="parameter">literal_constant }</span> [<strong>,</strong> ...<span class="parameter">n</span>] )
在编译和优化查询时指示查询优化器对局部变量使用特定值。 仅在查询优化期间使用该值,在查询执行期间不使用该值。
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
-
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
表提示的参数
存在一些例外情况:只有在使用 WITH 关键字指定表提示时,才支持在 FROM 子句中使用这些提示。指定表提示时必须使用括号。
![]() |
---|
不推荐省略 WITH 关键字:后续版本的 Microsoft SQL Server 将删除该功能。请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。 |
使用或不使用 WITH 关键字均可使用的表提示如下:NOLOCK, READUNCOMMITTED、UPDLOCK、REPEATABLEREAD、SERIALIZABLE、READCOMMITTED、TABLOCK、TABLOCKX、PAGLOCK、ROWLOCK、NOWAIT、READPAST、XLOCK 和 NOEXPAND。如果指定的表提示不含 WITH 关键字,则必须单独指定该提示。 例如:
FROM t (TABLOCK)
如果指定的提示含其他选项,则指定的提示必须含 WITH 关键字:
FROM t WITH (TABLOCK, INDEX(myindex))
建议在表提示之间使用逗号。
![]() |
---|
不推荐用空格而不是逗号分隔提示:后续版本的 Microsoft SQL Server 将删除该功能。请不要在新的开发工作中使用该功能,并尽快修改当前还在使用该功能的应用程序。 |
在针对兼容级别为 90 及更高的数据库的查询中使用提示时,即存在这些限制。
NOEXPAND
指定查询优化器处理查询时,不扩展任何索引视图来访问基础表。 查询优化器将视图当成包含聚集索引的表处理。 NOEXPAND 仅适用于索引视图。有关详细信息,请参阅备注。
INDEX <strong>(</strong><span class="parameter">index_value</span> [<strong>,</strong>...<span class="parameter"> n</span>] ) | INDEX = (<span class="parameter">index_value</span><strong>)</strong>
INDEX() 语法指定供查询优化器在处理该语句时使用的一个或多个索引的名称或 ID。另一供选择的 INDEX = 语法指定单个索引值。只能为每个表指定一个索引提示。
如果存在聚集索引,则 INDEX(0) 强制执行聚集索引扫描,INDEX(1) 强制执行聚集索引扫描或查找。如果不存在聚集索引,则 INDEX(0) 强制执行表扫描,INDEX(1) 被解释为错误。
如果在单个提示列表中使用了多个索引,则会忽略重复项,其余列出的索引将用于检索表中的行。索引提示中的索引顺序很重要。多索引提示还强制执行索引 AND 运算,查询优化器将对所访问的每个索引应用尽可能多的条件。如果提示索引的集合并未包含查询引用的所有列,则会在 SQL Server 数据库引擎检索所有索引列后执行提取操作以检索其余列。
![]() |
---|
如果将引用多个索引的索引提示用于星型联接中的事实数据表,则优化器将忽略索引提示,并返回一个警告消息。另外,不允许对包含指定索引提示的表执行索引 OR 操作。 |
表提示中的最大索引数为 250 个非聚集索引。
KEEPIDENTITY
只适用于 INSERT 语句(当 BULK 选项与 OPENROWSET 一起使用时)。
指定导入数据文件中的标识值用于标识列。 如果不指定 KEEPIDENTITY,则将验证但不导入此列的标识值。查询优化器将根据创建表时指定的种子值和增量值自动分配唯一值。
![]() |
---|
如果数据文件不包含表或视图中的标识列的值,并且标识列不是表中的最后一列,则必须跳过标识列。有关详细信息,请参阅使用格式化文件跳过数据字段 (SQL Server)。如果成功跳过了一个标识列,则查询优化器自动将标识列的唯一值分配到导入的表行中。 |
有关在 INSERT ... SELECT * FROM OPENROWSET(BULK...) 语句中使用此提示的示例,请参阅大容量导入数据时保留标识值 (SQL Server)。
有关检查表的标识值的信息,请参阅 DBCC CHECKIDENT (Transact-SQL)。
KEEPDEFAULTS
只适用于 INSERT 语句(当 BULK 选项与 OPENROWSET 一起使用时)。
指定数据记录在某一表列缺少值时插入此列的默认值(如果有),而不是插入 NULL。
有关在 INSERT ... SELECT * FROM OPENROWSET(BULK...) 语句中使用此提示的示例,请参阅在大容量导入期间保留空值或使用默认值 (SQL Server)。
FORCESEEK [ <strong>(</strong><span class="parameter">index_value</span><strong>(</strong><span class="parameter">index_column_name</span> [<strong>,</strong>...<span class="parameter">n</span> ]<strong>))</strong> ]
指定查询优化器仅使用索引查找操作作为表或视图中的数据的访问途径。 从 SQL Server 2008 R2 SP1 开始,还可以指定索引参数。 在这种情况下,查询优化器仅考虑通过指定的索引(至少使用指定的索引列)执行索引查找操作。
可以通过以下方式指定 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 时的计划数。这可能导致在更多情况下出现“无法生成计划”错误。在未来的版本中,对优化器进行内部修改后可允许考虑更多计划。 |
FORCESCAN
此提示在 SQL Server 2008 R2 SP1 中引入,它指定查询优化器仅将索引扫描操作作为引用的表或视图的访问路径。对于优化器低估受影响的行数并选择一个查找操作而非扫描操作的查询,FORCESCAN 提示很有用。出现这样的情况时,授予该操作的内存量太小,查询性能将受影响。
指定 FORCESCAN 时有无 INDEX 提示均可。 与索引提示组合使用 (INDEX = index_name, FORCESCAN) 时,查询优化器在访问引用的表时仅考虑通过指定的索引扫描访问路径。可以带索引提示 INDEX(0) 指定 FORCESCAN,以强制对基表执行表扫描操作。
对于分区的表和索引,在通过查询谓词评估消除分区后应用 FORCESCAN。这意味着扫描仅适用于剩余分区而非整个表。
FORCESCAN 提示存在以下限制。
-
不能为作为 INSERT、UPDATE 或 DELETE 语句的目标的表指定该提示。
-
该提示不能与一个以上的索引提示一起使用。
-
该提示阻止优化器考虑表的任何空间或 XML 索引。
-
不能为远程数据源指定该提示。
-
该提示不能与 FORCESEEK 提示一起指定。
HOLDLOCK
等同于 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
指示数据库引擎在遇到表的锁时,立即返回一条消息。 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 将删除该功能。请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。 |
READCOMMITTEDLOCK
指定读操作使用锁定来遵循有关 READ COMMITTED 隔离级别的规则。无论 READ_COMMITTED_SNAPSHOT 数据库选项的设置如何,数据库引擎都将在读取数据时获取共享锁,在读操作完成后释放这些锁。有关隔离级别的详细信息,请参阅SET TRANSACTION ISOLATION LEVEL (Transact-SQL)。不能对 INSERT 语句的目标表指定此提示;将返回错误 4140。
READPAST
指定数据库引擎不读取由其他事务锁定的行。 如果指定了 READPAST,将跳过行级锁。 也就是说,数据库引擎将跳过这些行,而不是阻塞当前事务直到锁被释放。例如,假设表T1 包含一个单精度整数列,其值为 1、2、3、4 和 5。如果事务 A 将值 3 更改为 8,但尚未提交,则 SELECT * FROM T1 (READPAST) 将生成值 1、2、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) 的方法解决该错误,然后重试语句。 |
REPEATABLEREAD
指定事务在 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 为 533、324 和 753 的数据行。查询谓词也包含 ComponentID 为 533、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
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)。
- --1.index
- SELECT *
- FROM sales.SalesOrderHeader o with(index(PK_SalesOrderHeader_SalesOrderID))
- INNER JOIN sales.SalesOrderDetail m with(index(0)) --聚集索引扫描
- ON O.salesorderid = m.salesorderid
- inner join production.Product e with (index(1)) --聚集索引扫描或查找
- on m.ProductID = e.ProductID
- --2.KEEPIDENTITY
- --建表
- create table dbo.y(year varchar(4) primary key)
- insert into dbo.y
- values('2010'),
- ('2011')
- CREATE TABLE dbo.CALENDAR
- (
- ID NUMERIC (10) identity(1,1) NOT NULL,
- YEAR VARCHAR (4) NULL references foreign key y(year),
- QUARTER VARCHAR (1) NULL default datename(quarter,getdate()),
- MONTH VARCHAR (2) NULL,
- WEEK VARCHAR (2) NULL,
- WEEK_MONTH VARCHAR (2) NULL,
- WORK_DAY BIT NULL,
- IS_HOLIDAY BIT NULL,
- CONSTRAINT PK_CALENDAR PRIMARY KEY (ID)
- )
- insert into dbo.calendar with(keepidentity)
- (ID,
- YEAR,
- QUARTER,
- MONTH,
- WEEK,
- WEEK_MONTH,
- WORK_DAY,
- IS_HOLIDAY
- )
- select *
- from
- openrowset(bulk 'c:\calendar.txt', --要读取的文件路径和名称
- formatfile='c:\calendar.fmt', --格式化文件的路径和名称
- firstrow = 1, --要载入的第一行
- --lastrow = 1000, --要载入的最后一行,此值必须大于firstrow
- maxerrors = 10, --在加载失败之前加载操作中最大的错误数
- errorfile ='c:\calendar_error.txt', --存放错误的文件
- rows_per_batch = 100 --每个批处理导入的行数
- ) as calendar
- --3.KEEPDEFAULTS
- insert into dbo.MDM_CALENDAR with(keepdefaults)
- ( ID ,
- YEAR ,
- CAL_QUARTER ,
- CAL_MONTH ,
- CAL_WEEK ,
- CAL_WEEK_OF_MONTH ,
- CAL_DAY ,
- CAL_DATE ,
- HOLIDAY
- )
- select *
- from
- openrowset(bulk 'c:\calendar.txt', --要读取的文件路径和名称
- formatfile='c:\calendar.fmt', --格式化文件的路径和名称
- firstrow = 1, --要载入的第一行
- --lastrow = 1000, --要载入的最后一行,此值必须大于firstrow
- maxerrors = 10, --在加载失败之前加载操作中最大的错误数
- errorfile ='c:\calendar_error.txt', --存放错误的文件
- rows_per_batch = 100 --每个批处理导入的行数
- ) as calendar
- --4.IGNORE_CONSTRAINTS
- --无法禁用:UNIQUE、PRIMARY KEY 或 NOT NULL约束
- --可以禁用:CHECK 和 FOREIGN KEY 约束
- insert into dbo.CALENDAR with(ignore_constraints)
- ( ID,
- YEAR,
- QUARTER,
- MONTH,
- WEEK,
- WEEK_MONTH,
- WORK_DAY,
- IS_HOLIDAY
- )
- select *
- from
- openrowset(bulk 'c:\calendar.txt', --要读取的文件路径和名称
- formatfile='c:\calendar.fmt', --格式化文件的路径和名称
- firstrow = 1, --要载入的第一行
- --lastrow = 1000, --要载入的最后一行,此值必须大于firstrow
- maxerrors = 10, --在加载失败之前加载操作中最大的错误数
- errorfile ='c:\calendar_error.txt', --存放错误的文件
- rows_per_batch = 100 --每个批处理导入的行数
- ) as calendar
- --5.IGNORE_TRIGGERS
- --建立触发器
- create trigger dbo.calendar_trigger
- on dbo.calendar
- after insert
- as
- begin
- select * from inserted
- end
- go
- insert into dbo.CALENDAR with(ignore_triggers,ignore_constraints)
- (ID,
- YEAR,
- QUARTER,
- MONTH,
- WEEK,
- WEEK_MONTH,
- WORK_DAY,
- IS_HOLIDAY
- )
- select *
- from
- openrowset(bulk 'c:\calendar.txt', --要读取的文件路径和名称
- formatfile='c:\calendar.fmt', --格式化文件的路径和名称
- firstrow = 1, --要载入的第一行
- --lastrow = 1000, --要载入的最后一行,此值必须大于firstrow
- maxerrors = 10, --在加载失败之前加载操作中最大的错误数
- errorfile ='c:\calendar_error.txt', --存放错误的文件
- rows_per_batch = 100 --每个批处理导入的行数
- ) as calendar
- --6.forceseek
- SELECT *
- FROM sales.SalesOrderHeader o with(forceseek)
- INNER JOIN sales.SalesOrderDetail m with(forceseek,
- index(IX_SalesOrderDetail_ProductID))
- ON O.salesorderid = m.salesorderid
- inner join production.Product e
- --with(FORCESEEK (PK_Product_ProductID (col1, col2, col3))) 这样用法在SQL Server2012的
- on m.ProductID = e.ProductID
- --7.forcescan:在SQL Server2012中引入的,在SQL Server2008不可用
- SELECT *
- FROM sales.SalesOrderHeader o with(FORCESCAN)
- INNER JOIN sales.SalesOrderDetail m with(forcescan,
- index(IX_SalesOrderDetail_ProductID))
- ON O.salesorderid = m.salesorderid
- inner join production.Product e
- with(forcescan (PK_Product_ProductID (col1, col2, col3)))
- on m.ProductID = e.ProductID
- /*=============================================
- 8.锁定提示
- 锁粒度:
- ROWLOCK
- PAGLOCK
- TABLOCK(在堆上的delete语句中加上tablock后,在行被删除时回收分页)
- 锁模式:
- READPAST:不读取被锁定的记录
- NOWAIT(SET LOCK_TIMEOUT 0):锁等待时间为0,也就是如果需要的数据被锁定,那么返回错误
- UPDLOCK:更新锁
- XLOCK:独占锁
- TABLOCKX = TABLOCK + XLOCK
- 隔离级别:
- READUNCOMMITTED/NOLOCK
- READCOMMITTED
- READCOMMITTEDLOCK:无论数据库是否设置了快照选项,读取时都会获取共享锁
- REPEATABLEREAD
- SERIALIZABLE/HOLDLOCK
- ===============================================*/
- begin tran
- SELECT *
- FROM Production.Product WITH(holdlock)
- select *
- from sys.dm_tran_locks
- where request_session_id = @@SPID
- commit tran
-
--1.index
-
SELECT
*
-
FROM sales.SalesOrderHeader o
with(index(PK_SalesOrderHeader_SalesOrderID))
-
INNER
JOIN sales.SalesOrderDetail m
with(index(
0))
--聚集索引扫描
-
ON O.salesorderid
= m.salesorderid
-
inner
join production.Product e
with (index(
1))
--聚集索引扫描或查找
-
on m.ProductID
= e.ProductID
-
-
-
-
--2.KEEPIDENTITY
-