यह पैटर्न
column = @argument OR (@argument IS NULL AND column IS NULL)
से बदला जा सकता है
EXISTS (SELECT column INTERSECT SELECT @argument)
यह आपको NULL के साथ NULL से मेल खाने देगा और इंजन को column
कुशलता से एक इंडेक्स का उपयोग करने की अनुमति देगा । इस तकनीक के एक उत्कृष्ट गहराई से विश्लेषण के लिए, मैं आपको पॉल व्हाइट के ब्लॉग लेख का संदर्भ देता हूं:
जैसा कि आपके विशेष मामले में दो तर्क हैं, आप उसी मिलान तकनीक का उपयोग कर सकते हैं @Blah
- इस तरह से आप संपूर्ण WHERE क्लॉज को अधिक या कम संक्षिप्त रूप से पुनः लिख सकेंगे:
WHERE
EXISTS (SELECT a.Blah, a.VersionId INTERSECT SELECT @Blah, @VersionId)
यह एक इंडेक्स पर तेजी से काम करेगा (a.Blah, a.VersionId)
।
या क्वेरी ऑप्टिमाइज़र इसे अनिवार्य रूप से समान बनाता है?
इस मामले में, हाँ। SQL सर्वर 2005 से सभी संस्करणों (कम से कम) में, ऑप्टिमाइज़र पैटर्न को पहचान सकता है col = @var OR (@var IS NULL AND col IS NULL)
और इसे उचित IS
तुलना के साथ बदल सकता है । यह आंतरिक पुनर्लेखन मिलान पर निर्भर करता है, इसलिए अधिक जटिल मामले हो सकते हैं जहां यह हमेशा विश्वसनीय नहीं होता है।
2008 SP1 CU5 समावेशी से SQL सर्वर के संस्करणों में , आपके पास पैरामीटर एंबेडिंग ऑप्टिमाइज़ेशन के माध्यम से उपयोग करने का विकल्प भी है OPTION (RECOMPILE)
, जहां संकलन से पहले किसी भी पैरामीटर या चर का रनटाइम मान क्वेरी के रूप में एम्बेडेड है।
तो, कम से कम काफी हद तक, इस मामले में चुनाव शैली का विषय है, हालांकि INTERSECT
निर्माण निर्विवाद रूप से कॉम्पैक्ट और सुरुचिपूर्ण है।
निम्नलिखित उदाहरण प्रत्येक भिन्नता के लिए 'समान' निष्पादन योजना दिखाते हैं (शाब्दिक बनाम चर संदर्भ को छोड़कर):
DECLARE @T AS table
(
c1 integer NULL,
c2 integer NULL,
c3 integer NULL
UNIQUE CLUSTERED (c1, c2)
);
-- Some data
INSERT @T
(c1, c2, c3)
SELECT 1, 1, 1 UNION ALL
SELECT 2, 2, 2 UNION ALL
SELECT NULL, NULL, NULL UNION ALL
SELECT 3, 3, 3;
-- Filtering conditions
DECLARE
@c1 integer,
@c2 integer;
SELECT
@c1 = NULL,
@c2 = NULL;
-- Writing the NULL-handling out explicitly
SELECT *
FROM @T AS T
WHERE
(
T.c1 = @c1
OR (@c1 IS NULL AND T.c1 IS NULL)
)
AND
(
T.c2 = @c2
OR (@c2 IS NULL AND T.c2 IS NULL)
);
-- Using INTERSECT
SELECT *
FROM @T AS T
WHERE EXISTS
(
SELECT T.c1, T.c2
INTERSECT
SELECT @c1, @c2
);
-- Using separate queries
IF @c1 IS NULL AND @c2 IS NULL
SELECT *
FROM @T AS T
WHERE T.c1 IS NULL
AND T.c2 IS NULL
ELSE IF @c1 IS NULL
SELECT *
FROM @T AS T
WHERE T.c1 IS NULL
AND T.c2 = @c2
ELSE IF @c2 IS NULL
SELECT *
FROM @T AS T
WHERE T.c1 = @c1
AND T.c2 IS NULL
ELSE
SELECT *
FROM @T AS T
WHERE T.c1 = @c1
AND T.c2 = @c2;
-- Using OPTION (RECOMPILE)
-- Requires 2008 SP1 CU5 or later
SELECT *
FROM @T AS T
WHERE
(
T.c1 = @c1
OR (@c1 IS NULL AND T.c1 IS NULL)
)
AND
(
T.c2 = @c2
OR (@c2 IS NULL AND T.c2 IS NULL)
)
OPTION (RECOMPILE);