क्यों एक समूह द्वारा एक के बिना एक समूह के साथ काफी तेजी से एक क्वेरी क्वेरी है?


12

मैं बस उत्सुक हूं कि एक समग्र क्वेरी GROUP BYबिना किसी खंड के इतनी तेजी से क्यों चलती है ।

उदाहरण के लिए, इस क्वेरी को चलने में लगभग 10 सेकंड लगते हैं

SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1

जबकि यह एक सेकंड से भी कम समय लेता है

SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
GROUP BY CreatedDate

CreatedDateइस मामले में केवल एक ही है , इसलिए समूहीकृत क्वेरी उसी परिणाम को लौटाती है जैसे कि एक अनग्रुप्ड।

मैंने देखा कि दो प्रश्नों के लिए निष्पादन योजनाएं अलग हैं - दूसरी क्वेरी समानांतरवाद का उपयोग करती है जबकि पहली क्वेरी नहीं करती है।

Query1 निष्पादन योजना Query2 निष्पादन योजना

यह SQL सर्वर के लिए एक समग्र क्वेरी का मूल्यांकन करने के लिए सामान्य है अगर यह एक समूह द्वारा खंड नहीं है? और क्या ऐसा कुछ है जो मैं GROUP BYक्लॉज का उपयोग किए बिना 1 क्वेरी के प्रदर्शन को बेहतर बनाने के लिए कर सकता हूं ?

संपादित करें

मैंने अभी सीखा कि मैं OPTION(querytraceon 8649)समानांतरवाद की लागत उपरि को 0 पर सेट करने के लिए उपयोग कर सकता हूं , जो क्वेरी को कुछ समानता का उपयोग करता है और रनटाइम को 2 सेकंड तक कम कर देता है, हालांकि मुझे नहीं पता कि इस क्वेरी संकेत का उपयोग करने के लिए कोई डाउनसाइड है या नहीं।

SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
OPTION(querytraceon 8649)

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

मैं अभी भी एक छोटे रनटाइम को पसंद करूंगा क्योंकि क्वेरी उपयोगकर्ता चयन पर एक मूल्य को पॉप्युलेट करने के लिए है, इसलिए आदर्श रूप से तत्काल होना चाहिए जैसे समूह क्वेरी है। अभी मैं सिर्फ अपनी क्वेरी लपेट रहा हूं, लेकिन मुझे पता है कि यह वास्तव में एक आदर्श समाधान नहीं है।

SELECT Min(CreatedDate)
FROM
(
    SELECT Min(CreatedDate) as CreatedDate
    FROM MyTable WITH (NOLOCK) 
    WHERE SomeIndexedValue = 1
    GROUP BY CreatedDate
) as T

# 2 संपादित करें

अधिक जानकारी के लिए मार्टिन के अनुरोध के जवाब में :

दोनों CreatedDateऔर SomeIndexedValueउन पर एक अलग गैर-अद्वितीय, गैर-संकुल सूचकांक है। SomeIndexedValueवास्तव में एक varchar (7) फ़ील्ड है, भले ही यह एक संख्यात्मक मान संग्रहीत करता है जो किसी अन्य तालिका के PK (int) को इंगित करता है। डेटाबेस में दो तालिकाओं के बीच संबंध परिभाषित नहीं है। मैं डेटाबेस को बिल्कुल भी बदलने वाला नहीं हूँ, और केवल क्वेरीज़ लिख सकता हूँ जो डेटा को क्वेरी करता है।

MyTable3 मिलियन से अधिक रिकॉर्ड शामिल हैं, और प्रत्येक रिकॉर्ड को एक समूह सौंपा गया है जो इसका ( SomeIndexedValue) है। समूह 1 से 200,000 रिकॉर्ड से कहीं भी हो सकते हैं

जवाबों:


8

ऐसा लगता है कि यह संभवत CreatedDate: सबसे कम से लेकर उच्चतम तक एक सूचकांक का अनुसरण कर रहा है और SomeIndexedValue = 1विधेय का मूल्यांकन करने के लिए लुकअप कर रहा है।

जब यह पहली मिलान पंक्ति को पाता है, तो यह किया जाता है, लेकिन यह इस तरह की पंक्ति को खोजने से पहले यह अपेक्षा करता है कि इसकी अपेक्षा कई अधिक लुकअप हो सकती है (यह मानता है कि विधेय से मेल खाती पंक्तियाँ बेतरतीब ढंग से तिथि के अनुसार वितरित की जाती हैं।)

इसी तरह के मुद्दे के लिए मेरा जवाब यहां देखें

इस क्वेरी के लिए आदर्श इंडेक्स एक होगा SomeIndexedValue, CreatedDate। यह मानते हुए कि आप इसे शामिल नहीं कर सकते हैं या कम से कम अपने मौजूदा सूचकांक को शामिल कॉलम के रूप में SomeIndexedValueकवर पर बना सकते हैं, CreatedDateतो आप क्वेरी को फिर से लिखने की कोशिश कर सकते हैं:

SELECT MIN(DATEADD(DAY, 0, CreatedDate)) AS CreatedDate
FROM MyTable
WHERE SomeIndexedValue = 1

उस विशेष योजना का उपयोग करने से रोकने के लिए।


2

क्या हम MAXDOP के लिए नियंत्रण कर सकते हैं और एक ज्ञात तालिका चुन सकते हैं, जैसे, AdventureWorks.Product.TransactionHistory?

जब मैं आपके सेटअप का उपयोग करके दोहराता हूं

--#1
SELECT MIN(TransactionDate) 
FROM AdventureWorks.Production.TransactionHistory
WHERE TransactionID = 100001 
OPTION( MAXDOP 1) ;

--#2
SELECT MIN(TransactionDate) 
FROM AdventureWorks.Production.TransactionHistory
WHERE TransactionID = 100001 
GROUP BY TransactionDate
OPTION( MAXDOP 1) ;
GO 

लागत समान हैं।

एक तरफ के रूप में, मैं आपकी अनुक्रमणित मूल्य पर एक सूचकांक की तलाश (यह होता है) की उम्मीद करेंगे; अन्यथा, आप स्ट्रीम समुच्चय के बजाय हैश मैच देखने जा रहे हैं। आप गैर-संकुलित अनुक्रमित के साथ प्रदर्शन में सुधार कर सकते हैं जिसमें वे मूल्य शामिल होते हैं जिन्हें आप एकत्र कर रहे हैं या एक अनुक्रमित दृश्य बनाते हैं जो आपके समुच्चय को स्तंभों के रूप में परिभाषित करता है। तब आप एक अनुक्रमित आईडी द्वारा एक संकुल सूचकांक को मारेंगे, जिसमें आपके एकत्रीकरण शामिल हैं। SQL Standard में, आप केवल दृश्य (NOEXPAND) संकेत का उपयोग कर सकते हैं।

एक उदाहरण (मैं MIN का उपयोग नहीं करता हूं, क्योंकि यह अनुक्रमित दृश्यों में काम नहीं करता है):

USE AdventureWorks ;
GO

-- Covering Index with Include
CREATE INDEX IX_CoverAndInclude
ON Production.TransactionHistory(TransactionDate) 
INCLUDE (Quantity) ;
GO

-- Indexed View
CREATE VIEW dbo.SumofQtyByTransDate
    WITH SCHEMABINDING
AS
SELECT 
      TransactionDate 
    , COUNT_BIG(*) AS NumberOfTransactions
    , SUM(Quantity) AS TotalTransactions
FROM Production.TransactionHistory
GROUP BY TransactionDate ;
GO

CREATE UNIQUE CLUSTERED INDEX SumofAllChargesIndex 
    ON dbo.SumofQtyByTransDate (TransactionDate) ;  
GO


--#1
SELECT SUM(Quantity) 
FROM AdventureWorks.Production.TransactionHistory 
WITH (INDEX(0))
WHERE TransactionID = 100001 
OPTION( MAXDOP 1) ;

--#2
SELECT SUM(Quantity)  
FROM AdventureWorks.Production.TransactionHistory 
WITH (INDEX(IX_CoverAndInclude))
WHERE TransactionID = 100001 
GROUP BY TransactionDate
OPTION( MAXDOP 1) ;
GO 

--#3
SELECT SUM(Quantity)  
FROM AdventureWorks.Production.TransactionHistory
WHERE TransactionID = 100001 
GROUP BY TransactionDate
OPTION( MAXDOP 1) ;
GO

MAXDOPसमानांतरता की अधिकतम डिग्री सेट करता है, जो क्वेरी का उपयोग करने वाले प्रोसेसर की संख्या को सीमित कर रहा है। यह मूल रूप से 2 क्वेरी को 1 के रूप में धीमी गति से चलाता है, क्योंकि यह समानांतरता का उपयोग करने की क्षमताओं को हटा रहा है, जो कि मैं नहीं चाहता।
राचेल

@ राचेल मैं सहमत हूँ; जब तक हम कुछ बुनियादी नियमों को निर्धारित नहीं करते, हम किसी भी चीज़ की तुलना नहीं कर सकते। मैं आसानी से एक पर चलने वाले एक धागे के लिए 64 कोर पर चलने वाली समानांतर प्रक्रिया की तुलना नहीं कर सकता। अंत में, मुझे आशा है कि हमारे सभी मशीनों में कम से कम एक तार्किक CPU = -)
ooutwire

0

मेरी राय में समस्या का कारण यह है कि sql सर्वर ऑप्टिमाइज़र BEST प्लान की तलाश में नहीं है, बल्कि वह एक अच्छी योजना की तलाश कर रहा है, जैसा कि इस तथ्य से स्पष्ट है कि समानता को मजबूर करने के बाद क्वेरी को बहुत तेजी से निष्पादित किया गया, कुछ ऐसा जो ऑप्टिमाइज़र के पास था खुद पर नहीं किया।

मैंने कई स्थितियों को भी देखा है, जहां क्वेरी को एक अलग प्रारूप में फिर से लिखना समानांतर बनाने के बीच का अंतर था (उदाहरण के लिए हालांकि SQL पर अधिकांश लेख पैरामीटर की सिफारिश करते हैं मैंने पाया है कि कभी-कभी यह भी कारण बनता है कि जब पैरामीटर सूँघते थे तब भी समानांतर करने के लिए noy एक समान नहीं थी - समानांतर एक, या UNION ALL के साथ दो प्रश्नों के संयोजन कभी-कभी समानांतरकरण को समाप्त कर सकते हैं)।

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

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