कंप्यूटेड कॉलम पर फ़िल्टर किए गए इंडेक्स बनाने में असमर्थ


18

मेरे पिछले प्रश्न में, टेबल पर नए गणना किए गए कॉलम जोड़ते समय लॉक एस्केलेशन को अक्षम करना एक अच्छा विचार है?, मैं एक गणना कॉलम बना रहा हूं:

ALTER TABLE dbo.tblBGiftVoucherItem
ADD isUsGift AS CAST
(
    ISNULL(
        CASE WHEN sintMarketID = 2 
            AND strType = 'CARD'
            AND strTier1 LIKE 'GG%' 
        THEN 1 
        ELSE 0 
        END
    , 0) 
    AS BIT
) PERSISTED;

गणना की गई कॉलम है PERSISTED, और गणना के अनुसार_column_definition (Transact-SQL) :

कायम

निर्दिष्ट करता है कि डेटाबेस इंजन तालिका में गणना किए गए मानों को भौतिक रूप से संग्रहीत करेगा, और जब कोई अन्य कॉलम जिस पर गणना किए गए स्तंभ निर्भर हैं, तब अद्यतित करें। एक गणना किए गए कॉलम को PERSISTED के रूप में चिह्नित करना एक इंडेक्स को एक गणना किए गए कॉलम पर बनाने की अनुमति देता है जो नियतात्मक है, लेकिन सटीक नहीं है। अधिक जानकारी के लिए, कम्प्यूटेड कॉलम पर अनुक्रमित देखें। विभाजन तालिका के विभाजन कॉलम के रूप में उपयोग किए जाने वाले किसी भी गणना किए गए कॉलम को स्पष्ट रूप से चिह्नित किया जाना चाहिए। परिकलित निर्दिष्ट होने पर कंप्यूटेड_कॉम्पी_ कंप्रेसन निश्चित होना चाहिए।

लेकिन जब मैं अपने कॉलम पर एक इंडेक्स बनाने की कोशिश करता हूं तो मुझे निम्नलिखित त्रुटि मिलती है:

CREATE INDEX FIX_tblBGiftVoucherItem_incl
ON dbo.tblBGiftVoucherItem (strItemNo) 
INCLUDE (strTier3)
WHERE isUsGift = 1;

फ़िल्टर किए गए इंडेक्स 'FIX_tblBGiftVoucherItem_incl' को टेबल 'dbo.tblBGiftVoucherItem' पर नहीं बनाया जा सकता है क्योंकि फ़िल्टर एक्सप्रेशन में कॉलम 'isUsGift' एक कंप्यूटेड कॉलम है। फ़िल्टर अभिव्यक्ति को फिर से लिखें ताकि इसमें यह कॉलम शामिल न हो।

मैं एक गणना किए गए कॉलम पर फ़िल्टर किए गए सूचकांक कैसे बना सकता हूं?

या

क्या कोई वैकल्पिक उपाय है?


3
WHERE (sintMarketID = 2 AND strType = 'CARD' AND strTier1 LIKE 'GG%')यद्यपि आप एक फ़िल्टर्ड इंडेक्स बना सकते हैं ।
ypercube y

जवाबों:


21

दुर्भाग्य से SQL Server 2014 के रूप में, कोई बनाने की क्षमता नहीं है Filtered Index फ़िल्टर गणना जहां एक परिकलित कॉलम है (चाहे वह स्थायी हो या नहीं)।

एक कनेक्ट आइटम हुआ है2009 से खुला है, इसलिए कृपया आगे बढ़ें और इसके लिए मतदान करें। हो सकता है कि Microsoft इसे एक दिन ठीक कर देगा।

हारून बर्ट्रेंड का एक लेख है जिसमें फ़िल्टर किए गए अनुक्रमित के साथ कई अन्य मुद्दों को शामिल किया गया है ।


21

हालाँकि, आप एक निरंतर स्तंभ पर फ़िल्टर किए गए अनुक्रमणिका नहीं बना सकते हैं, एक काफी सरल समाधान है जिसे आप उपयोग करने में सक्षम हो सकते हैं।

एक परीक्षण के रूप में, मैंने एक IDENTITYकॉलम के साथ एक सरल तालिका बनाई है , और पहचान कॉलम के आधार पर एक निरंतर गणना कॉलम:

USE tempdb;

CREATE TABLE dbo.PersistedViewTest
(
    PersistedViewTest_ID INT NOT NULL
        CONSTRAINT PK_PersistedViewTest
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , SomeData VARCHAR(2000) NOT NULL
    , TestComputedColumn AS (PersistedViewTest_ID - 1) PERSISTED
);
GO

फिर, मैंने गणना कॉलम पर एक फिल्टर के साथ तालिका के आधार पर एक स्कीमा-बाउंड व्यू बनाया:

CREATE VIEW dbo.PersistedViewTest_View
WITH SCHEMABINDING
AS
SELECT PersistedViewTest_ID
    , SomeData 
    , TestComputedColumn
FROM dbo.PersistedViewTest
WHERE TestComputedColumn < CONVERT(INT, 27);

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

CREATE UNIQUE CLUSTERED INDEX IX_PersistedViewTest
ON dbo.PersistedViewTest_View(PersistedViewTest_ID);
GO

तालिका में कुछ परीक्षण डेटा डालें:

INSERT INTO dbo.PersistedViewTest (SomeData)
SELECT o.name + o1.name + o2.name
FROM sys.objects o
    CROSS JOIN sys.objects o1
    CROSS JOIN sys.objects o2;

दृश्य पर एक आँकड़े आइटम और एक सूचकांक बनाएँ:

CREATE STATISTICS ST_PersistedViewTest_View
ON dbo.PersistedViewTest_View(TestComputedColumn)
WITH FULLSCAN;

CREATE INDEX IX_PersistedViewTest_View_TestComputedColumn
ON dbo.PersistedViewTest_View(TestComputedColumn);

SELECTतालिका के विरुद्ध जारी किए गए कॉलम के साथ बयानों का प्रदर्शन अब स्वचालित रूप से निरंतर दृश्य का उपयोग कर सकता है , यदि क्वेरी ऑप्टिमाइज़र यह निर्धारित करता है कि ऐसा करने के लिए यह समझ में आता है:

SELECT pv.PersistedViewTest_ID
    , pv.TestComputedColumn
FROM dbo.PersistedViewTest pv
WHERE pv.TestComputedColumn = CONVERT(INT, 26)

उपरोक्त क्वेरी के लिए वास्तविक निष्पादन योजना परिणामों को वापस करने के लिए निरंतर दृश्य का उपयोग करने के लिए चुना गया क्वेरी ऑप्टिमाइज़र दिखाता है:

यहां छवि विवरण दर्ज करें

आपने WHEREउपर्युक्त खंड में स्पष्ट रूपांतरण देखा होगा । यह स्पष्ट CONVERT(INT, 26)क्वेरी ऑप्टिमाइज़र को क्वेरी द्वारा वापस आने वाली पंक्तियों की संख्या का अनुमान लगाने के लिए सांख्यिकी ऑब्जेक्ट का ठीक से उपयोग करने की अनुमति देता है। यदि हम क्वेरी को लिखते हैं WHERE pv.TestComputedColumn = 26, तो क्वेरी ऑप्टिमाइज़र ठीक से अनुमान नहीं लगा सकता है क्योंकि 26 को वास्तव में माना जाता हैTINY INT ; यह SQL सर्वर का कारण बने दृश्य का उपयोग नहीं कर सकता है। निहित रूपांतरण बहुत दर्दनाक हो सकते हैं, और यह तुलना और जुड़ने के लिए सही डेटा प्रकारों का लगातार उपयोग करने के लिए भुगतान करता है।

बेशक, स्कीमा बाइंडिंग का उपयोग करने के परिणामस्वरूप सभी मानक "गोच" उपरोक्त परिदृश्य पर लागू होते हैं; यह सभी परिदृश्यों में इस समाधान का उपयोग करने से रोक सकता है। उदाहरण के लिए, पहले स्कीमा बंधन को दृश्य से हटाए बिना बेस टेबल को संशोधित करना संभव नहीं होगा। ऐसा करने के लिए, आपको क्लस्टर इंडेक्स को दृश्य से निकालना होगा।

यदि आपके पास SQL ​​सर्वर एंटरप्राइज़ संस्करण नहीं है, तो क्वेरी ऑप्टिमाइज़र स्वचालित रूप से उन प्रश्नों के लिए स्थायी दृश्य का उपयोग नहीं करेगा, जो सीधे WITH (NOEXPAND)संकेत का उपयोग करते हुए दृश्य का संदर्भ नहीं देते हैं। गैर-एंटरप्राइज़ संस्करण संस्करणों में निरंतर दृश्य का उपयोग करने के लाभ का एहसास करने के लिए, आपको कुछ इस तरह से ऊपर दिए गए क्वेरी को फिर से लिखना होगा:

SELECT pv.PersistedViewTest_ID
    , pv.TestComputedColumn
FROM dbo.PersistedViewTest_View pv WITH (NOEXPAND)
WHERE pv.TestComputedColumn = CONVERT(INT, 26)

ऊपर दिए गए एंटरप्राइज़ संस्करण सीमा को इंगित करने के लिए इयान रिंगरोज़ और संकेत के लिए पॉल व्हाइट को धन्यवाद (NOEXPAND)

पॉल के इस जवाब में निरंतर विचारों के संबंध में क्वेरी ऑप्टिमाइज़र के बारे में कुछ दिलचस्प विवरण हैं।


आस-पास के काम से पता चलता है कि दृश्य पर एक संकुल सूचकांक और एक गैर-अनुक्रमित सूचकांक दोनों बनाया जाता है। क्या किसी कारण से अव्यवस्थित सूचकांक पर गैर-अनुक्रमित सूचकांक का उपयोग करना पड़ता है? या, गैर-अनुक्रमित सूचकांक अधिक प्रदर्शनकारी है? यदि क्वेरी में क्लस्टर किए गए इंडेक्स का उपयोग किया गया था, तो आंकड़े क्या दिखाएंगे?
बॉब ब्रायन

दिलचस्प सवाल, @busBryan - क्लस्टर इंडेक्स को देखने के लिए लगातार बनाए रखने के लिए आवश्यक है, हालांकि यह वास्तव में एक अद्वितीय इंडेक्स होने की आवश्यकता नहीं है। मैं किसी अन्य कॉलम पर दृश्य के क्लस्टर इंडेक्स को बना सकता था, जैसे कि TestComputedColumnइसके बजाय। हालाँकि, चूंकि संकुल अनुक्रमणिका में तालिका / दृश्य के लिए सभी डेटा शामिल हैं, मैंने निर्णय लिया कि संभवतः क्लस्टरिंग कुंजी के रूप में एक नीरस रूप से बढ़ती संख्या का उपयोग करना बेहतर होगा। ध्यान दें, मैंने वास्तव में उस दमन का परीक्षण नहीं किया था, और यह वास्तव में रेप्रो के कुछ रूपों के लिए गलत हो सकता है।
मैक्स वर्नोन

ध्यान दें, गैर-क्लस्टर इंडेक्स एक कवरिंग इंडेक्स नहीं है, और ऐसे किसी भी प्रश्न के रूप में, जो या तो व्यू या अंतर्निहित टेबल से फिल्टर, जॉइन करता है, या कॉलम को रिटर्न करता है या बेस टेबल के खिलाफ की-लुकअप ऑपरेशन करने की आवश्यकता होगी दृश्य। यह संभावना है कि वास्तविक दुनिया के परिदृश्य के लिए, मेरे जवाब के सीमित दायरे को और भी बेहतर प्रदर्शन को ध्यान में रखते हुए उजागर किया जा सकता है।
मैक्स वेरनॉन

4

से Create Indexऔर उसके whereखंड, यह संभव नहीं है:

कहाँ पे

सूचकांक में शामिल करने के लिए कौन सी पंक्तियों को निर्दिष्ट करके एक फ़िल्टर किए गए सूचकांक बनाता है। फ़िल्टर्ड इंडेक्स एक टेबल पर नॉनक्लेस्टेड इंडेक्स होना चाहिए। फ़िल्टर्ड इंडेक्स में डेटा पंक्तियों के लिए फ़िल्टर्ड आँकड़े बनाता है।

फ़िल्टर विधेय सरल तुलनात्मक तर्क का उपयोग करता है और एक संगणित कॉलम, यूडीटी कॉलम, एक स्थानिक डेटा प्रकार स्तंभ या एक पदानुक्रम डेटा प्रकार स्तंभ का संदर्भ नहीं दे सकता है। तुलना संचालकों के साथ NULL शाब्दिक का उपयोग करने की अनुमति नहीं है। इसके बजाय IS NULL और IS NOT NULL ऑपरेटरों का उपयोग करें।

स्रोत: MSDN


3
  • आपको एक कॉलम की आवश्यकता होती है जिसे फ़िल्टर किए गए इंडेक्स पर रखने के लिए गणना नहीं की जाती है।
  • आपको उस कॉलम में जाने के लिए मान की गणना करने की आवश्यकता है।

इससे पहले कि हम गणना किए गए कॉलम का उपयोग करते थे, जब भी पंक्ति बदल या डाली जाती थी, तो हम स्तंभ मान की गणना करने के लिए ट्रिगर का उपयोग करते थे।

(ट्रिगर को आइटम के PK को सम्मिलित करने / हटाने के लिए एक 2 टेबल से भी इस्तेमाल किया जा सकता है जो तब प्रश्नों में उपयोग किया गया था।)


3

यह मैक्स वेर्नन के काम को सुधारने के लिए एक प्रयास है । अपने समाधान में, वह दृश्य और आँकड़े ऑब्जेक्ट पर 2 अनुक्रमित का उपयोग करने का सुझाव देता है।

पहली अनुक्रमणिका को संकुलित किया जाता है, जो वास्तव में एक मेज पर एक गैर-अनुक्रमित सूचकांक के विपरीत आवश्यक है, एक त्रुटि उत्पन्न हो जाएगी यदि दृश्य पर एक गैर-अनुक्रमित सूचकांक का निर्माण पहले क्लस्टर किए गए सूचकांक के बिना करने का प्रयास किया जाता है।

2 सूचकांक एक गैर-अनुक्रमित सूचकांक है, जिसका उपयोग क्वेरी के पीछे सूचकांक के रूप में किया जाता है। उनके जवाब के टिप्पणी अनुभाग में, मैंने पूछा कि अगर एक गैर-अनुक्रमित सूचकांक के बजाय एक संकुल सूचकांक का उपयोग किया जाता है तो क्या होगा।

निम्नलिखित विश्लेषण इस प्रश्न का उत्तर देने का प्रयास करता है।

मैं उनके सटीक समान कोड का उपयोग कर रहा हूं, सिवाय इसके कि मैं दृश्य पर एक अस्पष्ट अनुक्रम नहीं बना रहा हूं।

मैं एक आँकड़े ऑब्जेक्ट भी नहीं बना रहा हूँ। यदि आप नीचे दिए गए कोड को दर्ज करने के लिए SQL सर्वर प्रबंधन स्टूडियो (SSMS) का साथ और उपयोग कर रहे हैं, तो आपको पता होना चाहिए कि आपको कुछ लाल स्क्वीजी लाइनें दिखाई दे सकती हैं - जो त्रुटियों की तरह दिखती हैं। ये (शायद) त्रुटियां नहीं हैं, लेकिन एक मुद्दे को अंतर्मुखी के साथ शामिल करते हैं।

आप या तो intellisense को अक्षम कर सकते हैं या केवल त्रुटियों को अनदेखा कर सकते हैं और कमांड चला सकते हैं। उन्हें त्रुटियों के बिना पूरा करना चाहिए।

-- Create the test table that uses a computed column.
USE tempdb;
CREATE TABLE dbo.PersistedViewTest
(
    PersistedViewTest_ID INT NOT NULL
    CONSTRAINT PK_PersistedViewTest
    PRIMARY KEY CLUSTERED
    IDENTITY(1,1)
    , SomeData VARCHAR(2000) NOT NULL
    , TestComputedColumn AS (PersistedViewTest_ID - 1) PERSISTED
);
GO

-- Insert some test data into the table.
INSERT INTO dbo.PersistedViewTest (SomeData)
SELECT o.name + o1.name + o2.name
FROM sys.objects o
    CROSS JOIN sys.objects o1
    CROSS JOIN sys.objects o2;
GO

निम्नलिखित क्वेरी योजना (कोई दृश्य / सूचकांक दृश्य के साथ) निम्न क्वेरी तालिका के विरुद्ध चलाने के बाद निर्मित होती है:

SELECT pv.PersistedViewTest_ID, pv.TestComputedColumn
FROM dbo.PersistedViewTest pv
WHERE pv.TestComputedColumn = CONVERT(INT, 26)
GO

यहां छवि विवरण दर्ज करें

यह तुलना करने के लिए एक आधार रेखा देता है। ध्यान दें कि क्वेरी पूरी होने के बाद, एक सांख्यिकी ऑब्जेक्ट बनाया गया था (_WA_Sys_00000003_1FCDBCEB)। PK_PersistedViewTest आँकड़े ऑब्जेक्ट तब बनाया गया था जब संकुल तालिका सूचकांक बनाया गया था।

इसके बाद, उस दृश्य पर फ़िल्टर किए गए दृश्य और क्लस्टर किए गए अनुक्रमणिका बनाए जाते हैं:

-- Create filtered view on the computed column.
CREATE VIEW dbo.PersistedViewTest_View
WITH SCHEMABINDING
AS
SELECT PersistedViewTest_ID, SomeData, TestComputedColumn
FROM dbo.PersistedViewTest
WHERE TestComputedColumn < CONVERT(INT, 27);
GO

-- Create unique clustered index to persist the values, including the computed column.
CREATE UNIQUE CLUSTERED INDEX IX_PersistedViewTest
ON dbo.PersistedViewTest_View(PersistedViewTest_ID);
GO

अब, क्वेरी को फिर से चलाने का प्रयास करें, लेकिन इस बार दृश्य के विरुद्ध:

SELECT pv.PersistedViewTest_ID, pv.TestComputedColumn
FROM dbo.PersistedViewTest_View pv
WHERE pv.TestComputedColumn = CONVERT(INT, 26)
GO

नई निष्पादन योजना अब है:

यहां छवि विवरण दर्ज करें

यदि नई योजना पर विश्वास किया जाना है, तो उस दृश्य पर दृश्य और क्लस्टर इंडेक्स को जोड़ने के बाद, आंकड़े इंगित करते हैं कि क्वेरी को निष्पादित करने के लिए आवश्यक समय अब ​​दोगुना हो गया है। इसके अलावा, ध्यान दें कि क्वेरी के चलने के बाद नए इंडेक्स का समर्थन करने के लिए कोई नई सांख्यिकी ऑब्जेक्ट नहीं बनाई गई थी, जो टेबल पर क्वेरी से अलग है।

क्वेरी योजना अभी भी बताती है कि क्वेरी के प्रदर्शन को बेहतर बनाने में एक गैर-अनुक्रमित सूचकांक का निर्माण काफी सहायक होगा। तो, क्या इसका मतलब यह है कि वांछित प्रदर्शन सुधार प्राप्त करने से पहले एक गैर-अनुक्रमित सूचकांक को दृश्य में जोड़ा जाना चाहिए? कोशिश करने के लिए एक आखिरी चीज है। "NOEXPAND" विकल्प का उपयोग करने के लिए क्वेरी को संशोधित करें:

SELECT pv.PersistedViewTest_ID, pv.TestComputedColumn
FROM dbo.PersistedViewTest_View pv WITH (NOEXPAND)
WHERE pv.TestComputedColumn = CONVERT(INT, 26)
GO

यह निम्नलिखित क्वेरी योजना में परिणाम देता है:

यहां छवि विवरण दर्ज करें

यह निष्पादन योजना काफी हद तक उसी के समान दिखती है जिसे मैक्स वर्नोन के उत्तर में दिए गए गैर-अनुक्रमित सूचकांक के साथ बनाया गया था। लेकिन, यह एक कम (nonclustered) सूचकांक और एक कम आँकड़े ऑब्जेक्ट के साथ किया जाता है।

यह पता चलता है कि NOEXPAND विकल्प को अनुक्रमित दृश्य का उचित उपयोग करने के लिए SQL सर्वर के एक्सप्रेस और मानक संस्करणों के साथ उपयोग किया जाना है। पॉल व्हाइट के पास एक उत्कृष्ट लेख है जो NOEXPAND विकल्प का उपयोग करने के लाभों पर विस्तार करता है। उन्होंने यह भी सिफारिश की है कि इस विकल्प का उपयोग एंटरप्राइज़ संस्करण के साथ किया जाए ताकि यह सुनिश्चित किया जा सके कि व्यू इंडेक्स द्वारा प्रदान की गई विशिष्टता का उपयोग ऑप्टिमाइज़र द्वारा किया जाता है।

उपरोक्त विश्लेषण SQL Sever 2014 के एक्सप्रेस संस्करण के साथ किया गया था। मैंने इसे SQL Server 2016 के डेवलपर संस्करण के साथ भी आज़माया। प्रदर्शन लाभ प्राप्त करने के लिए NOEXPAND विकल्प विकास संस्करण के साथ आवश्यक नहीं लगता है, लेकिन फिर भी इसकी अनुशंसा की जाती है। ।

5 महीने से भी कम समय पहले, Microsoft ने डेवलपर संस्करणों को निःशुल्क बनाया था । लाइसेंस केवल विकास के लिए उपयोग को प्रतिबंधित करता है, जिसका अर्थ है कि डेटाबेस का उत्पादन वातावरण में उपयोग नहीं किया जा सकता है। इसलिए, यदि आप मेमोरी ऑप्टिमाइज़्ड टेबल, एन्क्रिप्शन, आर, इत्यादि का परीक्षण करना चाहते हैं तो अब आपके पास नो-लाइसेंस बहाना है। मैंने इसे सफलतापूर्वक अपने कंप्यूटर पर साइड SQL सर्वर 2014 एक्सप्रेस के साथ कुछ मुद्दों पर स्थापित किया है।

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