ROW_NUMBER () OVER (पार्टिशन बाय B, A ORDER BY C) इंडेक्स (A, B, C) पर इंडेक्स का उपयोग नहीं करता है


12

इन दो कार्यों पर विचार करें:

ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C)

ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C)

जहां तक ​​मैं समझता हूं, वे ठीक उसी परिणाम का उत्पादन करते हैं। दूसरे शब्दों में, जिस क्रम में आप PARTITION BYखंड में कॉलम सूचीबद्ध करते हैं, वह मायने नहीं रखता।

यदि कोई सूचकांक है, तो (A,B,C)मुझे उम्मीद है कि दोनों संस्करणों में इस सूचकांक का उपयोग करने के लिए ऑप्टिमाइज़र।

लेकिन, आश्चर्यजनक रूप से, आशावादी ने दूसरे संस्करण में एक अतिरिक्त स्पष्ट क्रमबद्ध करने का फैसला किया।

मैंने इसे SQL Server 2008 स्टैंडर्ड और SQL सर्वर 2014 एक्सप्रेस पर देखा है।

यहां एक पूरी स्क्रिप्ट है जिसे मैं इसे पुन: पेश करता था।

Microsoft SQL Server 2014 पर परीक्षण किया गया - 12.0.2000.8 (X64) 20 फरवरी 2014 20:04:26 कॉपीराइट (c) Microsoft निगम एक्सप्रेस संस्करण (64-बिट) Windows NT 6.1 पर (बिल्ड 7601: सर्विस पैक 1)

और Microsoft SQL सर्वर 2014 (SP1-CU7) (KB3162659) - 12.0.4459.0 (X64) मई 27 2016 15:33:17 कॉपीराइट (c) Microsoft NT NT पर Microsoft कॉर्पोरेशन एक्सप्रेस संस्करण (64-बिट) 6.1 निर्मित (अंतर्निहित C01): सेवा पैक 1)

पुराने और नए दोनों कार्डिनैलिटी एस्टीमेटर के साथ उपयोग करके OPTION (QUERYTRACEON 9481)और OPTION (QUERYTRACEON 2312)

तालिका, सूचकांक, नमूना डेटा सेट करें

CREATE TABLE [dbo].[T](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [A] [int] NOT NULL,
    [B] [int] NOT NULL,
    [C] [int] NOT NULL,
    CONSTRAINT [PK_T] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, 
STATISTICS_NORECOMPUTE = OFF, 
IGNORE_DUP_KEY = OFF, 
ALLOW_ROW_LOCKS = ON, 
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IX_ABC] ON [dbo].[T]
(
    [A] ASC,
    [B] ASC,
    [C] ASC
)WITH (PAD_INDEX = OFF, 
STATISTICS_NORECOMPUTE = OFF, 
SORT_IN_TEMPDB = OFF, 
DROP_EXISTING = OFF, 
ONLINE = OFF, 
ALLOW_ROW_LOCKS = ON, 
ALLOW_PAGE_LOCKS = ON)
GO

INSERT INTO [dbo].[T] ([A],[B],[C]) VALUES
(10, 20, 30),
(10, 21, 31),
(10, 21, 32),
(10, 21, 33),
(11, 20, 34),
(11, 21, 35),
(11, 21, 36),
(12, 20, 37),
(12, 21, 38),
(13, 21, 39);

प्रश्नों

SELECT -- AB
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C) AS rnAB
FROM T
ORDER BY C
OPTION(RECOMPILE);

SELECT -- BA
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C) AS rnBA
FROM T
ORDER BY C
OPTION(RECOMPILE);

SELECT -- both
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C) AS rnAB
    ,ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C) AS rnBA
FROM T
ORDER BY C
OPTION(RECOMPILE);

निष्पादन की योजना

ए, बी द्वारा विभाजन

एबी

बी, ए द्वारा विभाजन

बी 0 ए 0

दोनों

दोनों

जैसा कि आप देख सकते हैं, दूसरी योजना में एक अतिरिक्त सॉर्ट है। यह बी, ए, सी द्वारा आदेश देता है। ऑप्टिमाइज़र, जाहिरा तौर पर, यह महसूस करने के लिए पर्याप्त स्मार्ट नहीं है कि डेटा के PARTITION BY B,Aरूप में समान है PARTITION BY A,Bऔर फिर से सॉर्ट करता है।

दिलचस्प बात यह है कि तीसरी क्वेरी में इसके दोनों वेरिएंट हैं ROW_NUMBERऔर कोई अतिरिक्त सॉर्ट नहीं है! योजना पहले क्वेरी के लिए समान है। (अनुक्रम परियोजना में अतिरिक्त स्तंभ के लिए आउटपुट सूची में अतिरिक्त अभिव्यक्ति है, लेकिन कोई अतिरिक्त क्रम नहीं है)। इसलिए, इस अधिक जटिल मामले में, आशावादी को यह महसूस करने के लिए पर्याप्त स्मार्ट दिखाई दिया कि वह PARTITION BY B,Aजैसा है वैसा ही है PARTITION BY A,B

पहले और तीसरे प्रश्न में इंडेक्स स्कैन ऑपरेटर के पास प्रॉपर्टी ऑर्डर की गई है: यह सही है, दूसरी क्वेरी में यह गलत है।

और भी दिलचस्प, अगर मैं इस तरह से तीसरी क्वेरी फिर से लिखता हूं (दो कॉलम स्वैप करें):

SELECT -- both
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C) AS rnBA
    ,ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C) AS rnAB
FROM T
ORDER BY C
OPTION(RECOMPILE);

फिर अतिरिक्त सॉर्ट फिर से प्रकट होता है!

क्या कोई प्रकाश को बहा सकता है? यहाँ अनुकूलक में क्या चल रहा है?


टिप्पणियाँ संग्रहीत
पॉल व्हाइट 9

जवाबों:


2

ऐसा लगता है कि जब तक आप इसके डेवलपर हैं, तब तक इस सवाल का कोई अच्छा "जवाब" नहीं है कि "ऑप्टिमाइज़र में क्या चल रहा है"।

मैं यहाँ टिप्पणियों को एक साथ रखूँगा।

कुल मिलाकर, ऐसा लगता है कि इसे बग कहना कठिन होगा, क्योंकि क्वेरी का अंतिम परिणाम सही है। कुछ मामलों में निष्पादन योजना सरल नहीं है। ypercuber , मार्टिन स्मिथ और आरोन बर्ट्रेंड इसे "मिस्ड ऑप्टिमाइज़ेशन" कहते हैं।

  • लगता है GROUP BY a,bऔर GROUP BY b,aसमान योजनाओं की पैदावार लेकिन PARTITION BYएक ही परिवर्तन का उपयोग नहीं कर सकते

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

  • हाँ, यह एक और चूक अनुकूलन की तरह लगता है, और वहाँ बहुत सारे हैं। ऑप्टिमाइज़र मनुष्यों द्वारा लिखा गया है और सही नहीं है


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


मेरे लिए आशावादी की इस ख़ासियत को ध्यान में रखना व्यावहारिक परिणाम होगा। PARTITION BYविंडो फ़ंक्शन का उपयोग करते समय हमेशा उस क्रम से मेल खाने का प्रयास करें जिसमें आप उस क्रम में कॉलम PARTITION BYको सूचीबद्ध करते हैं जिसमें वे सूचकांक में सूचीबद्ध होते हैं। भले ही इससे फर्क न पड़े।

इस एहतियात का दूसरा पक्ष यह है कि जब आप अपने अनुक्रमितों की समीक्षा करते हैं और सूचकांक परिभाषा में चारों ओर कुछ कॉलम स्वैप करने का निर्णय लेते हैं। ध्यान रखें कि आप अनजाने में कुछ मौजूदा प्रश्नों को प्रभावित कर सकते हैं जो प्रतीत नहीं होने चाहिए। यह वास्तव में है कि मैंने कैसे आशावादी की इस विशिष्टता को देखा।

यदि आप नहीं करते हैं, तो हो सकता है कि ऑप्टिमाइज़र अपनी पूरी क्षमता के लिए सूचकांक का उपयोग करने में सक्षम न हो। भले ही ऑप्टिमाइज़र एक इष्टतम योजना का चयन करता है, इस तरह की योजना क्वेरी में थोड़ी सी निर्दोष परिवर्तन के साथ कम इष्टतम में बदल सकती है, जैसे कि SELECTबयान में कॉलम के क्रम को बदलना ।

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