SQL Server 2012
 
 
 
 
為這個主題評分
 

資料表提示會在 DML 陳述式的 FROM 子句中指定,並只會影響該子句中參考的資料表或檢視表。

注意

由於 SQL Server 查詢最佳化工具通常會選取最好的查詢執行計畫,因此,我們建議資深的開發人員和資料庫管理員只將提示當做最後的解決辦法。

適用於:

DELETE

INSERT

SELECT

UPDATE

MERGE

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 ( <table_hint> ) [ [, ]...n]

資料表提示也必須用括號來指定。

重要事項

省略 WITH 關鍵字是一項已被取代的功能:未來的 Microsoft SQL Server 版本將移除這項功能。請避免在新的開發工作中使用這項功能,並規劃修改目前使用這項功能的應用程式。

例如:

 
複製
FROM t (TABLOCK)

如果要使用另一個選項指定提示,您必須利用 WITH 關鍵字來指定提示:

 
複製
FROM t WITH (TABLOCK, INDEX(myindex))

我們建議您在資料表提示之間使用逗號。

重要事項

用空格而不用逗號來分隔提示是一項已被取代的功能:未來的 Microsoft SQL Server 版本將移除這項功能。請勿在新的開發工作中使用此功能,並且儘速修改使用此功能的應用程式。

當使用提示來查詢相容性層級是 90 和更高層級的資料庫時,適用這些限制。

NOEXPAND

如需詳細資訊,請參閱<備註>一節。

INDEX (index_value [,... n] ) | INDEX = ( index_value)

每份資料表只能指定一個索引提示。

如果沒有叢集索引,INDEX(0) 會強制執行資料表掃描,INDEX(1) 會解譯為一則錯誤。

如果提示索引的集合不含此查詢所參考的所有資料行,則當 SQL Server Database Engine 擷取所有索引資料行之後,將會執行提取作業來擷取其餘的資料行。

附註

另外,指定了索引提示的資料表不接受索引的 OR 作業。

資料表提示中的最大索引數目是 250 個非叢集索引。

KEEPIDENTITY

OPENROWSET 使用 BULK 選項時,才適用於 INSERT 陳述式。

如果未指定 KEEPIDENTITY,就會驗證這個資料行的識別值,但不會匯入它,而且查詢最佳化工具會根據建立資料表期間所指定的種子值和遞增值來自動指派唯一值。

重要事項

如果順利跳過識別欄位,查詢最佳化工具會自動在匯入的資料表資料列中,指派識別欄位的唯一值。

大量匯入資料時保留識別值 (SQL Server)>。

DBCC CHECKIDENT (Transact-SQL)>。

KEEPDEFAULTS

OPENROWSET 使用 BULK 選項時,才適用於 INSERT 陳述式。

指定在資料記錄缺少資料行的值時,如果資料表資料行有預設值,便插入這個預設值,而不是 NULL。

大量匯入期間保留 Null 或使用預設值 (SQL Server)>。

FORCESEEK [ (index_value(index_column_name [ ,...n ] )) ]

如此一來,查詢最佳化工具只會考慮至少使用指定索引資料行之指定索引的索引搜尋作業。

index_value

如果要傳回索引名稱或識別碼,請查詢 sys.indexes 目錄檢視。

index_column_name

例如,如果指定了非叢集索引,最佳化工具可能會選擇使用叢集索引鍵資料行及指定的資料行。

您可以使用下列方式指定 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 隱含加入的資料分割資料行。

注意

在後續版本中,將會從內部修改最佳化工具,以擴大可使用的計畫範圍。

FORCESCAN

發生此狀況時,將只會授與作業少量的記憶體,導致查詢效能受到影響。

您可以指定 FORCESCAN 與索引提示 INDEX(0),對基底資料表強制執行資料表掃描作業。

這表示掃描只會套用至其餘資料分割,而不會套用到整份資料表。

FORCESCAN 提示具有下列限制。

  • 您不可為 INSERT、UPDATE 或 DELETE 陳述式的目標資料表指定此提示。

  • 此提示無法搭配多個索引提示使用。

  • 此提示會讓最佳化工具無法使用資料表的任何空間或 XML 索引。

  • 您無法指定遠端資料來源的提示。

  • 此提示不可與 FORCESCAN 提示同時指定。

HOLDLOCK

HOLDLOCK 不可在包含 FOR BROWSE 選項的 SELECT 陳述式中使用。

IGNORE_CONSTRAINTS

OPENROWSET 使用 BULK 選項時,才適用於 INSERT 陳述式。

請注意,您不能停用 UNIQUE、PRIMARY KEY 或 NOT NULL 條件約束。

當停用 CHECK 和 FOREIGN KEY 條件約束時,您可以先匯入資料,再利用 Transact-SQL 陳述式來清理資料。

如果在大量匯入作業之前,資料表不是空的,重新驗證條件約束的成本,可能會超出在累加資料上套用 CHECK 和 FOREIGN KEY 條件約束的成本。

IGNORE_TRIGGERS

OPENROWSET 使用 BULK 選項時,才適用於 INSERT 陳述式。

依預設,INSERT 會套用觸發程序。

請只在應用程式不相依於任何觸發程序,且發揮最大效能非常重要時,才使用 IGNORE_TRIGGERS。

NOLOCK

如需詳細資訊,請參閱這個主題稍後的 READUNCOMMITTED。

附註

如果是 UPDATE 或 DELETE 陳述式:未來的 Microsoft SQL Server 版本將移除這項功能。請避免在新的開發工作中使用這項功能,並規劃修改目前使用這項功能的應用程式。

NOWAIT

NOWAIT 相當於針對特定資料表指定 SET LOCK_TIMEOUT 0。

PAGLOCK

如果是在以 SNAPSHOT 隔離等級操作的交易中指定時,不會採用頁面鎖定,除非 PAGLOCK 是與其他需要鎖定的資料表提示相結合,例如 UPDLOCK 和 HOLDLOCK。

READCOMMITTED

SET TRANSACTION ISOLATION LEVEL (Transact-SQL)>。

附註

如果是 UPDATE 或 DELETE 陳述式:未來的 Microsoft SQL Server 版本將移除這項功能。請避免在新的開發工作中使用這項功能,並規劃修改目前使用這項功能的應用程式。

READCOMMITTEDLOCK

您不可為 INSERT 陳述式的目標資料表指定此提示,否則會傳回錯誤 4140。

READPAST

使用 READPAST 的佇列讀取器會略過其他交易已鎖定的佇列項目,直接到下一個可用的佇列項目,不需要等待其他交易釋放鎖定。

當讀取外部索引鍵或索引檢視表時,或當修改次要索引時,使用 READPAST 的更新或刪除作業可能會進行封鎖。

如果是在以 SNAPSHOT 隔離等級操作的交易中指定時,READPAST 必須與其他需要鎖定的資料表提示相結合,例如 UPDLOCK 和 HOLDLOCK。

當 READ_COMMITTED_SNAPSHOT 資料庫選項設為 ON,且下列其中一個條件成立時,無法指定 READPAST 資料表提示。

  • 此工作階段的交易隔離等級為 READ COMMITTED。

  • READCOMMITTED 資料表提示也會指定於查詢中。

若要在這些情況下指定 READPAST 提示,請移除 READCOMMITTED 資料表提示 (如果有的話),並在查詢中包含 READCOMMITTEDLOCK 資料表提示。

READUNCOMMITTED

這可能會使您的交易發生錯誤、為使用者提供永遠不被認可的資料,或是讓使用者看到記錄兩次 (或是根本看不到)。

相反地,保有 Sch-S 鎖定的查詢將會封鎖嘗試取得 Sch-M 鎖定的並行交易。

SQL Server 查詢最佳化工具會忽略套用在 UPDATE 或 DELETE 陳述式目標資料表的 FROM 子句中的 READUNCOMMITTED 和 NOLOCK 提示。

附註

請避免在新的開發工作中使用此內容中的這些提示,並規劃修改目前在使用這些提示的應用程式。

您可以使用下列其中一個選項,防止交易讀到尚未認可的資料修改 (中途讀取),同時也將鎖定競爭的情況減到最低:

  • READ_COMMITTED_SNAPSHOT 資料庫選項設為 ON 的 READ COMMITTED 隔離等級。

  • SNAPSHOT 隔離等級。

SET TRANSACTION ISOLATION LEVEL (Transact-SQL)>。

附註

如果您在指定 READUNCOMMITTED 的情況下,收到錯誤訊息 601,請依照死結錯誤 (1205) 的相同方式來解決它,再重試您的陳述式。

REPEATABLEREAD

SET TRANSACTION ISOLATION LEVEL (Transact-SQL)>。

ROWLOCK

如果是在以 SNAPSHOT 隔離等級操作的交易中指定時,不會採用資料列鎖定,除非 ROWLOCK 是與其他需要鎖定的資料表提示相結合,例如 UPDLOCK 和 HOLDLOCK。

SPATIAL_WINDOW_MAX_CELLS = integer

number 是介於 1 和 8192 之間的值。

對於較疏鬆的資料,較低的數目會減少主要篩選執行時間。

這個選項適用於手動和自動方格鑲嵌。

SERIALIZABLE

SET TRANSACTION ISOLATION LEVEL (Transact-SQL)>。

TABLOCK

如果同時指定了 HOLDLOCK,就會將資料表鎖定保留到交易結束為止。

INSERT (Transact-SQL)>。

大量匯入採用最低限度記錄的必要條件>。

TABLOCKX

指定獨佔鎖定是在資料表上取得。

UPDLOCK

如果並用 UPDLOCK 與 TABLOCK,或因故採用了資料表層級鎖定,將會改採獨佔 (X) 鎖定。

例如,如果工作階段的隔離等級設定為 SERIALIZABLE,而查詢指定了 (UPDLOCK, READCOMMITTED),將會忽略 READCOMMITTED 提示,並使用 SERIALIZABLE 隔離等級執行交易。

XLOCK

如果指定了 ROWLOCK、PAGLOCK 或 TABLOCK,就會將獨佔鎖定套用在適當的資料粒度層級上。

在後面一種情況中,您可以利用 OPTION (EXPAND VIEWS) 查詢提示來防止存取索引檢視表。

另外,SQL Server 也會執行對應的鎖定一致性檢查。

例如,如果資料表有非叢集索引,且使用鎖定提示的 SELECT 陳述式是由涵蓋索引來處理,就會取得此涵蓋索引之索引鍵的鎖定,而不是基底資料表之資料列的鎖定。

當存取運算式和函數所參考的資料表時,它們不會使用 NOLOCK 資料表提示。

SQL Server 不允許 FROM 子句中每份資料表的下列每個群組,都有一個以上的資料表提示:

  • 資料粒度提示: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 版本支援的功能 (http://go.microsoft.com/fwlink/?linkid=232473)。

不過,若要使最佳化工具考慮比對索引檢視表,或使用 NOEXPAND 提示所參考的索引檢視表,下列 SET 選項必須設為 ON。

 

ANSI_NULLS

ANSI_WARNINGS

CONCAT_NULL_YIELDS_NULL

ANSI_PADDING

1

QUOTED_IDENTIFIERS

因此,您不需要手動調整這個設定。

另外,NUMERIC_ROUNDABORT 選項必須設成 OFF。

SQL Server 不會提供提示強制在未在 FROM 子句直接指定檢視名稱的查詢中使用特定的索引檢視,但即使查詢中未直接參考索引檢視,查詢最佳化工具仍會使用索引檢視。

將資料表提示當做查詢提示使用

查詢提示 (Transact-SQL)>。

KEEPIDENTITY、IGNORE_CONSTRAINTS 和 IGNORE_TRIGGERS 提示需要資料表的 ALTER 權限。

A.使用 TABLOCK 提示指定鎖定方法

Production.Product 資料表上採用共用鎖定,並且將鎖定保留到 UPDATE 陳述式結束為止。

複製
USE AdventureWorks2012;
GO
UPDATE Production.Product
WITH (TABLOCK)
SET ListPrice = ListPrice * 1.10
WHERE ProductNumber LIKE 'BK-%';
GO

B.使用 FORCESEEK 提示指定索引搜尋作業

Sales.SalesOrderDetail 資料表執行索引搜尋作業。

複製
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.使用 FORCECAN 提示指定索引掃描作業

下列範例會使用 FORCESCAN 提示,強制查詢最佳化工具對 Sales.SalesOrderDetail 資料表執行掃描作業。

複製
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);

相关文章:

  • 2021-09-01
  • 2021-11-15
  • 2021-10-29
  • 2021-12-09
  • 2021-07-05
  • 2021-06-17
  • 2021-11-07
  • 2021-08-14
猜你喜欢
  • 2021-06-10
  • 2022-12-23
  • 2021-12-19
  • 2021-05-26
  • 2021-10-07
  • 2022-12-23
相关资源
相似解决方案