SQL Server 2005 पर कई स्तंभों को न्यूनतम करने के लिए सबसे कुशल तरीका क्या है?


29

मैं ऐसी स्थिति में हूं जहां मैं 6 कॉलम से न्यूनतम मूल्य प्राप्त करना चाहता हूं।

मैंने इसे पूरा करने के लिए अब तक तीन तरीके खोजे हैं, लेकिन मुझे इन तरीकों के प्रदर्शन से चिंता है और यह जानना चाहूंगा कि प्रदर्शन के लिए कौन सा बेहतर होगा।

पहली विधि एक बड़े मामले के बयान का उपयोग करना है । यहां 3 कॉलम के साथ एक उदाहरण दिया गया है, ऊपर दिए गए लिंक में उदाहरण के आधार पर। मेरा केस स्टेटमेंट बहुत लंबा होगा क्योंकि मैं 6 कॉलम देख रहा हूँ।

Select Id,
       Case When Col1 <= Col2 And Col1 <= Col3 Then Col1
            When Col2 <= Col3 Then Col2 
            Else Col3
            End As TheMin
From   MyTable

दूसरा विकल्प UNIONकई चुनिंदा बयानों के साथ ऑपरेटर का उपयोग करना है । मैं इसे एक यूडीएफ में रखूंगा जो एक आईडी पैरामीटर को स्वीकार करता है।

select Id, dbo.GetMinimumFromMyTable(Id)
from MyTable

तथा

select min(col)
from
(
    select col1 [col] from MyTable where Id = @id
    union all
    select col2 from MyTable where Id = @id
    union all
    select col3 from MyTable where Id = @id
) as t

और जो तीसरा विकल्प मुझे मिला वह UNPIVOT ऑपरेटर का उपयोग करना था , जिसे मैं अभी तक अस्तित्व में नहीं जानता था

with cte (ID, Col1, Col2, Col3)
as
(
    select ID, Col1, Col2, Col3
    from TestTable
)
select cte.ID, Col1, Col2, Col3, TheMin from cte
join
(
    select
        ID, min(Amount) as TheMin
    from 
        cte 
        UNPIVOT (Amount for AmountCol in (Col1, Col2, Col3)) as unpvt
    group by ID
) as minValues
on cte.ID = minValues.ID

तालिका के आकार, और आवृत्ति के कारण जिसमें यह तालिका क्वेरी की गई और अद्यतन की गई है, मैं उन प्रदर्शन प्रभावों के बारे में चिंतित हूं जो इन क्वेरीज़ डेटाबेस पर होंगे।

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

एकाधिक स्तंभों में से न्यूनतम प्राप्त करने का प्रयास करते समय इनमें से कौन सी विधि बेहतर है? या फिर एक और बेहतर तरीका है जो मुझे नहीं पता है?

मैं SQL Server 2005 का उपयोग कर रहा हूं

नमूना डेटा और परिणाम

यदि मेरे डेटा में इस तरह के रिकॉर्ड हैं:

Id Col1 Col2 Col3 Col4 Col5 Col6
1 3 4 0 2 1 5
२ २ ६ १० ५। ९
3 1 1 2 3 4 5
४ ९ ५ ४ ६। ९

अंतिम परिणाम होना चाहिए

आईडी मान
१ ०
२ २
३ १
४ ४

जवाबों:


22

मैंने सभी 3 विधियों के प्रदर्शन का परीक्षण किया, और यहाँ मैंने जो पाया:

  • 1 रिकॉर्ड: कोई ध्यान देने योग्य अंतर नहीं
  • 10 रिकॉर्ड: कोई ध्यान देने योग्य अंतर नहीं
  • 1,000 रिकॉर्ड: कोई ध्यान देने योग्य अंतर नहीं
  • 10,000 रिकॉर्ड: UNIONउपश्रेणी थोड़ी धीमी थी। CASE WHENक्वेरी एक छोटे से तेज है UNPIVOTएक।
  • 100,000 रिकॉर्ड: UNIONसबक्वेरी काफी धीमी है, लेकिन UNPIVOTक्वेरी एक छोटे से अधिक तेजी से हो जाता है CASE WHENक्वेरी
  • 500,000 रिकॉर्ड: UNIONसबक्वेरी अभी भी काफी धीमी है, लेकिन क्वेरी की UNPIVOTतुलना में बहुत तेज हो जाती हैCASE WHEN

तो अंतिम परिणाम लगता है

  • छोटे रिकॉर्ड सेट के साथ बात करने के लिए पर्याप्त अंतर प्रतीत नहीं होता है। जो कुछ भी पढ़ने और बनाए रखने में सबसे आसान है, उसका उपयोग करें।

  • एक बार जब आप बड़े रिकॉर्ड सेट में आने लगते हैं, तो UNION ALLउपनगर अन्य दो तरीकों की तुलना में खराब प्रदर्शन करना शुरू कर देता है।

  • CASEबयान प्रदर्शन एक निश्चित बिंदु तक सबसे अच्छा ऊपर (मेरे मामले में, चारों ओर 100k पंक्तियों), और जो बात UNPIVOTक्वेरी सबसे अच्छा प्रदर्शन क्वेरी हो जाता है

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

मैंने मिकेल के उत्तर का उपयोग करके कुछ परीक्षण भी चलाए ; हालांकि, यह अन्य रिकॉर्ड आकार के लिए यहां अन्य सभी तरीकों की तुलना में धीमा था। एकमात्र अपवाद यह था कि यह UNION ALLबहुत बड़े रिकॉर्ड आकार के लिए क्वेरी से बेहतर था । मुझे यह तथ्य पसंद है कि यह सबसे छोटे मूल्य के अतिरिक्त कॉलम नाम को दिखाता है।

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


6

सबसे तेज़ क्या है इसके बारे में नहीं जानते, लेकिन आप कुछ इस तरह की कोशिश कर सकते हैं।

declare @T table
(
  Col1 int,
  Col2 int,
  Col3 int,
  Col4 int,
  Col5 int,
  Col6 int
)

insert into @T values(1, 2, 3, 4, 5, 6)
insert into @T values(2, 3, 1, 4, 5, 6)

select T4.ColName, T4.ColValue
from @T as T1
  cross apply (
                select T3.ColValue, T3.ColName
                from (
                       select row_number() over(order by T2.ColValue) as rn,
                              T2.ColValue,
                              T2.ColName
                       from (
                              select T1.Col1, 'Col1' union all
                              select T1.Col2, 'Col2' union all
                              select T1.Col3, 'Col3' union all
                              select T1.Col4, 'Col4' union all
                              select T1.Col5, 'Col5' union all
                              select T1.Col6, 'Col6'
                            ) as T2(ColValue, ColName)
                     ) as T3
                where T3.rn = 1
              ) as T4

परिणाम:

ColName ColValue
------- -----------
Col1    1
Col3    1

यदि आपको इस बात में कोई दिलचस्पी नहीं है कि किस स्तंभ का न्यूनतम मूल्य है, तो आप इसके बजाय इसका उपयोग कर सकते हैं।

declare @T table
(
  Id int,
  Col1 int,
  Col2 int,
  Col3 int,
  Col4 int,
  Col5 int,
  Col6 int
)

insert into @T
select 1,        3,       4,       0,       2,       1,       5 union all
select 2,        2,       6,      10,       5,       7,       9 union all
select 3,        1,       1,       2,       3,       4,       5 union all
select 4,        9,       5,       4,       6,       8,       9

select T.Id, (select min(T1.ColValue)
              from (
                      select T.Col1 union all
                      select T.Col2 union all
                      select T.Col3 union all
                      select T.Col4 union all
                      select T.Col5 union all
                      select T.Col6
                    ) as T1(ColValue)
             ) as ColValue
from @T as T

एक सरलीकृत unpivot क्वेरी।

select Id, min(ColValue) as ColValue
from @T
unpivot (ColValue for Col in (Col1, Col2, Col3, Col4, Col5, Col6)) as U
group by Id

6

एक स्थायी कम्प्यूटेड कॉलम जोड़ें जो CASEआपके लिए आवश्यक तर्क करने के लिए एक कथन का उपयोग करता है ।

न्यूनतम मूल्य तब हमेशा कुशलता से उपलब्ध होगा जब आपको उस मूल्य के आधार पर एक जॉइन (या जो कुछ भी) करना होगा।

किसी भी स्रोत मान के परिवर्तन ( INSERT/ UPDATE/ MERGE) में हर बार मान पुन: प्रकाशित किया जाएगा । मैं यह नहीं कह रहा हूं कि यह जरूरी काम के बोझ के लिए सबसे अच्छा समाधान है, मैं इसे केवल एक समाधान के रूप में पेश करता हूं , अन्य उत्तरों की तरह। केवल ओपी ही यह निर्धारित कर सकता है कि वर्कलोड के लिए सबसे अच्छा क्या है।


1

6 तारीखों का केस स्टेटमेंट। कम करने के लिए, पहले मामले के बयान से सच्ची शाखा की प्रतिलिपि बनाएँ। सबसे खराब स्थिति यह है कि जब डेट 1 सबसे कम मूल्य है, तो सबसे अच्छा मामला यह है कि डेट 6 सबसे कम मूल्य है, इसलिए डेट 6 में सबसे अधिक संभावित तारीख डालें। मैंने यह गणना कंप्यूटेड कॉलम की सीमाओं के कारण लिखी थी।

CASE WHEN Date1 IS NULL OR Date1 > Date2 THEN
        CASE WHEN Date2 IS NULL OR Date2 > Date3 THEN
            CASE WHEN Date3 IS NULL OR Date3 > Date4 THEN
                CASE WHEN Date4 IS NULL OR Date4 > Date5 THEN
                    CASE WHEN Date5 IS NULL OR Date5 > Date6 THEN
                        Date6
                    ELSE
                        Date5
                    END
                ELSE
                    CASE WHEN Date4 IS NULL OR Date4 > Date6 THEN
                        Date6
                    ELSE
                        Date4
                    END
                END
            ELSE
                CASE WHEN Date3 IS NULL OR Date3 > Date5 THEN
                    CASE WHEN Date5 IS NULL OR Date5 > Date6 THEN
                        Date6
                    ELSE
                        Date5
                    END
                ELSE
                    CASE WHEN Date3 IS NULL OR Date3 > Date6 THEN
                        Date6
                    ELSE
                        Date3
                    END
                END
            END
        ELSE
            CASE WHEN Date2 IS NULL OR Date2 > Date4 THEN
                CASE WHEN Date4 IS NULL OR Date4 > Date5 THEN
                    CASE WHEN Date5 IS NULL OR Date5 > Date6 THEN
                        Date6
                    ELSE
                        Date5
                    END
                ELSE
                    CASE WHEN Date4 IS NULL OR Date4 > Date5 THEN
                        CASE WHEN Date5 IS NULL OR Date5 > Date6 THEN
                            Date6
                        ELSE
                            Date5
                        END
                    ELSE
                        CASE WHEN Date4 IS NULL OR Date4 > Date6 THEN
                            Date6
                        ELSE
                            Date4
                        END
                    END
                END
            ELSE
                CASE WHEN Date2 IS NULL OR Date2 > Date5 THEN
                    CASE WHEN Date5 IS NULL OR Date5 > Date6 THEN
                        Date6
                    ELSE
                        Date5
                    END
                ELSE
                    CASE WHEN Date2 IS NULL OR Date2 > Date6 THEN
                        Date6
                    ELSE
                        Date2
                    END
                END
            END
        END
ELSE
    CASE WHEN Date1 IS NULL OR Date1 > Date3 THEN
        CASE WHEN Date3 IS NULL OR Date3 > Date4 THEN
            CASE WHEN Date4 IS NULL OR Date4 > Date5 THEN
                CASE WHEN Date5 IS NULL OR Date5 > Date6 THEN
                    Date6
                ELSE
                    Date5
                END
            ELSE
                CASE WHEN Date4 IS NULL OR Date4 > Date6 THEN
                    Date6
                ELSE
                    Date4
                END
            END
        ELSE
            CASE WHEN Date3 IS NULL OR Date3 > Date5 THEN
                CASE WHEN Date5 IS NULL OR Date5 > Date6 THEN
                    Date6
                ELSE
                    Date5
                END
            ELSE
                CASE WHEN Date3 IS NULL OR Date3 > Date6 THEN
                    Date6
                ELSE
                    Date3
                END
            END
        END
    ELSE
        CASE WHEN Date1 IS NULL OR Date1 > Date4 THEN
            CASE WHEN Date4 IS NULL OR Date4 > Date5 THEN
                CASE WHEN Date5 IS NULL OR Date5 > Date6 THEN
                    Date6
                ELSE
                    Date5
                END
            ELSE
                CASE WHEN Date4 IS NULL OR Date4 > Date6 THEN
                    Date6
                ELSE
                    Date4
                END
            END
        ELSE
            CASE WHEN Date1 IS NULL OR Date1 > Date5 THEN
                CASE WHEN Date5 IS NULL OR Date5 > Date6 THEN
                    Date6
                ELSE
                    Date5
                END
            ELSE
                CASE WHEN Date1 IS NULL OR Date1 > Date6 THEN
                    Date6
                ELSE
                    Date1
                END
            END
        END
    END
END

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

Lowest =    
(
    SELECT MIN(TVC.d) 
    FROM 
    (
        VALUES
            (Date1), 
            (Date2), 
            (Date3), 
            (Date4), 
            (Date5), 
            (Date6)
    ) 
    AS TVC(d)
)

1

आपका caseकथन कुशल नहीं है। आप सबसे बुरे मामले में 5 तुलना कर रहे हैं, और 2 सर्वश्रेष्ठ मामले में; जबकि न्यूनतम का पता nलगाना अधिकांश n-1तुलनाओं पर करना चाहिए ।

प्रत्येक पंक्ति के लिए, औसतन आप 2 के बजाय 3.5 तुलना कर रहे हैं। इस प्रकार यह अधिक सीपीयू समय ले रहा है और धीमा है। नीचे caseदिए गए कथन का उपयोग करके अपने परीक्षणों को फिर से आज़माएं । यह सिर्फ प्रति पंक्ति 2 तुलना उपयोग कर रहा है और अधिक कुशल होना चाहिए unpivotऔर union all

Select Id, 
       Case 
           When Col1 <= Col2 then case when Col1 <= Col3 Then Col1  else col3 end
            When  Col2 <= Col3 Then Col2  
            Else Col3 
            End As TheMin 
From   YourTableNameHere

union allके रूप में आप प्रत्येक पंक्ति में बल्कि पूरे तालिका के लिए नहीं न्यूनतम मूल्य मिल रहा है विधि अपने मामले में गलत है। इसके अलावा, यह कुशल नहीं होगा क्योंकि आप एक ही तालिका को 3 बार स्कैन करने जा रहे हैं। जब तालिका छोटी होती है, तो I / O बहुत अंतर नहीं करेगा, लेकिन बड़ी तालिकाओं के लिए। उस विधि का उपयोग न करें।

Unpivotअच्छा है और क्रॉस के साथ अपनी तालिका में शामिल होने का उपयोग करके मैन्युअल रूप से अप्रकाशित करने का प्रयास करें (select 1 union all select 2 union all select 3)। यह उतना ही कुशल होना चाहिए जितना कि unpivot

यदि आपके पास स्थान की समस्या नहीं है, तो सबसे अच्छा समाधान एक संगोष्ठित कॉलम होगा। यह 4 बाइट्स द्वारा पंक्ति के आकार में जोड़ देगा (मुझे लगता है कि आपके पास intटाइप होगा ), जो बदले में तालिका के आकार को बढ़ाएगा।

हालाँकि, आपके सिस्टम में स्थान और मेमोरी समस्या है और CPU तब नहीं है जब तक इसे जारी न रखा जाए लेकिन केस स्टेटमेंट का उपयोग करते हुए सरल कंप्यूटेड कॉलम का उपयोग करें। यह कोड को सरल बना देगा।


-1

मुझे लगता है कि पहला विकल्प सबसे तेज़ है (हालांकि यह प्रोग्रामिंग दृष्टिकोण से बहुत चालाक नहीं लगता है!)। ऐसा इसलिए है क्योंकि यह बिल्कुल एन पंक्तियों (जहां एन टेबल आकार है) से संबंधित है और इसे विधि 2 या 3 की तरह कोई खोज या सॉर्ट नहीं करना है।

बड़े नमूने के साथ एक परीक्षण को बिंदु साबित करना चाहिए।

अभी तक विचार करने के लिए एक अन्य विकल्प के रूप में (जैसे कि आपको और अधिक की आवश्यकता है!), अपनी मेज पर एक भौतिकवादी दृश्य बनाना है । यदि आपकी तालिका का आकार हजारों या अधिक के 100 में है। इस तरह, न्यूनतम मान की गणना की जाती है जबकि पंक्ति को बदल दिया जाता है और पूरी तालिका को प्रत्येक प्रश्न के साथ संसाधित नहीं करना होता। SQL Server में, materialized views को Indexed Views कहा जाता है


-1
Create table #temp
   (
    id int identity(1,1),
    Name varchar(30),
    Year1 int,
    Year2 int,
    Year3 int,
    Year4 int
   )

   Insert into #temp values ('A' ,2015,2016,2014,2010)
   Insert into #temp values ('B' ,2016,2013,2017,2018)
   Insert into #temp values ('C' ,2010,2016,2014,2017)
   Insert into #temp values ('D' ,2017,2016,2014,2015)
   Insert into #temp values ('E' ,2016,2016,2016,2016)
   Insert into #temp values ('F' ,2016,2017,2018,2019)
   Insert into #temp values ('G' ,2016,2017,2020,2019)

   Select *, Case 
                 when Year1 >= Year2 and Year1 >= Year3 and Year1 >= Year4 then Year1
                 when Year2 >= Year3 and Year2 >= Year4 and Year2 >= Year1 then Year2
                 when Year3 >= Year4 and Year3 >= Year1 and Year3 >= Year2 then Year3
                 when Year4 >= Year1 and Year4 >= Year2 and Year4 >= Year3 then Year4  
                 else Year1 end as maxscore  
                 from #temp

आप NULLs के लिए लेखांकन नहीं कर रहे हैं - जो आपकी CASE अभिव्यक्ति को अपेक्षाकृत सरल बनाता है। हालाँकि, यदि कम से कम एक स्तंभ वास्तव में NULL है, तो आपका समाधान Year1परिणाम के रूप में वापस आ जाएगा , जो कि आवश्यक नहीं है कि सही हो।
एंड्री एम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.