2017-08-29 54 views
5

मेरे पास कुछ मान कॉलम, एक सूत्र और परिणाम कॉलम वाला एक टेबल है।तालिका में प्रत्येक पंक्ति को अद्यतन करें

|rownum|value1|value2|value3|formula    |result| 
|------|------|------|------|--------------------|------| 
|1  |11 |30 |8  |value1/value2*value3|  | 
|2  |43 |0  |93 |value1-value2+value3|  | 

मैं सूत्र के परिणाम के साथ result स्तंभ को भरने के लिए चाहते हैं।

वर्तमान में मैं इस प्रश्न के साथ कि कर रहा हूँ:

DECLARE @v_sql NVARCHAR(MAX) 

SET @v_Sql = CAST ((SELECT 
      ' UPDATE [table] ' + 
      ' SET [result] = ' + table.[formula] + 
      ' WHERE [rownum] = ' + CAST(table.[rownum] as nvarchar(255)) + 
      ';' 
      FROM [table] 
      FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') AS NVARCHAR (MAX)) 

EXEC (@v_Sql) 

समस्या यह है कि यह एक बहुत लंबे समय लेता है। तालिका में # पंक्तियां 5 - 10 मिलियन होंगी।

क्या इसे गति देने का कोई तरीका है? इस समस्या के वैकल्पिक दृष्टिकोणों में से?

बहुत धन्यवाद!

+0

आप इसे [कोड समीक्षा] (https://codereview.stackexchange.com/) पर पोस्ट करना चाहते हैं। यह काम करने वाले कोड के लिए बेहतर जगह है जिसे आप तेज़ करना चाहते हैं। –

+0

फॉर्मूला एक गणना कॉलम कार्य करता है? –

+0

आपको अपने 'अपडेट' में बाधाओं की तलाश करनी होगी। क्या आपके पास कोई ट्रिगर्स, इंडेक्स या एफके है? आप किस तरह का अलगाव का उपयोग कर रहे हैं? एक प्रश्न योजना भी देखें। –

उत्तर

0

सभी उत्तर और विचारों के लिए धन्यवाद पैदा करते हैं। अंत में समस्या तालिका के बजाय आयाम में सूत्र को सहेजकर हल किया गया था। यह आयाम में प्रत्येक पंक्ति के लिए 1 अद्यतन कथन उत्पन्न करता है और प्रत्येक तथ्य रेखा के लिए 1 अद्यतन कथन के विपरीत, जहां सभी खंडों के साथ सभी प्रासंगिक तथ्यों को लागू करता है। प्रक्रिया का समय 1,5 घंटे से एक सेकंड से भी कम हो गया।

3

ऑपरेटर आदेश नियम मानते हुए और केवल अपने सरल सूत्र उदाहरण को कवर:

UPDATE [table] 
SET [result] = case replace(replace(replace([formula],'value1', ''), 'Value2', ''), 'Value3', '') 
     when '++' then [value1] + [value2] + [Value3] 
     when '+-' then [value1] + [value2] - [Value3] 
     when '+*' then [value1] + [value2] * [Value3] 
     when '+/' then [value1] + [value2]/[Value3] 
     when '-+' then [value1] - [value2] + [Value3] 
     when '--' then [value1] - [value2] - [Value3] 
     when '-*' then [value1] - [value2] * [Value3] 
     when '-/' then [value1] - [value2]/[Value3] 
     when '*+' then [value1] * [value2] + [Value3] 
     when '*-' then [value1] * [value2] - [Value3] 
     when '**' then [value1] * [value2] * [Value3] 
     when '*/' then [value1] * [value2]/[Value3] 
     when '/+' then [value1]/[value2] + [Value3] 
     when '/-' then [value1]/[value2] - [Value3] 
     when '/*' then [value1]/[value2] * [Value3] 
     when '//' then [value1]/[value2]/[Value3] 
     end 
from [Table] 
+0

धन्यवाद, लेकिन जिस तरह से मैंने समस्या प्रस्तुत की है वह बहुत सरल है। वास्तव में 7 फ़ील्ड हैं। सूत्र में उन क्षेत्रों में से 1 या अधिक होते हैं और किसी भी फैशन में बनाया जा सकता है। फार्मूला की संरचना के लिए कोई सीमा नहीं है इसके अलावा इसे गणितीय रूप से सही होना चाहिए। – tv87

+1

@ tv87 मैंने एक और जवाब जोड़ा है जो मदद कर सकता है। – cloudsafe

1

दो साधारण चीजें जो मन में आते हैं:

  1. यकीन rownum स्तंभ अगर आप कर रहे हैं पर एक सूचकांक है बनाओ व्यक्तिगत रूप से प्रत्येक पंक्ति को अद्यतन करना।

  2. यदि कुछ अलग-अलग सूत्र हैं तो आप प्रत्येक पंक्ति को अलग-अलग अद्यतन करने के बजाय एक ही सूत्र के साथ सभी पंक्तियों को UPDATE में अपडेट कर सकते हैं। इस मामले में formula कॉलम पर एक सूचकांक मदद करेगा।

+0

हाय, मैंने राउनम कॉलम पर एक इंडेक्स जोड़ा जो क्वेरी को बढ़ाता है। दुर्भाग्यवश यह अभी भी धीमा है। उपयोग किए गए विभिन्न सूत्रों की संख्या सीमित है और इस तालिका से जुड़े आयाम पर निर्भर करती है। तो शायद 1 मिलियन लाइनों के लिए लागू होने के लिए 100 अद्वितीय सूत्र हैं। मैं इस आयाम तालिका में सूत्रों को स्थानांतरित करने का प्रयास करूंगा और इसे निष्पादित किए जाने वाले अद्यतन विवरणों की मात्रा को सीमित करने के लिए वहां से पुनर्प्राप्त करूंगा। – tv87

+0

@ tv87, यह 1,000,000 गुना से 100 गुना 'अद्यतन' चलाने के लिए निश्चित रूप से तेज़ है। विशेष रूप से जब अद्यतन पंक्तियों की कुल संख्या समान होती है। यह लगभग 10,000 गुना तेजी से होना चाहिए। हालांकि, 'फॉर्मूला' कॉलम पर इंडेक्स होना महत्वपूर्ण है। –

1

क्या यह फॉर्मूला प्रकारों द्वारा त्वरित थोक अद्यतन है? [सूत्र] पर जरूरत सूचकांक भी:

DECLARE @v_sql NVARCHAR(MAX) 

SET @v_Sql = CAST ((SELECT 
      ' UPDATE [table] ' + 
      ' SET [result] = ' + [table].[formula] + 
      ' WHERE [formula] = ''' + [table].[formula] + ''';' 
      FROM [table] 
      group by [table].[formula] 
      FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') AS NVARCHAR (MAX)) 
exec(@v_Sql) 
0

ट्रिगर विकल्प के साथ जाओ, लेकिन अब के लिए, मात्रा में अद्यतन करने के कम प्रभाव पड़ेगा।

TOP(5000) सिर्फ 5000 पंक्तियों हर बार WHERE [result] is null OR [result]=''

GO 20000 इस क्वेरी को निष्पादित करेंगे 20000 बार (10 लाख पंक्तियाँ) यह अद्यतन बयान के लिए 0 रिकॉर्ड रिटर्न जब तक निष्पादित करने के लिए जारी रहेगा अद्यतन करेगा।

DECLARE @v_sql NVARCHAR(MAX) 

SET @v_Sql = CAST ((SELECT 
      ' UPDATE TOP (5000) [table] ' + 
      ' SET [result] = ' + [table].[formula] + 
      ' WHERE [formula] = ''' + [table].[formula] + ''' 
      AND ([result] is null OR [result]='');' 
      FROM [table] 
      group by [table].[formula] 
      FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') AS NVARCHAR (MAX)) 
exec(@v_Sql) 

    GO 20000 

इस के बाद, ट्रिगर

0

मैंने अभी 5 मिलियन पंक्तियों के साथ तालिका बनाई है। तालिका संरचना के साथ के रूप में:

rn t1 t2 t3 formula 
1 80 23 93 t1/t2 * t3 
2 80 87 30 t1/t2 * t3 
3 92 83 63 t1/t2 * t3 
4 68 19 36 t1/t2 * t3 
5 65 63 10 t1/t2 * t3 

तो क्या आप वाकई यह है कि आप सभी सूत्र मान्य हैं, और आप उदाहरण के लिए शून्य से भाग नहीं होगा, या डेटा प्रकार अतिप्रवाह, इस मामले में आप अपने खुद के eval कर सकते हैं() एसक्यूएल सर्वर में फंक्शन।

मैंने फॉर्मूला में 3 मानों के लिए अपना स्वयं का फ़ंक्शन बनाया है जैसे '+', '-', '*', '/'।

समारोह कोड है:

use db_test; 
go 

alter function dbo.eval(@a varchar(max)) 
returns float 
as 
begin 
    set @a = replace(@a, ' ', ''); 

    declare @pos1 int = PATINDEX('%[+/*-]%', @a); 
    declare @t1 float = cast(substring(@a, 1, @pos1 - 1) as float); 
    declare @sign1 char(1) = substring(@a, @pos1, 1); 
    set @a = substring(@a, @pos1 + 1, len(@a) - @pos1); 

    declare @pos2 int = PATINDEX('%[+/*-]%', @a); 
    declare @t2 float = cast(substring(@a, 1, @pos2 - 1) as float); 
    declare @sign2 char(1) = substring(@a, @pos2, 1); 
    set @a = substring(@a, @pos2 + 1, len(@a) - @pos2); 

    declare @t3 float = cast(@a as float); 

    set @t1 = (
     case @sign1 
      when '+' then @t1 + @t2 
      when '-' then @t1 - @t2 
      when '*' then @t1 * @t2 
      when '/' then @t1/@t2 
     end 
    ); 

    set @t1 = (
     case @sign2 
      when '+' then @t1 + @t3 
      when '-' then @t1 - @t3 
      when '*' then @t1 * @t3 
      when '/' then @t1/@t3 
     end 
    ); 

    return @t1; 
end; 

और यह अगले डेटा पर काम करता है:

select dbo.eval('7.6*11.3/4.5') as eval, 7.6*11.3/4.5 as sqlServerCalc; 

eval     sqlServerCalc 
19,0844444444444  19.084444 

उसके बाद आप स्तंभ मान करके अपने सूत्र में मूल्यों की जगह है और यह गणना कर सकते हैं:

with cte as (
    select rn, t1, t2, t3, formula, 
     REPLACE(REPLACE(REPLACE(formula, 't1', cast(t1 as varchar(max))), 't2', cast(t2 as varchar(max))), 't3', cast(t3 as varchar(max))) as calc 
    from db_test.dbo.loop 
) 
select rn, t1, t2, t3, formula, db_test.dbo.eval(calc) as result 
into db_test.dbo.loop2 
from cte; 

मेरे लिए समय ठीक है, मेरे एसक्यूएल सर्वर 2016 पर 3 मिनट लगते हैं और अच्छे परिणाम प्राप्त करते हैं:

select top 5 * 
from db_test.dbo.loop2; 
rn t1 t2 t3 formula   result 
1 80 23 93 t1/t2 * t3 323,478260869565 
2 80 87 30 t1/t2 * t3 27,5862068965517 
3 92 83 63 t1/t2 * t3 69,8313253012048 
4 68 19 36 t1/t2 * t3 128,842105263158 
5 65 63 10 t1/t2 * t3 10,3174603174603 

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

संबंधित मुद्दे