2011-08-10 22 views
5

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

CREATE TABLE stage 
(
    id int not null, 
    fk_parent int 
) 

CREATE TABLE task 
(
    id int not null, 
    fk_stage int not null, 
    cost decimal(18,2) not null default 0 
) 

:

इसे दर्शाने के लिए, मैं निम्नलिखित डेटा संरचना का उपयोग करेगा

==stage== 
id fk_parent 
1 null 
2 1 
3 1 

==task== 
id fk_stage cost 
1 2   100 
1 2   200 
1 3   600 

मैं प्रत्येक शाखा पर कुल लागत से युक्त एक मेज प्राप्त करने के लिए चाहते हैं। कुछ ऐसा:

Stage ID  Total Cost 
1    900 
2    300 
3    600 

लेकिन, मैं यह भी उत्पादक बनना चाहता हूं। मैं The worst algorithm in the world जैसे बेहद खराब समाधानों के साथ समाप्त नहीं करना चाहता हूं। मेरा मतलब है कि यह मामला है। यदि मैं stage तालिका में सभी वस्तुओं के लिए डेटा का अनुरोध करूंगा, कुल लागत के साथ, प्रत्येक कुल लागत का मूल्यांकन D बार किया जाएगा, जहां D पेड़ (स्तर) में गहराई है, जहां यह स्थित है। मुझे डर है कि मैं बहुत सारे स्तरों के साथ बड़ी मात्रा में डेटा पर बेहद कम प्रदर्शन करता हूं।

अतः,

मैं कुछ जो मुझे इस सवाल यहाँ का आग्रह करने के लिए फैसला किया।
मैंने कैशिंग के लिए stage तालिका में 2 और कॉलम जोड़ने का निर्णय लिया।

... 
calculated_cost decimal(18,2), 
date_calculated_cost datetime 
... 

तो क्या मैं करना चाहता था, एक datetime मूल्य है जो समय के बराबर है जब इस प्रक्रिया को शुरू किया गया था (काफी अनूठा) कोड के भीतर एक और चर जाते हैं। इस तरह, यदि stage पंक्ति में पहले से ही date_calculated_cost है जो कि मैं ले जा रहा हूं, उसके बराबर है, तो मैं इसे फिर से गणना करने की परेशानी नहीं करता, और केवल calculated_cost मान वापस लौटाता हूं।

मैं कार्य के साथ ऐसा नहीं कर सकता है (एक बार लागतों की गणना अद्यतन, stage तालिका के लिए आवश्यक हैं)
मैं प्रक्रिया के साथ यह नहीं कर सका
मैं (चल कर्सर भीतर प्रत्यावर्तन नो-गो है) मुझे यकीन नहीं है कि अस्थायी सारणी उपयुक्त हैं क्योंकि यह एक ही प्रक्रिया के समवर्ती अनुरोधों की अनुमति नहीं देगी (जो कम से कम संभावना है, लेकिन वैसे भी मैं इसे सही तरीके से करना चाहता हूं)
मैं अन्य तरीकों को समझ नहीं पाया।

मुझे अपने प्रश्न का एक निश्चित उत्तर की उम्मीद नहीं है, लेकिन मैं किसी भी अच्छे विचार को पुरस्कृत करूंगा, और सबसे अच्छा जवाब के रूप में चुना जाएगा।

उत्तर

2

1. समेकित लागत प्राप्त करने के लिए तालिकाओं से पूछने का एक तरीका।

  1. प्रत्येक चरण के लिए लागत की गणना करें।
  2. प्रत्येक चरण के लिए स्तर प्राप्त करने के लिए एक पुनरावर्ती सीटीई का उपयोग करें।
  3. परिणाम को एक temp तालिका में संग्रहीत करें।
  4. अस्थायी तालिका में कुछ अनुक्रमणिका जोड़ें।
  5. प्रत्येक स्तर

पहले तीन चरणों का एक बयान के संयुक्त है के लिए अद्यतन एक पाश में अस्थायी तालिका में लागत। यह पहली गणना करने के लिए प्रदर्शन के लिए अच्छा हो सकता है, cteCost, अपने स्वयं की एक टेम्पलेट तालिका में और उस अस्थायी तालिका को रिकर्सिव cteLevel में उपयोग करें।

;with cteCost as 
(
    select s.id, 
     s.fk_parent, 
     isnull(sum(t.cost), 0) as cost 
    from stage as s 
    left outer join task as t 
     on s.id = t.fk_stage 
    group by s.id, s.fk_parent 
), 
cteLevel as 
(
    select cc.id, 
     cc.fk_parent, 
     cc.cost, 
     1 as lvl 
    from cteCost as cc 
    where cc.fk_parent is null 
    union all 
    select cc.id, 
     cc.fk_parent, 
     cc.cost, 
     lvl+1 
    from cteCost as cc 
    inner join cteLevel as cl 
     on cc.fk_parent = cl.id  
) 
select * 
into #task 
from cteLevel 

create clustered index IX_id on #task (id) 
create index IX_lvl on #task (lvl, fk_parent) 

declare @lvl int 
select @lvl = max(lvl) 
from #task 

while @lvl > 0 
begin 

    update T1 set 
    T1.cost = T1.cost + T2.cost 
    from #task as T1 
    inner join (select fk_parent, sum(cost) as cost 
       from #task 
       where lvl = @lvl 
       group by fk_parent) as T2 
     on T1.id = T2.fk_parent 

    set @lvl = @lvl - 1 
end 

select id as [Stage ID], 
     cost as [Total Cost] 
from #task 

drop table #task 

2. कि stage में एक calculated_cost क्षेत्र का कहना है तालिका task पर एक ट्रिगर।

create trigger tr_task 
on task 
after insert, update, delete 
as 
    -- Table to hold the updates 
    declare @T table 
    (
    id int not null, 
    cost decimal(18,2) not null default 0 
) 

    -- Get the updates from inserted and deleted tables 
    insert into @T (id, cost) 
    select fk_stage, sum(cost) 
    from (
      select fk_stage, cost 
      from inserted 
      union all 
      select fk_stage, -cost 
      from deleted 
     ) as T 
    group by fk_stage 

    declare @id int 
    select @id = min(id) 
    from @T 

    -- For each updated row 
    while @id is not null 
    begin 

    -- Recursive update of stage 
    with cte as 
    (
     select s.id, 
      s.fk_parent 
     from stage as s 
     where id = @id 
     union all 
     select s.id, 
      s.fk_parent 
     from stage as s 
     inner join cte as c 
      on s.id = c.fk_parent  
    ) 
    update s set 
     calculated_cost = s.calculated_cost + t.cost 
    from stage as s 
     inner join cte as c 
     on s.id = c.id 
     cross apply (select cost 
        from @T 
        where id = @id) as t 

    -- Get the next id 
    select @id = min(id) 
    from @T 
    where id > @id 
    end 
+0

उत्तर के लिए इंतजार करते समय, मैंने अपनी समस्या (मुझे लगता है) हल किया। मैंने कुछ फ़ील्ड जोड़े, मैं एक ट्रिगर के अंदर मंच के 'स्तर' की गणना करता हूं, फिर सभी चरणों के खिलाफ एक कर्सर चलाता हूं, स्तर से उतरने का आदेश देता है, और वांछित परिणाम प्राप्त करता हूं। सभी लेनदेन के अंदर किया जाता है जो सभी संसाधनों को ताला लगा देता है, इसलिए पेड़ में कोई पत्ता संशोधित नहीं किया जा सकता है। ऐसा लगता है कि काम कर रहा है, लेकिन मुझे कुछ वास्तविक डेटा प्राप्त करने और परीक्षण करने के लिए एकीकरण भाग को समाप्त करने की आवश्यकता है, फिर मैं इसे यहां भी पोस्ट करूंगा। आपके उत्तर सही होने लगते हैं, और मेरे लिए बहुत दिलचस्प है। आपका समय देने के लिए आपका बहुत बहुत धन्यवाद। – AlexanderMP