# “存在（…）或存在（…）”中子句的顺序

11

``````SELECT CASE
WHEN EXISTS (SELECT 1 FROM ...)
OR EXISTS (SELECT 1 FROM ...)
THEN 1 ELSE 0 END;``````

（如果SQL Server更聪明，它似乎将并行执行两个EXISTS子句，并让其中一个先完成另一个短路。）

``````SELECT CASE
WHEN EXISTS (SELECT 1 FROM zumero.dbf_1162761\$z\$rv\$1257927703 rv INNER JOIN zumero.dbf_1162761\$t\$tx tx ON tx.txid=rv.txid WHERE tx.generation BETWEEN 1500 AND 2502)
OR EXISTS (SELECT 1 FROM zumero.dbf_1162761\$z\$dd\$1257927703 dd INNER JOIN zumero.dbf_1162761\$t\$tx tx ON tx.txid=dd.txid WHERE tx.generation BETWEEN 1500 AND 2502)
THEN 1 ELSE 0 END
OPTION (OPTIMIZE FOR UNKNOWN)``````

``````|--Compute Scalar(DEFINE:([Expr1006]=CASE WHEN [Expr1007] THEN (1) ELSE (0) END))
|--Nested Loops(Left Semi Join, DEFINE:([Expr1007] = [PROBE VALUE]))
|--Constant Scan
|--Concatenation
|--Nested Loops(Inner Join, WHERE:([scale].[zumero].[dbf_1162761\$z\$rv\$1257927703].[txid] as [rv].[txid]=[scale].[zumero].[dbf_1162761\$t\$tx].[txid] as [tx].[txid]))
|    |--Clustered Index Scan(OBJECT:([scale].[zumero].[dbf_1162761\$z\$rv\$1257927703].[PK__dbf_1162__97770A2F62EEAE79] AS [rv]), WHERE:([scale].[zumero].[dbf_1162761\$z\$rv\$1257927703].[txid] as [rv].[txid]>(0)))
|    |--Index Seek(OBJECT:([scale].[zumero].[dbf_1162761\$t\$tx].[gendex] AS [tx]), SEEK:([tx].[generation] >= (1500) AND [tx].[generation] <= (2502)) ORDERED FORWARD)
|--Nested Loops(Inner Join, OUTER REFERENCES:([tx].[txid]))
|--Clustered Index Scan(OBJECT:([scale].[zumero].[dbf_1162761\$t\$tx].[PK__dbf_1162__E3BA953EC2197789] AS [tx]),  WHERE:([scale].[zumero].[dbf_1162761\$t\$tx].[generation] as [tx].[generation]>=(1500) AND [scale].[zumero].[dbf_1162761\$t\$tx].[generation] as [tx].[generation]<=(2502)) ORDERED FORWARD)
|--Index Seek(OBJECT:([scale].[zumero].[dbf_1162761\$z\$dd\$1257927703].[n\$dbf_1162761\$z\$dd\$txid\$1257927703] AS [dd]), SEEK:([dd].[txid]=[scale].[zumero].[dbf_1162761\$t\$tx].[txid] as [tx].[txid]),  WHERE:([scale].[zumero].[dbf_1162761\$z\$dd\$1257927703].[txid] as [dd].[txid]>(0)) ORDERED FORWARD)``````

``````SELECT CASE
WHEN EXISTS (SELECT 1 FROM zumero.dbf_1162761\$z\$dd\$1257927703 dd INNER JOIN zumero.dbf_1162761\$t\$tx tx ON tx.txid=dd.txid WHERE tx.generation BETWEEN 1500 AND 2502)
OR EXISTS (SELECT 1 FROM zumero.dbf_1162761\$z\$rv\$1257927703 rv INNER JOIN zumero.dbf_1162761\$t\$tx tx ON tx.txid=rv.txid WHERE tx.generation BETWEEN 1500 AND 2502)
THEN 1 ELSE 0 END
OPTION (OPTIMIZE FOR UNKNOWN)``````

``````|--Compute Scalar(DEFINE:([Expr1006]=CASE WHEN [Expr1007] THEN (1) ELSE (0) END))
|--Nested Loops(Left Semi Join, DEFINE:([Expr1007] = [PROBE VALUE]))
|--Constant Scan
|--Concatenation
|--Nested Loops(Inner Join, OUTER REFERENCES:([tx].[txid]))
|    |--Clustered Index Scan(OBJECT:([scale].[zumero].[dbf_1162761\$t\$tx].[PK__dbf_1162__E3BA953EC2197789] AS [tx]),  WHERE:([scale].[zumero].[dbf_1162761\$t\$tx].[generation] as [tx].[generation]>=(1500) AND [scale].[zumero].[dbf_1162761\$t\$tx].[generation] as [tx].[generation]<=(2502)) ORDERED FORWARD)
|    |--Index Seek(OBJECT:([scale].[zumero].[dbf_1162761\$z\$dd\$1257927703].[n\$dbf_1162761\$z\$dd\$txid\$1257927703] AS [dd]), SEEK:([dd].[txid]=[scale].[zumero].[dbf_1162761\$t\$tx].[txid] as [tx].[txid]),  WHERE:([scale].[zumero].[dbf_1162761\$z\$dd\$1257927703].[txid] as [dd].[txid]>(0)) ORDERED FORWARD)
|--Nested Loops(Inner Join, WHERE:([scale].[zumero].[dbf_1162761\$z\$rv\$1257927703].[txid] as [rv].[txid]=[scale].[zumero].[dbf_1162761\$t\$tx].[txid] as [tx].[txid]))
|--Clustered Index Scan(OBJECT:([scale].[zumero].[dbf_1162761\$z\$rv\$1257927703].[PK__dbf_1162__97770A2F62EEAE79] AS [rv]), WHERE:([scale].[zumero].[dbf_1162761\$z\$rv\$1257927703].[txid] as [rv].[txid]>(0)))
|--Index Seek(OBJECT:([scale].[zumero].[dbf_1162761\$t\$tx].[gendex] AS [tx]), SEEK:([tx].[generation] >= (1500) AND [tx].[generation] <= (2502)) ORDERED FORWARD)``````

11

``````CREATE TABLE dbo.X_HEAP (ID INT NOT NULL, FLUFF VARCHAR(100));

INSERT INTO dbo.X_HEAP  WITH (TABLOCK)
SELECT TOP (1000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), REPLICATE('Z', 100)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);

CREATE TABLE dbo.X_CI (ID INT NOT NULL, FLUFF VARCHAR(100), PRIMARY KEY (ID));

INSERT INTO dbo.X_CI  WITH (TABLOCK)
SELECT TOP (1000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), REPLICATE('Z', 100)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);``````

``````SELECT CASE
WHEN EXISTS (SELECT 1 FROM dbo.X_HEAP WHERE ID = 500000)
OR EXISTS (SELECT 1 FROM dbo.X_CI WHERE ID = 500000)
THEN 1 ELSE 0 END;``````

``````SELECT CASE
WHEN EXISTS (SELECT 1 FROM dbo.X_CI WHERE ID = 500000) THEN 1
WHEN EXISTS (SELECT 1 FROM dbo.X_HEAP WHERE ID = 500000) THEN 1
ELSE 0 END;``````

SQL Server执行时间：CPU时间= 0毫秒，经过的时间= 0毫秒。

``````SELECT CASE
WHEN EXISTS (SELECT 1 FROM dbo.X_HEAP WHERE ID = 500000) THEN 1
WHEN EXISTS (SELECT 1 FROM dbo.X_CI WHERE ID = 500000) THEN 1
ELSE 0 END
OPTION (MAXDOP 1);``````

SQL Server执行时间：CPU时间= 15毫秒，经过的时间= 22毫秒。

``````SELECT CASE
WHEN EXISTS (SELECT 1 FROM dbo.X_HEAP WHERE ID = 500000)
OR EXISTS (SELECT 1 FROM dbo.X_CI WHERE ID = 500000)
THEN 1 ELSE 0 END;``````

``````SELECT CASE
WHEN EXISTS (SELECT 1 FROM dbo.X_CI WHERE ID = 500000)
OR EXISTS (SELECT 1 FROM dbo.X_HEAP WHERE ID = 500000)
THEN 1 ELSE 0 END;``````

``````SELECT CASE
WHEN EXISTS (
SELECT 1
FROM (
SELECT TOP 2 1 t
FROM
(
SELECT 1 ID

UNION ALL

SELECT TOP 1 ID
FROM dbo.X_HEAP
WHERE ID = 50000
) h
CROSS JOIN
(
SELECT 1 ID

UNION ALL

SELECT TOP 1 ID
FROM dbo.X_CI
WHERE ID = 50000
) ci
) cnt
HAVING COUNT(*) = 2
)
THEN 1 ELSE 0 END;``````

4
`CASE WHEN EXISTS (SELECT 1 FROM dbo.X_CI WHERE ID = 500000 UNION ALL SELECT 1 FROM dbo.X_HEAP WHERE ID = 500000) THEN 1 ELSE 0 END`可以选择另一种方法，尽管这仍然依赖于手动确定哪个查询更快，并将其放在第一位。我不确定是否有表达它的方法，以便SQL Server将自动重新排序，以便首先自动评估廉价的。