इन दो कार्यों पर विचार करें:
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);
निष्पादन की योजना
ए, बी द्वारा विभाजन
बी, ए द्वारा विभाजन
दोनों
जैसा कि आप देख सकते हैं, दूसरी योजना में एक अतिरिक्त सॉर्ट है। यह बी, ए, सी द्वारा आदेश देता है। ऑप्टिमाइज़र, जाहिरा तौर पर, यह महसूस करने के लिए पर्याप्त स्मार्ट नहीं है कि डेटा के 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);
फिर अतिरिक्त सॉर्ट फिर से प्रकट होता है!
क्या कोई प्रकाश को बहा सकता है? यहाँ अनुकूलक में क्या चल रहा है?