Welcome to Sign in | Help

Re: Optimizare SQL

  •  04-02-2009, 7:45 PM

    Re: Optimizare SQL

    Ceea ce ai tu este o problemă clasică de running sum, care nu prea poate fi rezolvată eficient, frumos şi corect (adică folosind doar facilităţi documentate) în SQL Server. Trebuie să renunţi la una dintre "eficient", "frumos" sau "corect". La care renunţi?

    Dacă renunţi la "eficient", atunci rezultă ceea ce ai (eventul poţi să faci un index compus, pe Cont, DataInr şi NDS, dar nu ajută la mare lucru).

    Dacă renunţi la "frumos", atunci foloseşti un cursor ca să completezi coloana respectivă în tabelă. În acest caz (la zeci de mii de înregistrări), cursorul va merge mult mai repede decât query-ul actual.

    Dacă renunţi la "corect", atunci foloseşti o facilitate nedocumentată şi completezi acea coloană printr-un UPDATE de genul @variabila=coloana=expresie, astfel:

    USE tempdb

    GO

    CREATE TABLE A_lstFisaCont (

          cont varchar(20) not null,

          datainr datetime null,

          nds int not null,

          coduser int not null default (1),

          debit money not null,

          credit money not null,

          sold money null

    )

     

    GO

    INSERT INTO A_lstFisaCont (cont, datainr, nds, debit, credit)

    SELECT '456' as cont, NULL as datainr, 1 as nds, 200 as debit, 0 as credit

    UNION ALL SELECT '1012' as cont, NULL as datainr, 1 as nds, 0 as debit, 200 as credit

    UNION ALL SELECT '5121' as cont, '20080101' AS datainr, 2 as nds, 200 as debit, 0 as credit

    UNION ALL SELECT '456' as cont, '20080101' AS datainr, 2 as nds, 0 as debit, 200 as credit

    UNION ALL SELECT '5121' as cont, '20080102' AS datainr, 3 as nds, 10 as debit, 0 as credit

    UNION ALL SELECT '766' as cont, '20080102' AS datainr, 3 as nds, 0 as debit, 10 as credit

    UNION ALL SELECT '5121' as cont, '20080103' AS datainr, 4 as nds, 12 as debit, 0 as credit

    UNION ALL SELECT '766' as cont, '20080103' AS datainr, 4 as nds, 0 as debit, 12 as credit

    UNION ALL SELECT '5121' as cont, '20080103' AS datainr, 5 as nds, 13 as debit, 0 as credit

    UNION ALL SELECT '766' as cont, '20080103' AS datainr, 5 as nds, 0 as debit, 13 as credit

    UNION ALL SELECT '766' as cont, '20080131' AS datainr, 6 as nds, 35 as debit, 0 as credit

    UNION ALL SELECT '121' as cont, '20080131' AS datainr, 6 as nds, 0 as debit, 35 as credit

     

    GO

    SELECT * FROM A_lstFisaCont ORDER BY cont, datainr, nds

     

    GO

    DECLARE @cont varchar(20), @sold money

    UPDATE x SET

          @sold=sold=debit-credit+CASE WHEN @cont=cont THEN @sold ELSE 0 END,    

          @cont=cont

    FROM (SELECT TOP 9223372036854775807 * FROM A_lstFisaCont ORDER BY cont, datainr, nds) x

     

    GO

    SELECT * FROM A_lstFisaCont ORDER BY cont, datainr, nds

     

    GO

    --DROP TABLE A_lstFisaCont

    Totuşi, nu recomand această variantă, pentru că nu e documentat niciunde că UPDATE-ul se va face în ordinea specificată în ORDER BY-ul din subquery (e doar o conincidenţă). Drept urmare, recomand varianta cu cursor, cel puţin până când se va implementa în SQL Server funcţiile agregate în care se poate preciza ordinea. Pentru ca acest lucru să se întâmple cât mai curând, vă rog să votaţi sugestia următoare pe Connect (eventual şi celelalte sugestii menţionate în http://www.insidetsql.com/OVER_Clause_and_Ordered_Calculations.doc):

    https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=254387

    Răzvan

    PS. Clauza WHERE din query-ul tău putea fi scrisă mai simplu astfel:

    where cont=fc.cont and coduser=1
    and (datainr is null or fc.datainr>datainr or fc.datainr=datainr and fc.nds>=nds)

View Complete Thread
Powered by Community Server (Commercial Edition), by Telligent Systems