SQL क्वेरी लिखने के लिए सबसे अच्छा तरीका है जो गैर-पूर्ण मान या NULL के लिए एक स्तंभ की जाँच करता है


17

मेरे पास एक एसपी है जिसमें एक पैरामीटर है जो डिफ़ॉल्ट मान के समान है और फिर मैं इस तरह से एक क्वेरी करना चाहता हूं:

SELECT ...
FROM ...
WHERE a.Blah = @Blah AND (a.VersionId = @VersionId OR (@VersionId IS NULL AND a.VersionId IS NULL));

WHEREदोनों एक गैर-खाली मूल्य और के लिए एक शून्य मूल्य के लिए ऊपर जाँच करता है @VersionId

इसके बजाय प्रदर्शन के संदर्भ में बेहतर होगा कि एक IFबयान का उपयोग करें और क्वेरी को एक में डुप्लिकेट करें जो गैर-पूर्ण और दूसरे के लिए खोज करता है? :

IF @VersionId IS NULL BEGIN
    SELECT ...
    FROM ...
    WHERE a.Blah = @Blah AND a.VersionId IS NULL;
ELSE BEGIN
    SELECT ...
    FROM ...
    WHERE a.Blah = @Blah AND a.VersionId = @VersionId;
END

या क्वेरी ऑप्टिमाइज़र इसे अनिवार्य रूप से समान बनाता है?

अपडेट करें:

(नोट: मैं SQL सर्वर का उपयोग कर रहा हूँ)

(और जहां तक ​​मुझे पता है, a.VersionId = @VersionIdदोनों मामलों के लिए उपयोग करने से काम नहीं चलेगा, है?)



मैं आम तौर पर निम्नलिखित का उपयोग करता हूं: ISNULL (a.VersionId, @VersionId) = @VersionId
628426

जवाबों:


36

यह पैटर्न

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);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.