द्वितीयक चयनात्मक सूचकांक का उपयोग क्यों नहीं किया जाता है, जहां खंड) मान ’() पर फिल्टर करता है?


13

सेट अप:

create table dbo.T
(
  ID int identity primary key,
  XMLDoc xml not null
);

insert into dbo.T(XMLDoc)
select (
       select N.Number
       for xml path(''), type
       )
from (
     select top(10000) row_number() over(order by (select null)) as Number
     from sys.columns as c1, sys.columns as c2
     ) as N;

प्रत्येक पंक्ति के लिए नमूना XML:

<Number>314</Number>

क्वेरी के लिए कार्य Tनिर्दिष्ट मान के साथ पंक्तियों की संख्या को गिनना है <Number>

ऐसा करने के दो स्पष्ट तरीके हैं:

select count(*)
from dbo.T as T
where T.XMLDoc.value('/Number[1]', 'int') = 314;

select count(*)
from dbo.T as T
where T.XMLDoc.exist('/Number[. eq 314]') = 1;

यह पता चला कि value()और exists()काम करने के लिए चयनात्मक XML सूचकांक के लिए दो अलग-अलग पथ परिभाषाओं की आवश्यकता है।

create selective xml index SIX_T on dbo.T(XMLDoc) for
(
  pathSQL = '/Number' as sql int singleton,
  pathXQUERY = '/Number' as xquery 'xs:double' singleton
);

sqlसंस्करण के लिए है value()और xqueryसंस्करण के लिए है exist()

आप सोच सकते हैं कि इस तरह का एक सूचकांक आपको एक अच्छी तलाश के साथ एक योजना देगा लेकिन चयनात्मक XML इंडेक्स को सिस्टम टेबल के प्राथमिक कुंजी के साथ सिस्टम टेबल के प्रमुख कुंजी के Tरूप में लागू किया जाता है । निर्दिष्ट पथ उस तालिका में विरल स्तंभ हैं। यदि आप परिभाषित रास्तों के वास्तविक मूल्यों का एक सूचकांक चाहते हैं, तो आपको प्रत्येक पथ अभिव्यक्ति के लिए एक माध्यमिक चयनात्मक सूचकांक बनाने की आवश्यकता है।

create xml index SIX_T_pathSQL on dbo.T(XMLDoc)
  using xml index SIX_T for (pathSQL);

create xml index SIX_T_pathXQUERY on dbo.T(XMLDoc)
  using xml index SIX_T for (pathXQUERY);

exist()सिलेक्टिव XML इंडेक्स के लिए सिस्टम टेबल में एक महत्वपूर्ण लुकअप के बाद सेकेंडरी एक्सएमएल इंडेक्स में एक खोज की क्वेरी प्लान करता है (न जाने क्यों इसकी जरूरत है) और अंतिम रूप Tसे यह सुनिश्चित करने के लिए इसमें लुकअप होता है कि वास्तव में हैं वहाँ पंक्तियाँ। अंतिम भाग आवश्यक है क्योंकि सिस्टम टेबल के बीच कोई विदेशी कुंजी बाधा नहीं है और T

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

value()क्वेरी के लिए योजना इतनी अच्छी नहीं है। यह Tनेस्टर्ड लूप्स के साथ एक क्लस्टर्ड इंडेक्स स्कैन करता है, जो कि स्पार्स कॉलम से वैल्यू पाने के लिए इंटरनल टेबल पर एक सीक के साथ जुड़ता है और आखिर में वैल्यू पर फिल्टर करता है।

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

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

जहां क्लॉज फिल्टर होता है, वहां माध्यमिक चयनात्मक सूचकांक का उपयोग क्यों नहीं किया जाता है value()?

अपडेट करें:

प्रश्न शब्दार्थ से भिन्न हैं। यदि आप मान के साथ एक पंक्ति जोड़ते हैं

<Number>313</Number>
<Number>314</Number>` 

exist()संस्करण 2 पंक्तियाँ जाएगी और values()क्वेरी 1 पंक्ति में गिना जाएगा। लेकिन इंडेक्स परिभाषाओं के साथ जैसा कि वे यहां निर्दिष्ट हैं, singletonनिर्देश SQL सर्वर का उपयोग करके आपको कई <Number>तत्वों के साथ एक पंक्ति को जोड़ने से रोका जाएगा ।

हालांकि , संकलक की गारंटी के values()बिना फ़ंक्शन का उपयोग करने की अनुमति नहीं [1]देता है कि हम केवल एक ही मूल्य प्राप्त करेंगे। यही कारण [1]है कि हमारे पास value()योजना में एक टॉप एन सॉर्ट है ।

लगता है कि मैं यहाँ एक उत्तर पर बंद कर रहा हूँ ...

जवाबों:


11

singletonअनुक्रमणिका की पथ अभिव्यक्ति में घोषणा लागू होती है कि आप कई <Number>तत्वों को नहीं जोड़ सकते हैं लेकिन XQuery कंपाइलर value()फ़ंक्शन में अभिव्यक्ति की व्याख्या करते समय इसे ध्यान में नहीं रखते हैं । आपको [1]SQL सर्वर को खुश करने के लिए निर्दिष्ट करना होगा । स्कीमा के साथ टाइप किए गए XML का उपयोग करना उस के साथ मदद नहीं करता है। और उस SQL ​​सर्वर के कारण एक ऐसी क्वेरी का निर्माण होता है जो कुछ ऐसा उपयोग करता है जिसे "लागू करें" पैटर्न कहा जा सकता है।

प्रदर्शित करने के लिए सबसे सरल है XML का उपयोग नियमित तालिकाओं के बजाय उस क्वेरी का अनुकरण करना जो हम वास्तव में Tऔर आंतरिक तालिका के खिलाफ कर रहे हैं ।

यहां आंतरिक तालिका के लिए वास्तविक तालिका के रूप में सेटअप है।

create table dbo.xml_sxi_table
(
  pk1 int not null,
  row_id int,
  path_1_id varbinary(900),
  pathSQL_1_sql_value int,
  pathXQUERY_2_value float
);

go

create clustered index SIX_T on xml_sxi_table(pk1, row_id);
create nonclustered index SIX_pathSQL on xml_sxi_table(pathSQL_1_sql_value) where path_1_id is not null;
create nonclustered index SIX_T_pathXQUERY on xml_sxi_table(pathXQUERY_2_value) where path_1_id is not null;

go

insert into dbo.xml_sxi_table(pk1, row_id, path_1_id, pathSQL_1_sql_value, pathXQUERY_2_value)
select T.ID, 1, T.ID, T.ID, T.ID
from dbo.T;

जगह में दोनों तालिकाओं के साथ आप exist()क्वेरी के बराबर निष्पादित कर सकते हैं ।

select count(*)
from dbo.T
where exists (
             select *
             from dbo.xml_sxi_table as S
             where S.pk1 = T.ID and
                   S.pathXQUERY_2_value = 314 and
                   S.path_1_id is not null
             );

value()क्वेरी का समकक्ष इस तरह दिखेगा।

select count(*)
from dbo.T
where (
      select top(1) S.pathSQL_1_sql_value
      from dbo.xml_sxi_table as S
      where S.pk1 = T.ID and
            S.path_1_id is not null
      order by S.path_1_id
      ) = 314;

top(1)और order by S.path_1_idअपराधी है और यह है [1]xpath एक्सप्रेशन इसके लिए जिम्मेदार है कि में।

मुझे नहीं लगता कि Microsoft के लिए आंतरिक तालिका की वर्तमान संरचना के साथ इसे ठीक करना संभव है, भले ही आपको फ़ंक्शन [1]से बाहर निकलने की अनुमति दी गई हो values()। उन्हें शायद हर पथ अभिव्यक्ति के लिए अद्वितीय अवरोधों के साथ प्रत्येक पथ अभिव्यक्ति के लिए कई आंतरिक तालिकाओं का निर्माण करना होगा ताकि ऑप्टिमाइज़र के लिए यह सुनिश्चित हो सके कि <number>प्रत्येक पंक्ति के लिए केवल एक तत्व हो सकता है । यकीन नहीं है कि वास्तव में ऑप्टिमाइज़र के लिए "लागू पैटर्न से बाहर तोड़ने" के लिए पर्याप्त होगा।

आपके लिए जो इस मजेदार और दिलचस्प के बारे में सोचते हैं और चूंकि आप अभी भी इसे पढ़ रहे हैं।

आंतरिक तालिका की संरचना को देखने के लिए कुछ प्रश्न।

select T.name, 
       T.internal_type_desc, 
       object_name(T.parent_id) as parent_table_name
from sys.internal_tables as T
where T.parent_id = object_id('T');

select C.name as column_name, 
       C.column_id,
       T.name as type_name,
       C.max_length,
       C.is_sparse,
       C.is_nullable
from sys.columns as C
  inner join sys.types as T
    on C.user_type_id = T.user_type_id
where C.object_id in (
                     select T.object_id 
                     from sys.internal_tables as T 
                     where T.parent_id = object_id('T')
                     )
order by C.column_id;

select I.name as index_name,
       I.type_desc,
       I.is_unique,
       I.filter_definition,
       IC.key_ordinal,
       C.name as column_name, 
       C.column_id,
       T.name as type_name,
       C.max_length,
       I.is_unique,
       I.is_unique_constraint
from sys.indexes as I
  inner join sys.index_columns as IC
    on I.object_id = IC.object_id and
       I.index_id = IC.index_id
  inner join sys.columns as C
    on IC.column_id = C.column_id and
       IC.object_id = C.object_id
  inner join sys.types as T
    on C.user_type_id = T.user_type_id
where I.object_id in (
                     select T.object_id 
                     from sys.internal_tables as T 
                     where T.parent_id = object_id('T')
                     );
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.