OR 演算子は、ネイティブ コンパイル ストアド プロシージャのクエリ述語ではサポートされていません。 NOT 演算子はネイティブ コンパイル ストアド プロシージャのクエリ述語でもサポートされていないため、同等の論理演算子のみを使用して OR 演算子の効果をシミュレートすることはできません。 ただし、OR 演算子の効果は、メモリ最適化テーブル変数を使用してシミュレートできます。
WHERE 句における OR 演算子
WHERE 句に OR 演算子がある場合は、次の方法を使用してその動作をシミュレートできます。
適切なスキーマを使用して、メモリ最適化テーブル変数を作成します。 これには、定義済みのメモリ最適化テーブル型が必要です。
最上位レベルの OR 演算子から始めて、OR 演算子によって結合された述語に従って、WHERE 句を 2 つの部分に分けます。 WHERE 句に複数の OR 演算子がある場合は、これを複数回行う必要がある場合があります。 OR 演算子が残らなくなるまで、この手順を繰り返します。 たとえば、次の述語がある場合です。
pred1 OR (pred2 AND (pred3 OR pred4)) OR (pred5 AND pred6)この手順の後に、次の述語が得られるはずです。
pred1 pred5 AND pred6 pred2 AND pred3 pred2 AND pred4手順 2 で見つかった 2 つの各部分を述語として使用してクエリを実行します。 各クエリの結果を、手順 1 で作成したメモリ最適化テーブル変数に挿入します。
必要に応じて、メモリ最適化テーブル変数から重複を削除します。
クエリの結果として、メモリ最適化テーブル変数の内容を使用します。
次の例では、In-Memory OLTP 用に更新された AdventureWorks2012 データベースのテーブルを使用します。 このサンプルのファイルをダウンロードするには、 AdventureWorks Databases - 2012、2008R2、2008 に移動します。 In-Memory OLTP コード サンプルを AdventureWorks2012 に適用するには、 SQL Server 2014 In-Memory OLTP サンプルに移動します。
次のストアド プロシージャをデータベースに追加します。 このストアド プロシージャは、ネイティブ コンパイルを使用するように変換します。
CREATE PROCEDURE Sales.usp_fuzzySearchSalesOrderDetail_ondisk
@SalesOrderId int = 0, @SalesOrderDetailId int = 0,
@CarrierTrackingNumber nvarchar(25) = N'', @ProductId int = 0,
@minUnitPrice money = 0, @maxUnitPrice money = 0
AS BEGIN
SELECT SalesOrderId, SalesOrderDetailId, ModifiedDate
FROM Sales.SalesOrderDetail_ondisk s
WHERE s.SalesOrderId = @SalesOrderId
OR s.SalesOrderDetailId = @SalesOrderDetailId
OR s.CarrierTrackingNumber = @CarrierTrackingNumber
OR s.ProductID = @ProductId
OR (s.UnitPrice > @minUnitPrice AND s.UnitPrice < @maxUnitPrice)
END
GO
変換後、テーブルとストアド プロシージャのスキーマは次のようになります。
CREATE TYPE Sales.fuzzySearchSalesOrderDetailType AS TABLE
(
SalesOrderId int not null,
SalesOrderDetailId int not null,
ModifiedDate datetime2(7) not null
INDEX ix_fuzzySearchSalesOrderDetailType NONCLUSTERED (SalesOrderId, SalesOrderDetailId)
) WITH (MEMORY_OPTIMIZED = ON)
GO
CREATE TYPE Sales.fuzzySearchSalesOrderDetailTempType AS TABLE
(
SalesOrderId int not null,
SalesOrderDetailId int not null,
recordcount int not null
INDEX ix_fuzzySearchSalesOrderDetailTempType NONCLUSTERED (SalesOrderId, SalesOrderDetailId)
) WITH (MEMORY_OPTIMIZED = ON)
GO
CREATE PROCEDURE Sales.usp_fuzzySearchSalesOrderDetail_inmem
@SalesOrderId int = 0, @SalesOrderDetailId int = 0,
@CarrierTrackingNumber nvarchar(25) = N'', @ProductId int = 0,
@minUnitPrice money = 0, @maxUnitPrice money = 0
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER
AS BEGIN ATOMIC WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'ENGLISH')
DECLARE @retValue Sales.fuzzySearchSalesOrderDetailType
INSERT INTO @retValue (SalesOrderId, SalesOrderDetailId, ModifiedDate)
SELECT SalesOrderId, SalesOrderDetailId, ModifiedDate
FROM Sales.SalesOrderDetail_inmem s
WHERE s.SalesOrderId = @SalesOrderId
INSERT INTO @retValue (SalesOrderId, SalesOrderDetailId, ModifiedDate)
SELECT SalesOrderId, SalesOrderDetailId, ModifiedDate
FROM Sales.SalesOrderDetail_inmem s
WHERE s.SalesOrderDetailId = @SalesOrderDetailId
INSERT INTO @retValue (SalesOrderId, SalesOrderDetailId, ModifiedDate)
SELECT SalesOrderId, SalesOrderDetailId, ModifiedDate
FROM Sales.SalesOrderDetail_inmem s
WHERE s.CarrierTrackingNumber COLLATE Latin1_General_BIN2 = @CarrierTrackingNumber COLLATE Latin1_General_BIN2
INSERT INTO @retValue (SalesOrderId, SalesOrderDetailId, ModifiedDate)
SELECT SalesOrderId, SalesOrderDetailId, ModifiedDate
FROM Sales.SalesOrderDetail_inmem s
WHERE s.ProductID = @ProductId
INSERT INTO @retValue (SalesOrderId, SalesOrderDetailId, ModifiedDate)
SELECT SalesOrderId, SalesOrderDetailId, ModifiedDate
FROM Sales.SalesOrderDetail_inmem s
WHERE (s.UnitPrice > @minUnitPrice AND s.UnitPrice < @maxUnitPrice)
-- After the above statements, there will be duplicates inside @retValue
-- Delete the duplicates from @retValue
DECLARE @duplicates Sales.fuzzySearchSalesOrderDetailTempType
INSERT INTO @duplicates (SalesOrderId, SalesOrderDetailId, recordcount)
SELECT SalesOrderId, SalesOrderDetailId, COUNT(*) AS recordCount
FROM @retValue
GROUP BY SalesOrderId, SalesOrderDetailId
-- Now we have one row per pair
-- clear and rebuild the result set
DELETE FROM @retValue
INSERT INTO @retValue
SELECT s.SalesOrderId, s.SalesOrderDetailId, s.ModifiedDate
FROM Sales.SalesOrderDetail_inmem s
JOIN @duplicates d ON s.SalesOrderId = d.SalesOrderId AND s.SalesOrderDetailId = d.SalesOrderDetailId
-- After this every pair of (SalesOrderId, SalesOrderDetailId) in @retValue should be unique.
SELECT SalesorderId, SalesOrderDetailId, ModifiedDate FROM @retValue
END
GO
JOIN 条件における OR 演算子
SELECT ステートメントの JOIN 条件に OR 演算子がある場合は、次の方法を使用してその動作をシミュレートできます。 JOIN 条件に複数の OR 演算子がある場合、または OR 演算子で複数の JOIN 条件がある場合は、これを複数回行う必要がある場合があります。
OUTER JOIN 条件がある場合、この回避策を他の OUTER JOIN 条件に対する回避策と組み合わせることができます。
適切なスキーマを使用して、メモリ最適化テーブル変数を作成します。 これには、定義済みのメモリ最適化テーブル型が必要です。
OR 演算子で結合された述語に従って、JOIN 条件の述語を 2 つの部分に分けます。 複数の JOIN 条件がある場合は、JOIN 条件ごとにこれを行い、結果のフラグメントの組み合わせのセットを作成する必要があります。 たとえば、各 JOIN 条件に 1 つの OR 演算子を持つ 3 つの JOIN 条件がある場合、2x2x2=8 述語が存在する可能性があります。
手順 2 で生成された述語ごとに、手順 1 で作成したメモリ最適化テーブル変数にその結果を挿入するクエリを作成します。
必要に応じて、メモリ最適化テーブル変数から重複を削除します。
クエリの結果として、メモリ最適化テーブル変数の内容を使用します。
次の例では、In-Memory OLTP 用に更新された AdventureWorks2012 データベースのテーブルを使用します。 このサンプルのファイルをダウンロードするには、 AdventureWorks Databases - 2012、2008R2、2008 に移動します。 In-Memory OLTP コード サンプルを AdventureWorks2012 に適用するには、 SQL Server 2014 In-Memory OLTP サンプルに移動します。
次のストアド プロシージャをデータベースに追加します。 このストアド プロシージャは、ネイティブ コンパイルを使用するように変換します。 このサンプルでは、INNER JOIN 条件を使用します。
CREATE PROCEDURE Sales.usp_fuzzySearchSalesSpecialOffers_ondisk
@SpecialOfferId int
AS BEGIN
SELECT s.SalesOrderId, s.SalesOrderDetailId, s.SpecialOfferID, s.ModifiedDate
FROM Sales.SalesOrderDetail_ondisk s
JOIN Sales.SpecialOffer_onDisk offer
ON s.SpecialOfferID = offer.SpecialOfferID
OR s.ProductID IN (SELECT ProductId FROM Sales.SpecialOfferProduct sop WHERE sop.SpecialOfferID = @SpecialOfferId)
END
変換後、テーブルとストアド プロシージャのスキーマは次のようになります。
CREATE TYPE Sales.fuzzySearchSalesSpecialOffers_Type AS TABLE
(
SalesOrderId int not null,
SalesOrderDetailId int not null,
SpecialOfferId int not null,
ModifiedDate datetime2(7) not null
INDEX ix_fuzzySearchSalesSpecialOffers_Type NONCLUSTERED (SalesOrderId, SalesOrderDetailId)
) WITH (MEMORY_OPTIMIZED = ON)
GO
CREATE TYPE Sales.fuzzySearchSalesSpecialOffers_TempType AS TABLE
(
SalesOrderId int not null,
SalesOrderDetailId int not null,
SpecialOfferId int not null,
recordcount int null
INDEX ix_fuzzySearchSalesSpecialOffers_TempType NONCLUSTERED (SalesOrderId, SalesOrderDetailId)
) WITH (MEMORY_OPTIMIZED = ON)
GO
CREATE PROCEDURE Sales.usp_fuzzySearchSalesSpecialOffers_inmem
@SpecialOfferId int
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER
AS BEGIN ATOMIC WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'ENGLISH')
DECLARE @retValue Sales.FuzzySearchSalesSpecialOffers_Type
-- Find all special offers matching the conditions
INSERT INTO @retValue (SalesOrderId, SalesOrderDetailId, SpecialOfferid, ModifiedDate)
SELECT s.SalesOrderId, s.SalesOrderDetailId, s.SpecialOfferID, s.ModifiedDate
FROM Sales.SalesOrderDetail_inmem s
JOIN Sales.SpecialOffer_inmem offer
ON s.SpecialOfferID = offer.SpecialOfferID
INSERT INTO @retValue (SalesOrderId, SalesOrderDetailId, SpecialOfferid, ModifiedDate)
SELECT s.SalesOrderId, s.SalesOrderDetailId, s.SpecialOfferID, s.ModifiedDate
FROM Sales.SalesOrderDetail_inmem s
JOIN Sales.SpecialOfferProduct_inmem sop
ON sop.SpecialOfferId = @SpecialOfferId AND s.ProductID = sop.ProductId
-- Now we need to remove the duplicates from @matchingSpecialOffers
DECLARE @duplicates Sales.fuzzySearchSalesSpecialOffers_TempType
INSERT INTO @duplicates (SalesOrderId, SalesOrderDetailId, SpecialOfferid, recordcount)
SELECT SalesOrderId, SalesOrderDetailId, SpecialOfferId, COUNT(*)
FROM @retValue
GROUP BY SalesOrderId, SalesOrderDetailId, SpecialOfferId
-- now there should be no duplicates within @duplicate
-- use @duplicate for join.
SELECT s.SalesOrderId, s.SalesOrderDetailId, s.SpecialOfferID, s.ModifiedDate
FROM Sales.SalesOrderDetail_inmem s
JOIN @duplicates offer
ON s.SalesOrderId = offer.SalesOrderId
AND s.SalesOrderDetailId = offer.SalesOrderDetailID
AND s.SpecialOfferId = offer.SpecialOfferId
END
GO
副作用
WHERE 句または JOIN 条件に複数の OR 演算子がある場合、動作をシミュレートするために実行する必要があるクエリの数が指数関数的に増加する可能性があります。 これにより、クエリのパフォーマンスが低下し、メモリ最適化テーブル変数を使用する必要があるため、メモリ使用量が増加する可能性があります。