【1】官网参考
(1)查询提示 option
(maxdop)
https://docs.microsoft.com/zh-cn/sql/t-sql/queries/hints-transact-sql-query?view=sql-server-ver15
(2)查询中的表提示
https://docs.microsoft.com/zh-cn/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver15
(3)连接提示
https://docs.microsoft.com/zh-cn/sql/t-sql/queries/hints-transact-sql-join?view=sql-server-ver15
(4)具体一般形式与内容
<query_hint> ::= { { HASH | ORDER } GROUP | { CONCAT | HASH | MERGE } UNION | { LOOP | MERGE | HASH } JOIN | EXPAND VIEWS | FAST <integer_value> | FORCE ORDER | { FORCE | DISABLE } EXTERNALPUSHDOWN | { FORCE | DISABLE } SCALEOUTEXECUTION | IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX | KEEP PLAN | KEEPFIXED PLAN | MAX_GRANT_PERCENT = <numeric_value> | MIN_GRANT_PERCENT = <numeric_value> | MAXDOP <integer_value> | MAXRECURSION <integer_value> | NO_PERFORMANCE_SPOOL | OPTIMIZE FOR ( @variable_name { UNKNOWN | = <literal_constant> } [ , ...n ] ) | OPTIMIZE FOR UNKNOWN | PARAMETERIZATION { SIMPLE | FORCED } | QUERYTRACEON <integer_value> | RECOMPILE | ROBUST PLAN | USE HINT ( <use_hint_name> [ , ...n ] ) | USE PLAN N'<xml_plan>' | TABLE HINT ( <exposed_object_name> [ , <table_hint> [ [, ]...n ] ] ) } <table_hint> ::= { NOEXPAND [ , INDEX ( <index_value> [ ,...n ] ) | INDEX = ( <index_value> ) ] | 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 | SNAPSHOT | SPATIAL_WINDOW_MAX_CELLS = <integer_value> | TABLOCK | TABLOCKX | UPDLOCK | XLOCK } <use_hint_name> ::= { 'ASSUME_JOIN_PREDICATE_DEPENDS_ON_FILTERS' | 'ASSUME_MIN_SELECTIVITY_FOR_FILTER_ESTIMATES' | 'DISABLE_BATCH_MODE_ADAPTIVE_JOINS' | 'DISABLE_BATCH_MODE_MEMORY_GRANT_FEEDBACK' | 'DISABLE_DEFERRED_COMPILATION_TV' | 'DISABLE_INTERLEAVED_EXECUTION_TVF' | 'DISABLE_OPTIMIZED_NESTED_LOOP' | 'DISABLE_OPTIMIZER_ROWGOAL' | 'DISABLE_PARAMETER_SNIFFING' | 'DISABLE_ROW_MODE_MEMORY_GRANT_FEEDBACK' | 'DISABLE_TSQL_SCALAR_UDF_INLINING' | 'DISALLOW_BATCH_MODE' | 'ENABLE_HIST_AMENDMENT_FOR_ASC_KEYS' | 'ENABLE_QUERY_OPTIMIZER_HOTFIXES' | 'FORCE_DEFAULT_CARDINALITY_ESTIMATION' | 'FORCE_LEGACY_CARDINALITY_ESTIMATION' | 'QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_n' | 'QUERY_PLAN_PROFILE' }
【2】查询提示=》案例
转自官网
A. 使用 MERGE JOIN
下面的示例指定,MERGE JOIN 在查询中运行 JOIN 操作。 该示例使用 AdventureWorks2012 数据库。
SELECT *
FROM Sales.Customer AS c
INNER JOIN Sales.CustomerAddress AS ca ON c.CustomerID = ca.CustomerID
WHERE TerritoryID = 5
OPTION (MERGE JOIN);
GO
B. 使用 OPTIMIZE FOR
以下示例指示查询优化器在优化查询时对 @city_name
使用值 'Seattle'
,并对 @postal_code
的所有列值使用谓词的平均选择性。 该示例使用 AdventureWorks2012 数据库。
CREATE PROCEDURE dbo.RetrievePersonAddress
@city_name NVARCHAR(30),
@postal_code NVARCHAR(15)
AS
SELECT * FROM Person.Address
WHERE City = @city_name AND PostalCode = @postal_code
OPTION ( OPTIMIZE FOR (@city_name = 'Seattle', @postal_code UNKNOWN) );
GO
C. 使用 MAXRECURSION
可以使用 MAXRECURSION 来防止不合理的递归公用表表达式进入无限循环。 下面的示例特意创建了一个无限循环,然后使用 MAXRECURSION 提示将递归级别限制为两级。 该示例使用 AdventureWorks2012 数据库。
--Creates an infinite loop
WITH cte (CustomerID, PersonID, StoreID) AS
(
SELECT CustomerID, PersonID, StoreID
FROM Sales.Customer
WHERE PersonID IS NOT NULL
UNION ALL
SELECT cte.CustomerID, cte.PersonID, cte.StoreID
FROM cte
JOIN Sales.Customer AS e
ON cte.PersonID = e.CustomerID
)
--Uses MAXRECURSION to limit the recursive levels to 2
SELECT CustomerID, PersonID, StoreID
FROM cte
OPTION (MAXRECURSION 2);
GO
在更正代码错误之后,就不再需要 MAXRECURSION。
D. 使用 MERGE UNION
以下示例使用 MERGE UNION 查询提示。 该示例使用 AdventureWorks2012 数据库。
SELECT *
FROM HumanResources.Employee AS e1
UNION
SELECT *
FROM HumanResources.Employee AS e2
OPTION (MERGE UNION);
GO
E. 使用 HASH GROUP 和 FAST
以下示例使用 HASH GROUP 和 FAST 查询提示。 该示例使用 AdventureWorks2012 数据库。
SELECT ProductID, OrderQty, SUM(LineTotal) AS Total
FROM Sales.SalesOrderDetail
WHERE UnitPrice < $5.00
GROUP BY ProductID, OrderQty
ORDER BY ProductID, OrderQty
OPTION (HASH GROUP, FAST 10);
GO
F. 使用 MAXDOP
以下示例使用 MAXDOP 查询提示。 该示例使用 AdventureWorks2012 数据库。
SELECT ProductID, OrderQty, SUM(LineTotal) AS Total
FROM Sales.SalesOrderDetail
WHERE UnitPrice < $5.00
GROUP BY ProductID, OrderQty
ORDER BY ProductID, OrderQty
OPTION (MAXDOP 2);
GO
G. 使用 INDEX
以下示例使用 INDEX 提示。 第一个示例指定了一个索引。 第二个示例为单个表引用指定多个索引。 在这两个示例中,由于对使用别名的表应用了 INDEX 提示,因此 TABLE HINT 子句还必须将相同的别名指定为公开的对象名称。 该示例使用 AdventureWorks2012 数据库。
EXEC sp_create_plan_guide
@name = N'Guide1',
@stmt = N'SELECT c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 2;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT(e, INDEX (IX_Employee_ManagerID)))';
GO
EXEC sp_create_plan_guide
@name = N'Guide2',
@stmt = N'SELECT c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 2;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT(e, INDEX(PK_Employee_EmployeeID, IX_Employee_ManagerID)))';
GO
H. 使用 FORCESEEK
下面的示例使用 FORCESEEK 表提示。 TABLE HINT 子句还必须指定与公开的对象名称相同的名称(包含两部分)。 将 INDEX 提示应用于名称包含两部分的表时指定名称。 该示例使用 AdventureWorks2012 数据库。
EXEC sp_create_plan_guide
@name = N'Guide3',
@stmt = N'SELECT c.LastName, c.FirstName, HumanResources.Employee.Title
FROM HumanResources.Employee
JOIN Person.Contact AS c ON HumanResources.Employee.ContactID = c.ContactID
WHERE HumanResources.Employee.ManagerID = 3
ORDER BY c.LastName, c.FirstName;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT( HumanResources.Employee, FORCESEEK))';
GO
I. 使用多个表提示
下面的示例将 INDEX 提示应用到一个表,将 FORCESEEK 提示应用到另一个表。 该示例使用 AdventureWorks2012 数据库。
EXEC sp_create_plan_guide
@name = N'Guide4',
@stmt = N'SELECT e.ManagerID, c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 3;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT (e, INDEX( IX_Employee_ManagerID))
, TABLE HINT (c, FORCESEEK))';
GO
J. 使用 TABLE HINT 覆盖现有的表提示
下面的示例展示了如何使用 TABLE HINT 提示。 使用提示时,可以不指定提示替代在查询的 FROM 子句中指定的 INDEX 表提示行为。 该示例使用 AdventureWorks2012 数据库。
EXEC sp_create_plan_guide
@name = N'Guide5',
@stmt = N'SELECT e.ManagerID, c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e WITH (INDEX (IX_Employee_ManagerID))
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 3;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT(e))';
GO
K. 指定语义影响的表提示
以下示例在查询中包含了NOLOCK 和 INDEX 这两个表提示,其中前者会影响语义,后者不影响语义。 若要保留查询的语义,应在计划指南的 OPTIONS 子句中指定 NOLOCK 提示。 与 NOLOCK 提示一起,在语句编译和优化期间指定 INDEX 和 FORCESEEK 提示,并替换查询中不影响语义的 INDEX 提示。 该示例使用 AdventureWorks2012 数据库。
EXEC sp_create_plan_guide
@name = N'Guide6',
@stmt = N'SELECT c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e
WITH (NOLOCK, INDEX (PK_Employee_EmployeeID))
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 3;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT (e, INDEX(IX_Employee_ManagerID), NOLOCK, FORCESEEK))';
GO
下面的示例演示另一种保留查询语义并使优化器能够选择并非在表提示中指定的索引的方法。 允许优化器通过在 OPTIONS 子句中指定 NOLOCK 提示来进行选择。 指定提示是因为它会影响语义。 然后,指定只有表引用而无 INDEX 提示的 TABLE HINT 关键字。 该示例使用 AdventureWorks2012 数据库。
EXEC sp_create_plan_guide
@name = N'Guide7',
@stmt = N'SELECT c.LastName, c.FirstName, e.Title
FROM HumanResources.Employee AS e
WITH (NOLOCK, INDEX (PK_Employee_EmployeeID))
JOIN Person.Contact AS c ON e.ContactID = c.ContactID
WHERE e.ManagerID = 2;',
@type = N'SQL',
@module_or_batch = NULL,
@params = NULL,
@hints = N'OPTION (TABLE HINT (e, NOLOCK))';
GO
L. 使用 USE HINT
以下示例使用 RECOMPILE 和 USE HINT 查询提示。 该示例使用 AdventureWorks2012 数据库。
SELECT * FROM Person.Address
WHERE City = 'SEATTLE' AND PostalCode = 98104
OPTION (RECOMPILE, USE HINT ('ASSUME_MIN_SELECTIVITY_FOR_FILTER_ESTIMATES', 'DISABLE_PARAMETER_SNIFFING'));
GO
M. 使用 QUERYTRACEON HINT
以下示例使用 QUERYTRACEON 查询提示。 该示例使用 AdventureWorks2012 数据库。 可以使用以下查询,为特定查询启用跟踪标志 4199 控制的所有影响计划的修补程序:
SELECT * FROM Person.Address
WHERE City = 'SEATTLE' AND PostalCode = 98104
OPTION (QUERYTRACEON 4199);
还可以使用多个跟踪标志,如以下查询中所示:
SELECT * FROM Person.Address WHERE City = 'SEATTLE' AND PostalCode = 98104 OPTION (QUERYTRACEON 4199, QUERYTRACEON 4137);
【3】表提示 =》案例
(1)使用锁
FROM t (TABLOCK)
如果指定的提示含其他选项,则指定的提示必须含 WITH 关键字:
(2)index索引,锁 同时用
FROM t WITH (TABLOCK, INDEX(myindex))