http://msdn.microsoft.com/zh-cn/library/ms187373.aspx
表提示在 DML 语句的 FROM 子句中指定,仅影响在该子句中引用的表或视图。
|
|
|---|
|
由于 SQL Server 查询优化器通常会为查询选择最佳执行计划,因此我们建议仅在最后迫不得已的情况下才可由资深的开发人员和数据库管理员使用提示。 |
适用范围:
Transact-SQL 语法约定
WITH ( <table_hint> [ [, ]...n ] )
<table_hint> ::=
[ NOEXPAND ] {
INDEX ( index_value [ ,...n ] ) | INDEX = ( index_value ) | FORCESEEK [( index_value ( index_column_name [ ,... ] ) ) ]
| FORCESCAN
| FORCESEEK
| HOLDLOCK
| NOLOCK
| NOWAIT
| PAGLOCK
| READCOMMITTED
| READCOMMITTEDLOCK
| READPAST
| READUNCOMMITTED
| REPEATABLEREAD
| ROWLOCK
| SERIALIZABLE
| SPATIAL_WINDOW_MAX_CELLS = integer
| TABLOCK
| TABLOCKX
| UPDLOCK
| XLOCK
}
<table_hint_limited> ::=
{
KEEPIDENTITY
| KEEPDEFAULTS
| HOLDLOCK
| IGNORE_CONSTRAINTS
| IGNORE_TRIGGERS
| NOLOCK
| NOWAIT
| PAGLOCK
| READCOMMITTED
| READCOMMITTEDLOCK
| READPAST
| REPEATABLEREAD
| ROWLOCK
| SERIALIZABLE
| TABLOCK
| TABLOCKX
| UPDLOCK
| XLOCK
}
指定表提示时必须使用括号。
|
|
|---|
|
不推荐省略 WITH 关键字:后续版本的 Microsoft SQL Server 将删除该功能。请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。 |
例如:
FROM t (TABLOCK)
如果指定的提示含其他选项,则指定的提示必须含 WITH 关键字:
FROM t WITH (TABLOCK, INDEX(myindex))
建议在表提示之间使用逗号。
|
|
|---|
|
不推荐用空格而不是逗号分隔提示:后续版本的 Microsoft SQL Server 将删除该功能。请不要在新的开发工作中使用该功能,并尽快修改当前还在使用该功能的应用程序。 |
在针对兼容级别为 90 及更高的数据库的查询中使用提示时,即存在这些限制。
有关详细信息,请参阅备注。
只能为每个表指定一个索引提示。
如果不存在聚集索引,则 INDEX(0) 强制执行表扫描,INDEX(1) 被解释为错误。
如果提示索引的集合并未包含查询引用的所有列,则会在 SQL Server 数据库引擎检索所有索引列后执行提取操作以检索其余列。
|
|
|---|
|
另外,不允许对包含指定索引提示的表执行索引 OR 操作。 |
表提示中的最大索引数为 250 个非聚集索引。
一起使用时)。
如果不指定 KEEPIDENTITY,则将验证但不导入此列的标识值。查询优化器将根据创建表时指定的种子值和增量值自动分配唯一值。
|
|
|---|
|
如果成功跳过了一个标识列,则查询优化器自动将标识列的唯一值分配到导入的表行中。 |
大容量导入数据时保留标识值 (SQL Server)
DBCC CHECKIDENT (Transact-SQL)。
一起使用时)。
指定数据记录在某一表列缺少值时插入此列的默认值(如果有),而不是插入 NULL。
在大容量导入期间保留 Null 或使用默认值 (SQL Server)。
在这种情况下,查询优化器仅考虑通过指定的索引(至少使用指定的索引列)执行索引查找操作。
可以通过以下方式指定 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 提示一起指定。
-
至少必须指定一个列且该列为第一个键列。
-
FORCESEEK (MyIndex (a, c)。
-
在提示中指定的列名顺序必须与引用的索引中列的顺序匹配。
-
不能指定自动包含在索引中的聚集键列,但是优化器可以使用这些列。
-
返回错误 366。
-
修改索引定义(例如通过添加或删除列)可能需要修改引用该索引的查询。
-
该提示阻止优化器考虑表的任何空间或 XML 索引。
-
该提示不能与 FORCESCAN 提示一起指定。
-
对于分区的索引,不能在 FORCESEEK 提示中指定 SQL Server 隐式添加的分区列。
|
|
|---|
|
在未来的版本中,对优化器进行内部修改后可允许考虑更多计划。 |
出现这样的情况时,授予该操作的内存量太小,查询性能将受影响。
可以带索引提示 INDEX(0) 指定 FORCESCAN,以强制对基表执行表扫描操作。
这意味着扫描仅适用于剩余分区而非整个表。
FORCESCAN 提示存在以下限制。
-
不能为作为 INSERT、UPDATE 或 DELETE 语句的目标的表指定该提示。
-
该提示不能与一个以上的索引提示一起使用。
-
该提示阻止优化器考虑表的任何空间或 XML 索引。
-
不能为远程数据源指定该提示。
-
该提示不能与 FORCESEEK 提示一起指定。
HOLDLOCK 不能被用于包含 FOR BROWSE 选项的 SELECT 语句。
一起使用时)。
注意,您无法禁用 UNIQUE、PRIMARY KEY 或 NOT NULL 约束。
通过禁用 CHECK 和 FOREIGN KEY 约束,可以导入数据,然后使用 Transact-SQL 语句清除该数据。
如果在大容量导入操作之前表不为空,则重新验证约束的开销可能超过对增量数据应用 CHECK 和 FOREIGN KEY 约束的开销。
一起使用时)。
默认情况下,INSERT 将应用触发器。
仅当应用程序不依赖任何触发器,并且必须最大程度地提高性能时,才使用 IGNORE_TRIGGERS。
有关详细信息,请参阅本主题后面的 READUNCOMMITTED。
|
|
|---|
|
对于 UPDATE 或 DELETE 语句:后续版本的 Microsoft SQL Server 将删除该功能。请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。 |
NOWAIT 等同于将特定表的 SET LOCK_TIMEOUT 值指定为 0。
在从 SNAPSHOT 隔离级别操作的事务中指定时,除非将 PAGLOCK 与需要锁的其他表提示(例如,UPDLOCK 和 HOLDLOCK)组合,否则不会取得页锁。
SET TRANSACTION ISOLATION LEVEL (Transact-SQL)。
|
|
|---|
|
对于 UPDATE 或 DELETE 语句:后续版本的 Microsoft SQL Server 将删除该功能。请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。 |
不能对 INSERT 语句的目标表指定此提示;将返回错误 4140。
使用 READPAST 的队列读取器会跳过被其他事务锁定的队列项,跳至下一个可用的队列项,而不是等待其他事务释放锁。
读取外键或索引视图或者修改辅助索引时,使用 READPAST 的更新或删除操作可能发生阻塞。
在从 SNAPSHOT 隔离级别操作的事务中指定时,READPAST 必须与需要锁的其他表提示(例如,UPDLOCK 和 HOLDLOCK)组合。
当 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON 并且满足以下条件之一时,无法指定 READPAST 表提示。
-
会话的事务隔离级别为 READ COMMITTED。
-
查询中也指定了 READCOMMITTED 表提示。
若要在上述情况下指定 READPAST 提示,请删除 READCOMMITTED 表提示(如果存在),然后在查询中包括 READCOMMITTEDLOCK 表提示。
这可能会使您的事务出错,向用户显示从未提交过的数据,或者导致用户两次看到记录(或根本看不到记录)。
相反,持有 Sch-S 锁的查询将阻塞尝试获取 Sch-M 锁的并发事务。
SQL Server 查询优化器忽略 FROM 子句中应用于 UPDATE 或 DELETE 语句的目标表的 READUNCOMMITTED 和 NOLOCK 提示。
|
|
|---|
|
请避免在新的开发工作上下文中使用这些提示,并计划修改当前使用它们的应用程序。 |
可以通过使用以下任意一种方法,在保护事务避免对未提交的数据修改进行脏读的同时最大程度地减少锁争用:
-
READ COMMITTED 隔离级别,其中 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON。
-
SNAPSHOT 隔离级别。
SET TRANSACTION ISOLATION LEVEL (Transact-SQL)。
|
|
|---|
|
如果在指定了 READUNCOMMITTED 的情况下收到 601 号错误消息,则按解决死锁错误 (1205) 的方法解决该错误,然后重试语句。 |
SET TRANSACTION ISOLATION LEVEL (Transact-SQL)。
如果在 SNAPSHOT 隔离级别运行的事务中指定了行锁,除非将 ROWLOCK 与需要锁的其他表提示(例如,UPDLOCK 和 HOLDLOCK)组合使用,否则不会采用行锁。
是 1 到 8192 之间的值。
对于较稀疏的数据,较小的数字将减少主要筛选器执行时间。
此选项适用于手动和自动网格分割。
SET TRANSACTION ISOLATION LEVEL (Transact-SQL)。
如果同时指定了 HOLDLOCK,则会一直持有表锁,直至事务结束。
INSERT (Transact-SQL)。
在大容量导入中按最小方式记录日志的前提条件。
指定对表采用排他锁。
如果将 UPDLOCK 与 TABLOCK 组合使用或出于一些其他原因采用表级锁,将采用排他 (X) 锁。
例如,如果将会话的隔离级别设置为 SERIALIZABLE 且查询指定 (UPDLOCK, READCOMMITTED),则忽略 READCOMMITTED 提示且使用 SERIALIZABLE 隔离级别运行事务。
如果同时指定了 ROWLOCK, PAGLOCK 或 TABLOCK,则排他锁将应用于相应的粒度级别。
在后一种情况中,使用 OPTION (EXPAND VIEWS) 查询提示可阻止访问索引视图。
另外,SQL Server 还将执行对应的锁一致性检查。
例如,如果表具有非聚集索引,而且由涵盖索引处理使用锁提示的 SELECT 语句,则获得的锁针对的是涵盖索引中的索引键,而不是基表中的数据行。
表达式和函数引用的表在被访问时将不使用 NOLOCK 表提示。
对于 FROM 子句中的每个表,SQL Server 不允许存在多个来自以下各个组的表提示:
-
粒度提示:PAGLOCK、NOLOCK、READCOMMITTEDLOCK、ROWLOCK、TABLOCK 或 TABLOCKX。
-
隔离级别提示:HOLDLOCK、NOLOCK、READCOMMITTED、REPEATABLEREAD 和 SERIALIZABLE。
筛选索引提示
创建筛选索引。
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
CREATE INDEX (Transact-SQL)。
使用 NOEXPAND
SQL Server 2012 各个版本支持的功能。
但是,为了使优化器考虑使用索引视图进行匹配,或者使用通过 NOEXPAND 提示引用的索引视图,则必须将以下 SET 选项设置为 ON。
|
ANSI_NULLS |
ANSI_WARNINGS |
CONCAT_NULL_YIELDS_NULL |
|
ANSI_PADDING |
1 |
QUOTED_IDENTIFIERS |
因此,不必手动调整此设置。
另外,必须将 NUMERIC_ROUNDABORT 选项设置为 OFF。
如果某个查询没有在 FROM 子句中直接命名特定索引视图,则 SQL Server 不提供用于在此查询中强制使用此视图的提示;但是,即使查询中未直接引用索引视图,查询优化器仍会考虑使用索引视图。
将表提示用作查询提示
查询提示 (Transact-SQL)。
A.使用 TABLOCK 提示指定锁定方法
表采用共享锁,并保持到 UPDATE 语句结束。
USE AdventureWorks2012; GO UPDATE Production.Product WITH (TABLOCK) SET ListPrice = ListPrice * 1.10 WHERE ProductNumber LIKE 'BK-%'; GO
B.使用 FORCESEEK 提示指定索引查找操作
表执行索引查找操作。
USE AdventureWorks2012;
GO
SELECT *
FROM Sales.SalesOrderHeader AS h
INNER JOIN Sales.SalesOrderDetail AS d WITH (FORCESEEK)
ON h.SalesOrderID = d.SalesOrderID
WHERE h.TotalDue > 100
AND (d.OrderQty > 5 OR d.LineTotal < 1000.00);
GO
以下示例使用指定索引的 FORCESEEK 提示强制查询优化器对指定的索引和索引列执行索引查找操作。
USE AdventureWorks2012; GO SELECT h.SalesOrderID, h.TotalDue, d.OrderQty FROM Sales.SalesOrderHeader AS h INNER JOIN Sales.SalesOrderDetail AS d WITH (FORCESEEK (PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID (SalesOrderID))) ON h.SalesOrderID = d.SalesOrderID WHERE h.TotalDue > 100 AND (d.OrderQty > 5 OR d.LineTotal < 1000.00); GO
C.使用 FORCESCAN 提示指定索引扫描操作
表执行扫描操作。
USE AdventureWorks2012;
GO
SELECT h.SalesOrderID, h.TotalDue, d.OrderQty
FROM Sales.SalesOrderHeader AS h
INNER JOIN Sales.SalesOrderDetail AS d
WITH (FORCESCAN)
ON h.SalesOrderID = d.SalesOrderID
WHERE h.TotalDue > 100
AND (d.OrderQty > 5 OR d.LineTotal < 1000.00);