資料表提示 (Transact-SQL)
資料表提示會在資料操作語言 (DML) 陳述式持續時間覆寫查詢最佳化工具的預設行為,其方式是指定鎖定方法、一個或多個索引、查詢處理作業 (例如資料表掃描或索引搜尋) 或是其他選項。
警告 |
---|
由於 SQL Server 查詢最佳化工具通常會選取最好的查詢執行計畫,因此,我們建議資深的開發人員和資料庫管理員將提示當做最後的解決辦法。 |
適用於:
語法
WITH ( <table_hint> [ [ , ]...n ] )
<table_hint> ::=
[ NOEXPAND ] {
INDEX ( index_value [ ,...n ] ) | INDEX = ( index_value )
| FASTFIRSTROW
| FORCESEEK
| HOLDLOCK
| NOLOCK
| NOWAIT
| PAGLOCK
| READCOMMITTED
| READCOMMITTEDLOCK
| READPAST
| READUNCOMMITTED
| REPEATABLEREAD
| ROWLOCK
| SERIALIZABLE
| TABLOCK
| TABLOCKX
| UPDLOCK
| XLOCK
}
<table_hint_limited> ::=
{
KEEPIDENTITY
| KEEPDEFAULTS
| FASTFIRSTROW
| HOLDLOCK
| IGNORE_CONSTRAINTS
| IGNORE_TRIGGERS
| NOWAIT
| PAGLOCK
| READCOMMITTED
| READCOMMITTEDLOCK
| READPAST
| REPEATABLEREAD
| ROWLOCK
| SERIALIZABLE
| TABLOCK
| TABLOCKX
| UPDLOCK
| XLOCK
}
引數
WITH ( <table_hint> ) [ [ , ]...n ]
但有某些例外,僅當利用 WITH 關鍵字指定提示時,FROM 子句才會支援資料表提示。資料表提示也必須用括號來指定。重要事項 省略 WITH 關鍵字是一項已被取代的功能:未來的 Microsoft SQL Server 版本將移除這項功能。請避免在新的開發工作中使用這項功能,並規劃修改目前使用這項功能的應用程式。
不論是否有 WITH 關鍵字,都允許使用下列資料表提示:NOLOCK、READUNCOMMITTED、UPDLOCK、REPEATABLEREAD、SERIALIZABLE、READCOMMITTED、FASTFIRSTROW、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 ( index_value [ ,... n] ) | INDEX = ( index_value )
INDEX() 語法會指定當查詢最佳化工具在處理陳述式時,所要使用之一個或多個索引的名稱或識別碼。替代的 INDEX = 語法會指定單一索引值。每份資料表只能指定一個索引提示。如果有叢集索引存在,INDEX(0) 會強制執行叢集索引掃描,INDEX(1) 會強制執行叢集索引掃描或搜尋。如果沒有叢集索引,INDEX(0) 會強制執行資料表掃描,INDEX(1) 會解譯為一則錯誤。
如果在單一提示清單中使用多個索引,便會忽略重複項目,且會利用其餘列出的索引來擷取資料表的資料列。索引提示中的索引順序非常重要。另外,多個索引提示也會強制執行索引的 AND 作業,而且查詢最佳化工具會在所存取的每個索引上盡量套用多一點的條件。如果提示索引的集合不含此查詢所參考的所有資料行,則當 SQL Server Database Engine 擷取所有索引資料行之後,將會執行提取作業來擷取其餘的資料行。
[!附註]
當星狀聯結的事實資料表使用參考多個索引的索引提示時,最佳化工具會忽略索引提示,且會傳回一則警告訊息。另外,指定了索引提示的資料表不接受索引的 OR 作業。
資料表提示中的最大索引數目是 250 個非叢集索引。
KEEPIDENTITY
只有在搭配 OPENROWSET 使用 BULK 選項時,才適用於 INSERT 陳述式。指定識別欄位要使用匯入之資料檔中的一個或多個識別值。如果未指定 KEEPIDENTITY,就會驗證這個資料行的識別值,但不會匯入它,而且查詢最佳化工具會根據建立資料表期間所指定的種子值和遞增值來自動指派唯一值。
重要事項 如果資料檔中沒有資料表或檢視表中之識別欄位的值,而且識別欄位不是資料表的最後一個資料行,您就必須略過此識別欄位。如需詳細資訊,請參閱<使用格式檔案以略過資料欄位>。如果順利跳過識別欄位,查詢最佳化工具會自動在匯入的資料表資料列中,指派識別欄位的唯一值。
如需在 INSERT ...SELECT * FROM OPENROWSET(BULK...)陳述式中使用這個提示的範例,請參閱<大量匯入資料時保留識別值>。
如需有關檢查資料表識別值的詳細資訊,請參閱<DBCC CHECKIDENT (Transact-SQL)>。
KEEPDEFAULTS
只有在搭配 OPENROWSET 使用 BULK 選項時,才適用於 INSERT 陳述式。指定在資料記錄缺少資料行的值時,如果資料表資料行有預設值的話,便插入這個預設值,而不是 NULL。
如需在 INSERT ...SELECT * FROM OPENROWSET(BULK...)陳述式中使用這個提示的範例,請參閱<在大量匯入期間保留 Null 或使用預設值>。
FASTFIRSTROW
這相當於 OPTION (FAST 1)。如需詳細資訊,請參閱<查詢提示 (Transact-SQL)>。重要事項 下一版的 Microsoft SQL Server 將不再提供此功能。請勿在新的開發工作中使用此功能,並且儘速修改使用此功能的應用程式。
FORCESEEK
指定查詢最佳化工具只使用索引搜尋作業,當做查詢中參考之資料表或檢視表資料的存取路徑。FORCESEEK 同樣適用於叢集和非叢集的索引搜尋作業。可以針對 SELECT 陳述式的 FROM 子句中以及 UPDATE、MERGE 或 DELETE 陳述式的 FROM <table_source> 子句中的任何資料表或檢視表來指定它。
指定 FORCESEEK 時,不一定需要 INDEX 提示。當查詢最佳化工具結合索引提示時,它會透過指定的索引來只考量搜尋存取路徑。如果 FORCESEEK 造成找不到任何計畫,將會傳回錯誤 8622。如需詳細資訊,請參閱<使用 FORCESEEK 資料表提示>。
HOLDLOCK
這相當於 SERIALIZABLE。如需詳細資訊,請參閱這個主題稍後的 SERIALIZABLE。HOLDLOCK 只適用於指定了 HOLDLOCK 的資料表或檢視表,且只在使用它的陳述式所定義的交易持續時間內有效。包括 FOR BROWSE 選項的 SELECT 陳述式不能使用 HOLDLOCK。IGNORE_CONSTRAINTS
只有在搭配 OPENROWSET 使用 BULK 選項時,才適用於 INSERT 陳述式。指定大量匯入作業忽略資料表的任何條件約束。根據預設,INSERT 會檢查 CHECK 和 FOREIGN KEY 條件約束。當大量匯入作業指定 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
只有在搭配 OPENROWSET 使用 BULK 選項時,才適用於 INSERT 陳述式。指定大量匯入作業忽略資料表所定義的任何觸發程序。依預設,INSERT 會套用觸發程序。
請只在應用程式不相依於任何觸發程序,且發揮最大效能非常重要時,才使用 IGNORE_TRIGGERS。
NOLOCK
這相當於 READUNCOMMITTED。如需詳細資訊,請參閱這個主題稍後的 READUNCOMMITTED。[!附註]
如果是 UPDATE 或 DELETE 陳述式:未來的 Microsoft SQL Server 版本將移除這項功能。請避免在新的開發工作中使用這項功能,並規劃修改目前使用這項功能的應用程式。
NOWAIT
指示 Database Engine 一旦發現資料表的鎖定時,便立刻傳回訊息。NOWAIT 相當於針對特定資料表指定 SET LOCK_TIMEOUT 0。PAGLOCK
在通常會採用資料列或索引鍵的個別鎖定,或通常會採用單一資料表鎖定的情況下,頁面會鎖定。依預設,會使用作業所適用的鎖定模式。如果是在以 SNAPSHOT 隔離等級操作的交易中指定時,不會採用頁面鎖定,除非 PAGLOCK 是與其他需要鎖定的資料表提示相結合,例如 UPDLOCK 和 HOLDLOCK。READCOMMITTED
指定讀取作業使用鎖定或資料列版本控制,以遵守 READ COMMITTED 隔離等級的規則。如果資料庫選項 READ_COMMITTED_SNAPSHOT 是 OFF,則 Database Engine 會在讀取資料時取得共用鎖定,並在讀取作業完成時釋放這些鎖定。如果資料庫選項 READ_COMMITTED_SNAPSHOT 是 ON,Database Engine 便不需要鎖定,而會使用資料列版本控制。如需有關隔離等級的詳細資訊,請參閱<SET TRANSACTION ISOLATION LEVEL (Transact-SQL)>。[!附註]
如果是 UPDATE 或 DELETE 陳述式:未來的 Microsoft SQL Server 版本將移除這項功能。請避免在新的開發工作中使用這項功能,並規劃修改目前使用這項功能的應用程式。
READCOMMITTEDLOCK
指定讀取作業使用鎖定,以遵守 READ COMMITTED 隔離等級的規則。不論資料庫選項 READ_COMMITTED_SNAPSHOT 的設定為何,Database Engine 一律在讀取資料時取得共用鎖定,並在讀取作業完成時釋放這些鎖定。如需有關隔離等級的詳細資訊,請參閱<SET TRANSACTION ISOLATION LEVEL (Transact-SQL)>。READPAST
指定 Database Engine 不讀取其他交易已鎖定的資料列。在大部分情況下,這項指定也適用於頁面。當指定了 READPAST 時,將會略過資料列層級和頁面層級的鎖定。也就是說,Database Engine 會跳過資料列或頁面,而不是封鎖目前交易,直到釋放鎖定為止。例如,假設資料表 T1 包含了值為 1、2、3、4、5 的單一整數資料行。如果交易 A 將 3 的值變更為 8,但是尚未認可,則 SELECT * FROM T1 (READPAST) 會產生 1、2、4、5 的值。READPAST 主要是在實作一個工作佇列來使用 SQL Server 資料表時,為了減少鎖定爭用而使用。使用 READPAST 的佇列讀取器會略過其他交易已鎖定的佇列項目,直接到下一個可用的佇列項目,不需要等待其他交易釋放鎖定。UPDATE 或 DELETE 陳述式所參考的任何資料表,以及 FROM 子句所參考的任何資料表,都可以指定 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 鎖定的並行交易。如需有關鎖定行為的詳細資訊,請參閱<鎖定相容性 (Database Engine)>。
無法針對插入、更新或刪除作業修改的資料表指定 READUNCOMMITTED 和 NOLOCK。SQL Server 查詢最佳化工具會忽略套用在 UPDATE 或 DELETE 陳述式目標資料表的 FROM 子句中的 READUNCOMMITTED 和 NOLOCK 提示。
[!附註]
SQL Server 的未來版本將移除套用到 UPDATE 或 DELETE 陳述式目標資料表的 FROM 子句中 READUNCOMMITTED 和 NOLOCK 提示的使用支援。請避免在新的開發工作中使用此內容中的這些提示,並規劃修改目前在使用這些提示的應用程式。
您可以使用下列其中一個選項,防止交易讀到尚未認可的資料修改 (中途讀取),同時也將鎖定爭用的情況減到最低:
READ_COMMITTED_SNAPSHOT 資料庫選項設為 ON 的 READ COMMITTED 隔離等級。
SNAPSHOT 隔離等級。
如需有關隔離等級的詳細資訊,請參閱<SET TRANSACTION ISOLATION LEVEL (Transact-SQL)>。
[!附註]
如果您在指定 READUNCOMMITTED 的情況下,收到錯誤訊息 601,請依照死結錯誤 (1205) 的相同方式來解決它,再重試您的陳述式。
REPEATABLEREAD
指定利用與執行 REPEATABLE READ 隔離等級之交易相同的鎖定語意來執行掃描。如需有關隔離等級的詳細資訊,請參閱<SET TRANSACTION ISOLATION LEVEL (Transact-SQL)>。ROWLOCK
指定通常在採用頁面或資料表鎖定時,採用資料列鎖定。如果是在以 SNAPSHOT 隔離等級操作的交易中指定時,不會採用資料列鎖定,除非 ROWLOCK 是與其他需要鎖定的資料表提示相結合,例如 UPDLOCK 和 HOLDLOCK。SERIALIZABLE
這相當於 HOLDLOCK。使共用鎖定更具限制性的方法是將共用鎖定持續保留到交易完成為止,而不是在不再需要所要求的資料表或資料頁面時,便立即釋放共用鎖定 (不論交易是否完成)。利用與在 SERIALIZABLE 隔離等級執行之交易相同的語意來執行掃描。如需有關隔離等級的詳細資訊,請參閱<SET TRANSACTION ISOLATION LEVEL (Transact-SQL)>。TABLOCK
指定資料表設定共用鎖定,並保留到陳述式結束為止。如果也指定了 HOLDLOCK,就會將共用資料表鎖定保留到交易結束為止。當您使用 INSERT INTO <target_table> SELECT <columns> FROM <source_table> 陳述式,將資料匯入堆積時,可以指定目標資料表的 TABLOCK 提示來啟用陳述式的最佳化記錄和鎖定。此外,資料庫的復原模式必須設定為簡單或大量記錄。如需詳細資訊,請參閱<INSERT (Transact-SQL)>。
當 TABLOCK 搭配 OPENROWSET BULK 資料列集提供者使用,以便將資料匯入資料表時,它會使多個用戶端能夠以最佳化的記錄和鎖定,同時將資料載入目標資料表中。如需詳細資訊,請參閱<大量匯入採用最低限度記錄的必要條件>。
TABLOCKX
指定獨佔鎖定是在資料表上取得。UPDLOCK
指定採用更新鎖定,且保留到交易完成為止。XLOCK
指定採用獨佔鎖定,且保留到交易完成為止。如果指定了 ROWLOCK、PAGLOCK 或 TABLOCK,就會將獨佔鎖定套用在適當的資料粒度層級上。
備註
如果查詢計畫並未存取資料表,就會忽略資料表提示。這可能是最佳化工具選擇完全不存取資料表所造成的,也可能是因為改成存取索引檢視表。在後面一種情況中,您可以利用 OPTION (EXPAND VIEWS) 查詢提示來防止存取索引檢視表。
所有鎖定提示都會傳播到查詢計畫所存取的所有資料表和檢視表,包括檢視表中所參考的資料表和檢視表。另外,SQL Server 也會執行對應的鎖定一致性檢查。
取得資料列層級鎖定的 ROWLOCK、UPDLOCK、AND XLOCK 等鎖定提示,會將鎖定放在索引鍵上,而不是實際的資料列上。例如,如果資料表有非叢集索引,且使用鎖定提示的 SELECT 陳述式是由涵蓋索引來處理,就會取得此涵蓋索引之索引鍵的鎖定,而不是基底資料表之資料列的鎖定。
如果資料表包含計算資料行,且計算資料行是由存取其他資料表之資料行的運算式或函數來計算,就不會在這些資料表上使用資料表提示。這表示不會傳播資料表提示。例如,在查詢中指定資料表的 NOLOCK 資料表提示。這份資料表擁有多個計算資料行,這些計算資料行會利用存取另一資料表中之資料行的運算式和函數的組合來進行計算。當存取運算式和函數所參考的資料表時,它們不會使用 NOLOCK 資料表提示。
SQL Server 不允許 FROM 子句中每份資料表的下列每個群組,都有一個以上的資料表提示:
資料粒度提示:PAGLOCK、NOLOCK、ROWLOCK、TABLOCK 或 TABLOCKX。
隔離等級提示:HOLDLOCK、NOLOCK、READCOMMITTED、REPEATABLEREAD、SERIALIZABLE。
已篩選的索引提示
已篩選的索引可以當做資料表提示使用,但是當它未涵蓋此查詢所選取的所有資料列時,會造成查詢最佳化工具產生錯誤 8622。下列是無效之已篩選的索引提示範例。此範例會建立已篩選的索引 FIBillOfMaterialsWithComponentID,然後將它當做 SELECT 陳述式的索引提示使用。已篩選的索引述詞包括 ComponentID 533、324 和 753 的資料列。此查詢述詞也包含 ComponentID 533、324 和 753 的資料列,但是會擴充結果集,使其包含 ComponentID 855 和 924 (這兩者不在已篩選的索引中)。因此,查詢最佳化工具無法使用已篩選的索引提示,而且會產生錯誤 8622。如需詳細資訊,請參閱<篩選索引設計指導方針>。
USE AdventureWorks;
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 只適用於索引檢視表。索引檢視表是建立了唯一叢集索引的檢視表。如果查詢包含同時在索引檢視表和基底資料表中的資料行參考,而且查詢最佳化工具判斷使用索引檢視表能夠提供最好的查詢執行方法,則查詢最佳化工具會使用檢視表的索引。這項功能稱為「索引檢視表比對」(Indexed View Matching),只有 SQL Server Enterprise 和 Developer 版本支援這項功能。
不過,若要使最佳化工具考慮比對索引檢視表,或使用 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 選項。只有在查詢也指定了檢視表的名稱時,才能使用這個提示。SQL Server 在 FROM 子句並未直接指定檢視表名稱的查詢中,不會提供強制使用特定索引檢視表的提示;不過,查詢最佳化工具仍會考慮使用索引檢視表,即使查詢並未直接參考它們,也是如此。
如需詳細資訊,請參閱<解析檢視上的索引>。
將資料表提示當做查詢提示使用
也可以使用 OPTION (TABLE HINT) 子句將資料表提示指定為查詢提示。我們建議您只有在計畫指南的內容中,才將資料表提示當做查詢提示使用。如果是特定的查詢,只將這些提示指定為資料表提示。如需詳細資訊,請參閱<查詢提示 (Transact-SQL)>。
權限
KEEPIDENTITY、IGNORE_CONSTRAINTS 和 IGNORE_TRIGGERS 提示需要資料表的 ALTER 權限。
範例
A. 使用 TABLOCK 提示來指定鎖定方法
下列範例會指定在 Production.Product 資料表上採用共用鎖定,並且將鎖定保留到 UPDATE 陳述式結束為止。
USE AdventureWorks;
GO
UPDATE Production.Product
WITH (TABLOCK)
SET ListPrice = ListPrice * 1.10
WHERE ProductNumber LIKE 'BK-%';
GO
B. 使用 FORCESEEK 提示來指定索引搜尋作業
下列範例會使用 FORCESEEK 提示來強制查詢最佳化工具針對 Sales.SalesOrderDetail 資料表執行索引搜尋作業。
USE AdventureWorks;
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