Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

Spora stored procedure, sta sad?

[es] :: MS SQL :: Spora stored procedure, sta sad?

[ Pregleda: 2797 | Odgovora: 17 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

Mikelly

Član broj: 16730
Poruke: 389
95.155.29.*



Profil

icon Spora stored procedure, sta sad?09.06.2009. u 13:43 - pre 180 meseci
Baza ima tri tabele, obveznici sa 600 zapisa, konta sa 10 zapisa i tabelu podataka detalja sa svega 2500 zapisa. Baza od 2,5 MB. Uskladistena procedura koja radi korelisani query (u svrhu racunanja kamata), za svakog od 600 obveznika ponaosob, radi citavih 10 sekundi. Vjecnost. A tu su podaci za svega 3 mjeseca. Trebace joj citav minut da obradi kompletnu godinu.

E sad, mozda je do SQL Express-a. Ako stavim Full SQL Server, da li ce se mozda stvari ubrzat???

Jer, 10 sekundi je stvarno previse, pa gigaherci i gigabajti su joj na raspolaganju, plus je baza na Windows Server-u.

Ovoga sam se i plasio kad sam pisao tu jadnu proceduru.

Ako neko ima iskustva sa ovim, cijenio bih pomoc...

A ako racunanje kamata prebacim na teret aplikacije, mislim da sve nece trajat ni sekundu, sa sve prevlacenjem podataka i racunanjem kamata.

Ne znam, nemam previse iskustva, ali sam malo razocaran, mislio sam da je baza "tata" a sad ispade da bi mi bilo bolje da sam se skoncentrisao na aplikaciju.

Bilo kakav savjet, predlog, misljenje mi je dobrodoslo...

Pozdrav i hvala.




 
Odgovor na temu

sallle
Sasa Ninkovic
GTECH
Beograd

Član broj: 146
Poruke: 480
80.93.229.*

ICQ: 20785904


+4 Profil

icon Re: Spora stored procedure, sta sad?09.06.2009. u 14:03 - pre 180 meseci
baza jeste tata ako znas da je vozis.

verovatno je losh upit, i loshi indeksi...
 
Odgovor na temu

mmix
Miljan Mitrović
Profesorkin muz
Passau, Deutschland

SuperModerator
Član broj: 17944
Poruke: 6042



+4631 Profil

icon Re: Spora stored procedure, sta sad?09.06.2009. u 14:19 - pre 180 meseci
kako setas kroz korisnike? kurzor?

Kakva je situacija sa lockovima na tabelama sa kojima radis?
Sloba je za 12 godina promenio antropološki kod srpskog naroda. On je od jednog naroda koji je bio veseo, pomalo površan, od jednog naroda koji je bio znatiželjan, koji je voleo da vidi, da putuje, da upozna,
od naroda koji je bio kosmopolitski napravio narod koji je namršten, mrzovoljan, sumnjicav, zaplašen, narod koji se stalno nešto žali, kome je stalno neko kriv… - Z.Đinđić
 
Odgovor na temu

ludja85
Vojislav Pankovic
Novi Sad

Član broj: 137528
Poruke: 3
*.dynamic.sbb.rs.



Profil

icon Re: Spora stored procedure, sta sad?09.06.2009. u 18:59 - pre 180 meseci
Mozes li postaviti trenutni kod procedure, pa da probamo malo to da optimizujemo?
 
Odgovor na temu

Mikelly

Član broj: 16730
Poruke: 389
78.155.52.*



Profil

icon Re: Spora stored procedure, sta sad?15.06.2009. u 13:51 - pre 180 meseci
Ja se izvinjavam sto se prije nijesam javio, a vi ste bili voljni da pomognete. Nadam se da nije kasno :)

@mmix
Nema kursora, nema lockova. Samo korelisani query.

@ludja85
Nemam proceduru kod sebe, kad dodjem doma, postavicu je.

@salle
vjerovatno si u pravu, ali ja sam (bio) jako ponosan na taj upit, zato pazi sta pricas :))))


Procedura ide ovako: Uzmem svaki par (korisnik, konto) iz baze, sortiram po datumu, trazim razliku datuma izmedju dva uzastopna zapisa (zbog toga korelisani query), ta razlika * saldo prvog * 0.03% kamate = iznos kamate za taj interval, suma svih zapisa = kamata na taj konto, suma tih kamata za korisnika = kamata za korisnika.


Ja nijesam bio lijen u medjuvremenu, prebacio sam racunanje kamata na aplikaciju.
I opet izenenadjenje. Za istu kolicinu podataka aplikaciji (E5200, 4GB RAM) treba (opet velikih) 6 sekundi.
Mada i tu ima prostora za unapredjenje. Naime, isao sam sa mnogo poziva bazi. 600 korisnika x 10 konta = 6000 poziva, mada ce vise od pola vratiti prazan set podataka (taj korisnik nema nista na tom kontu). Mozda bi bilo brze da sve odjednom prevucem iz baze, pa da izvlacim podatke iz dataseta...


Sad, uzimajuci u obzir i brzinu kojom i aplikacija daje rezultate, bojim se da sam u korijenu pogrijesio (sam nacin racunanja kamata). Mada, ako hocu 100% tacne kamate, moram ih svaki put iznova racunat. Inace, kada bih vrijednost kamata cuvao u bazi, neki retroaktivni zapis bi napravio, blago receno, karambol. Mozda bih mogao napravit sopstvenu log tabelu pomocu koje bih radio rollback do do datuma tog retro zapisa, i onda ponovo nazad to danasnjeg datuma, ali mi se to cini jako komplikovano... Mozda su ti kursori sto mmix pominje dobro rjesenje, ali sa njima do sad nijesam radio...


Nista, postavicu proceduru kad dodjem doma, pa ako ste voljni, pogledajte...


Hvala puno i pozdrav.
 
Odgovor na temu

mmix
Miljan Mitrović
Profesorkin muz
Passau, Deutschland

SuperModerator
Član broj: 17944
Poruke: 6042



+4631 Profil

icon Re: Spora stored procedure, sta sad?15.06.2009. u 14:07 - pre 180 meseci
Kurzori nikad nisu dobro resenje

Uradi actual plan po ovom linku i okaci ovde ako mozes, to ce najpre pomoci u resenju problema.
Sloba je za 12 godina promenio antropološki kod srpskog naroda. On je od jednog naroda koji je bio veseo, pomalo površan, od jednog naroda koji je bio znatiželjan, koji je voleo da vidi, da putuje, da upozna,
od naroda koji je bio kosmopolitski napravio narod koji je namršten, mrzovoljan, sumnjicav, zaplašen, narod koji se stalno nešto žali, kome je stalno neko kriv… - Z.Đinđić
 
Odgovor na temu

Mikelly

Član broj: 16730
Poruke: 389
212.200.246.*



Profil

icon Re: Spora stored procedure, sta sad?15.06.2009. u 15:25 - pre 180 meseci
Ok, execution plan je u attachmentu. Ne sumnjam da je to izuzetna stvar, ali se na prvi pogled uplasih od njega...

Kad smo vec kod ovih sitnica, jel postoji nacin da ja vidim zahtjeve klijenta prema serveru (ono kad radi update dataseta, fill metode i slicno)?

evo koda procedure:

Code:

ALTER PROCEDURE [dbo].[Sumarno]

@obveznik int = Null,
@konto int = Null,
@datum1 datetime = Null,
@datum2 datetime = Null
    
AS
BEGIN

    WITH Buff(ID, Obveznik, Konto, Datum_knjizenja, Datum_dospijeca, Potrazuje, Duguje, [Status], Kamata, Datum_brisanja) AS 
    (
    SELECT ID, Obveznik, Konto, Datum_Knjizenja, Datum_Dospijeca, Potrazuje, Duguje, [Status], Kamata, CASE WHEN(Coalesce(@datum2, Getdate()) <= Coalesce(Datum_brisanja, Getdate())) THEN Coalesce(@datum2, Getdate()) ELSE Coalesce(Datum_brisanja, Getdate()) END
    FROM Data INNER JOIN Konta ON Konta.ID_Konto = Data.Konto INNER JOIN Obveznici ON Obveznici.ID_Obveznik = Data.Obveznik 
    WHERE [Status] <> 1 AND Obveznik = Coalesce(@obveznik, Obveznik) AND Konto = Coalesce(@konto, Konto)
    AND Datum_dospijeca >= Coalesce(@datum1, '1900-01-01') AND Datum_dospijeca <= Coalesce(@datum2, Getdate())
    UNION (SELECT (SELECT MAX(ID)+1 FROM Data), -1, -1, Getdate(), Getdate(), 0, 0, 0, 0, NULL)
    )
    
    SELECT a.Obveznik, a.Konto, a.Potrazuje, a.Duguje, a.Saldo, Coalesce(b.Kamata,0) AS Kamata, (a.Saldo + Kamata) AS Total FROM
    
    (
    SELECT Obveznik, Konto, SUM(Potrazuje) AS Potrazuje, SUM(Duguje) AS Duguje, SUM(Potrazuje - Duguje) AS Saldo
    FROM Buff GROUP BY Obveznik, Konto
    HAVING Obveznik = Coalesce(@obveznik, Obveznik) AND Konto = Coalesce(@konto, Konto)    
    ) a
     
    LEFT JOIN
        
    (
    SELECT Obveznik, Konto, SUM(Kamata) AS Kamata
    
    FROM
        (
        SELECT DISTINCT 
            Buff.Obveznik, Buff.Konto,
            (                
            Coalesce(
                (
                SELECT(SUM(t.Potrazuje - t.Duguje)) AS Saldo FROM Buff t 
                WHERE t.Datum_dospijeca <= Buff.Datum_dospijeca 
                AND t.Datum_dospijeca < Buff.Datum_brisanja
                AND t.Obveznik = Buff.Obveznik
                AND t.Konto = Buff.Konto
                AND t.Kamata = 1
                )
                ,
                0
                )
            )
            * 0.0003 * 
            Coalesce(
                DateDiff(
                    day, 
                    Buff.Datum_dospijeca, 
                    (
                    Coalesce(
                        (
                        SELECT MIN(t.Datum_dospijeca) AS Sledeci FROM Buff t 
                        WHERE t.Datum_dospijeca > Buff.Datum_dospijeca
                        AND (t.Datum_dospijeca < Buff.Datum_brisanja)
                        AND (t.Obveznik = Buff.Obveznik OR t.Obveznik = -1)                            AND (t.Konto = Buff.Konto OR t.Konto = -1)
                        )
                        ,
                        CASE 
                        WHEN(Buff.Datum_dospijeca < Buff.Datum_brisanja) 
                        THEN Buff.Datum_brisanja
                        ELSE Buff.Datum_dospijeca
                        END
                        )                        
                    )
                )
            ,0)AS Kamata
            FROM Buff                                
        ) Temp
    
    GROUP BY Temp.Obveznik, Temp.Konto
    
    HAVING Temp.Obveznik <> -1    
    
    )b
    
    ON
    
    b.Konto = a.Konto AND b.Obveznik = a.Obveznik 

    ORDER BY a.Obveznik, a.Konto
END


Ako bude potreban kakav komentar za proceduru, tu sam.

Pozdrav i hvala...
Prikačeni fajlovi
 
Odgovor na temu

mmix
Miljan Mitrović
Profesorkin muz
Passau, Deutschland

SuperModerator
Član broj: 17944
Poruke: 6042



+4631 Profil

icon Re: Spora stored procedure, sta sad?15.06.2009. u 16:30 - pre 180 meseci
nemam sad SQL server pri ruci da pogledam SQL plan, ali ono sto mi je odmah ubolo uci je CASE-WHEN struktura u nested select-u, query optimizer to ne moze da optimizuje nikako sto znaci da ce ta struktura da se izvrsi za svaki red koji prodje kroz where u query-u ciklicno za SVE parent iteracije ispocetka. Mozda gresim, pogledacu danas popodne kroz sqlplan.
Sloba je za 12 godina promenio antropološki kod srpskog naroda. On je od jednog naroda koji je bio veseo, pomalo površan, od jednog naroda koji je bio znatiželjan, koji je voleo da vidi, da putuje, da upozna,
od naroda koji je bio kosmopolitski napravio narod koji je namršten, mrzovoljan, sumnjicav, zaplašen, narod koji se stalno nešto žali, kome je stalno neko kriv… - Z.Đinđić
 
Odgovor na temu

Zidar
Canada

Član broj: 15387
Poruke: 3085
*.100.46-69.q9.net.



+79 Profil

icon Re: Spora stored procedure, sta sad?16.06.2009. u 15:10 - pre 180 meseci
Procedura ti je napotrebno zakomplikovana.

Prvo, umesto WITH Buff, efikasnije je upotrebis temp tabelu, recimo #Buff neka se zove. Posle upotrebis tu tabelu gd eti treba. A treba ti tamo gde radis nad njom GROUP BY. I to moze u jos jednu temp tabelu.
Seti se, ovo je stored procedura, dozvoljeno je raditi sta god hoces.

Drugo, kad god imas GROUP BY ti koristis HAVING kao kriterijum. Trebalo bi WHERE ako nije kriterijum po agregatnoj funkciji. Naopisao si ovo:
Code:

FROM     (SELECT   obveznik,
                       konto,
                       Sum(potrazuje)          AS potrazuje,
                       Sum(duguje)             AS duguje,
                       Sum(potrazuje - duguje) AS saldo
              FROM     buff
              GROUP BY obveznik,
                       konto
              HAVING   obveznik = Coalesce(@obveznik,obveznik)
                       AND konto = Coalesce(@konto,konto)
            ) AS A

Bez ikakvih drugih izmena (temp atbele i ostalo) trebalo bi pisati ovako:
Code:

FROM     (SELECT   obveznik,
                       konto,
                       Sum(potrazuje)          AS potrazuje,
                       Sum(duguje)             AS duguje,
                       Sum(potrazuje - duguje) AS saldo
              FROM     buff
              GROUP BY obveznik,
                       konto
              WHERE obveznik = Coalesce(@obveznik,obveznik)
                       AND konto = Coalesce(@konto,konto)
            ) AS A

HAVING pises ako hoces da filtriras po rezultatima funkcije SUM, znaci za kolone Potrazuje, Duguje, Saldo. WHERE filtrira rekorde pre nego sto uradi SUM. Ako koristis HAVING ond nema nikakvog rpefiltriranja, radi se SUM i gde treba i gde ne treba, pa se na kraju uzme samo ono sto ti treba.

No ovo je sve malo dete. Sad dolazi glavno. Tvoj LEFT JOIN. Imas tamo cetiri nivoa subkverija. Smanji malo dozivljaj.

Preporucujem da celu proceduru odradis prvo kao skriptu, sa temp tabelama i pregleanjem medjurezultata. Tako ces videti gde trosi najvise vremena.

I pokusaj da ne saljes NULL vrednosti kao parametre, pa da se vadis sa COALESCE. I to ti verovatno izbacuje indekse iz igre.

Zatim ,kazes negde ovo
Citat:
600 korisnika x 10 konta = 6000 poziva, mada ce vise od pola vratiti prazan set podataka (taj korisnik nema nista na tom kontu).
Zasto u startu ne eliminises korsnike koji neamju nista na tom kontu. pretpostavlajm da s eto moze uraditi u onom delu gde definises Buff. Daj dakle samo korisnike koji imaju nesto na kontu, izracunaj sta treba i sacuvaj rezultat kao temp tabelu. Onda to upari sa svim korisnicima (LEFT JOIN) tako d ati se prikazu svi korisnici, i proracun kamate samo za one koji nesto imaju.

Taktika je 'podeli pa vladaj', 'divide et conquere'. I zapamti, posto je u pitanju stored procedura, sve je dozvoljeno.


 
Odgovor na temu

Mikelly

Član broj: 16730
Poruke: 389
212.200.246.*



Profil

icon Re: Spora stored procedure, sta sad?16.06.2009. u 18:00 - pre 180 meseci
Prihvatam kritike, naravno. Sebe mogu nazvati samo advanced beginnerom sto se tice sql-a, ali ja sam se stvarno dobro namucio da napisem prethodnu proceduru, i sigurno da u njoj ima stvari koje su isforsirane, tj. nijesam umio drugacije. Zbog toga i pisem ovo.

Prije svega, evo sta ja trazim od procedure. Uzecu samo jedan korisnik i jedan konto (ionako se sve racuna u toj 'rezoluciji').
Code:

Obveznik    Konto    Datum        Duguje    Potrazuje    Saldo    RazlikaDana    Kamata (Saldo*RazlikaDana*0.0003)
1            2        1-1-2009    15        0            -15        14            -0,063
1            2        1-15-2009    23        0            -38        46            -0,5244
1            2        3-2-2009    0        40            +2        42            0,0252
1            2        4-13-2009    15        0            -13        18            -0,0702
1            2        5-1-2009    0        10            -3        40            -0,036
1            2        6-10-2009    20        0            -23


Sve je u svrhu racunanja kamata, da nije tog racunanja sve bi bilo prosto ko' pasulj. Moram izracunat saldo koji odgovara svakom zapisu (Running Sum - Korelisani query), i moram izracunat razliku izmedju dva uzastopna datuma (Opet korelisani query), jer na osnovu njih racunam kamate. Ova dva query-ja se izvrsavaju jedan za drugim, ne jedan u drugom, tako da, tehnicki, posle LEFT JOIN imam tri, ne cetiri nivoa subquery-ja. Plus su gornja dva zaista jako jednostavna, moras se slozit, a drugi (DISTINCT Obveznik, Konto) je momenat kada limitiram racunanja samo na one korisnike koji imaju nesto na nekom kontu. Ono 6000 poziva se odnosilo samo na aplikaciju, jer dok sam tamo, ne mogu znat ima li koji korisnik sta na kom kontu a da ne upitam bazu.

Onda, sto se tice WITH Buff, to mi nije bio prvi izbor, u momentu kad sam pocinjao da pisem proceduru nisam ni znao za WITH. Problem je bio u tome sto, kada pravim temp tabelu ja hocu da joj 'prilijepim' jedan dummy zapis na kraju (ono UNION na kraju WITH Buff). Taj dummy zapis je izuzetno bitan. Ima nulu i na duguje i na potrazuje, tako da ce saldo ostati nepromijenjen, a datum ce biti danasnji datum, pa cu dobiti kolika je kamata od zadnjeg unesenog zapisa do danasnjeg dana (ako ne unesem taj zapis, kamata se svim korisnicima racuna do zadnje aktivnosti, koja moze biti i mjesec dana stara).

Evo dje je tu problem. Kad pravim temp tabelu nakon koje dodje UNION dummy zapis, i fino joj dodijelim alijas, kao da nijesam nista dodava. Mozda vam ovo zvuci glupo, ali ja pisao ili ne pisao UNION, na isto mi dodje. Ovo sve pod uslovom da jednako mislimo kad kazemo 'temp' tabela. Ja pod tim podrazumijevam nesto tipa:
Code:

SELECT Temp.* 
FROM 
(
    SELECT * FROM Data 
    UNION(...)
) AS Temp


Ti kazes da mogu definisat temp tabelu pa je posle referencirat vise puta. Je li to nesto kao DECLARE #Buff(...), i onda sa njom sta mi je volja?

Sto se tice HAVING i WHERE hvala za tip, to nijesam znao, ali meni ni to ne funkcionise. Upravo sam izvrsio:
Code:

SELECT Obveznik, Konto, SUM(Potrazuje) AS Potrazuje, SUM(Duguje) AS Duguje, SUM(Potrazuje - Duguje) AS Saldo
FROM DATA GROUP BY Obveznik, Konto
WHERE Konto = Konto AND Obveznik = Obveznik


i evo sta mi kaze:
Msg 156, Level 15, State 1, Line 4
Incorrect syntax near the keyword 'WHERE'.

Kad ne ide, ne ide...

Ne znam, ako vas ne mrzi pogledajte jos malo, nije ni cudo u suprotnom.


Pozdrav i hvala.
 
Odgovor na temu

Zidar
Canada

Član broj: 15387
Poruke: 3085
*.100.46-69.q9.net.



+79 Profil

icon Re: Spora stored procedure, sta sad?16.06.2009. u 20:34 - pre 180 meseci
Pazi ovako, mi te ne kritikujemo, pokusavamo damo da nadjemo sta bi moglo da uzrokuje sporost. Ako ti procedura radi tacno, to je vec nesto. Moze se desiti da sa svim mogucim ubrzanjima svedes vreem na 3 sekunde, sto je bolje nego 6, ali zar je zaista bitno? Moze se desiti da ti i za veci broj rekorda ne bude sporije nego sada. Ali, ako barem radi, dobro je.

Elem, mene nije mrzelo da konstruisem tabelu kao sto je tvoja Data. Dodao sam test podatke za Obveznik = 1, Konto = 2, kako si dao u poslednjem postu. Od toga sam napravio 100 obveznika sa po 15 konta, svaki par (obveznik,konto) sa po 5-6 transakicja. Na kraju sam imao tabelu od nesto preko 7000 redova, znaci malkice vise nego ti.

Evo cele skripta. Na pocetku se kreira tabela sa podacima i unose test podaci. Na kraju je dat kveri (nema upotreba temp tabela) koji vraca sve rekorde za sve obveznike/konta za manje od 1 sekunde. Proanaliziraj, pa pokusaj da vidis sta je moglo jednostavnije od onoga sto si ti uradio.

Od ove skripte lako je napraviti stored procduru, ono sto sam stavio u DECLARE na pocetku proglasis da budu parametri procedure. Za sada, uzdrzi se od neobaveznih parametara. Mozes da radis proceduru, a moze i table valued function, kako ti je volja.
U zdravle



Code:

-- kreiramo #Temp tabelu #Data
IF OBJECT_ID('tempdb..#Data') IS NOT NULL DROP TABLE #Data
CREATE TABLE #Data    -- DROP TABLE Data
(
Obveznik int
, Konto int
, Potrazuje money
, Duguje Money
, Datum DateTime
, PRIMARY KEY (Obveznik, Konto, Datum)
)

-- SELECT COUNT(*) FROM #DAta
-- DELETE #Data

-- Podaci za (Obveznik = 1, Konto = 2)
-- Ove podatke necemo menjati tokom testiranja
INSERT INTO #Data (Obveznik, Konto, Datum, Duguje,Potrazuje ) VALUES (1 , 2,   '1-1-2009',    15,   0);
INSERT INTO #Data (Obveznik, Konto, Datum, Duguje,Potrazuje ) VALUES (1,  2,   '1-15-2009',   23,   0);
INSERT INTO #Data (Obveznik, Konto, Datum, Duguje,Potrazuje ) VALUES (1,  2,   '3-2-2009',    0,   40);
INSERT INTO #Data (Obveznik, Konto, Datum, Duguje,Potrazuje ) VALUES (1 , 2,   '4-13-2009',   15,   0);
INSERT INTO #Data (Obveznik, Konto, Datum, Duguje,Potrazuje ) VALUES (1 , 2,   '5-1-2009',    0,   10);
INSERT INTO #Data (Obveznik, Konto, Datum, Duguje,Potrazuje ) VALUES (1,  2,   '6-10-2009',   20,  0 );

-- pomocna tabela brojeva, trebace nam da sagradimo test records
IF OBject_ID('tempdb..#Numbers') IS NOT NULL DROP TABLE #Numbers
CREATE TABLE #NUmbers (Num int PRIMARY KEY)
DECLARE @N as int
SEt @N=1
WHILE @N<=100
BEGIN
INSERT INTO #NUmbers VALUES (@N)
SET @N = @N+1
END
--SELECT * FROM #NUmbers

-- SELECT * FROM Data
-- da napravimo malo test podataka:
-- Dodajmo jos konta za istog obveznika
INSERT INTO #DAta (    Obveznik, Konto,          Datum, Duguje, Potrazuje )
SELECT        Obveznik, Konto = Num, Datum, Duguje, Potrazuje
FROM #DAta 
JOIN #NUmbers ON 1=1
WHERE Obveznik = 1 AND Konto = 2
AND Num <=15
AND NUm <> 2
-- Sada imamo 15 konta za korisnika 1, sva imaju iste transakcije
-- Dovoljno dobro za testiranje

-- Sad cemo da napravimo po 15 konta za jos 100 korisnika
INSERT INTO #Data (Obveznik , Konto, Datum, Duguje, Potrazuje)
SELECT
Obveznik = Num, Konto, Datum, Duguje, Potrazuje
FROM #Data 
JOIN #NUmbers ON 1=1
WHERE Obveznik = 1
AND Num > 1

-- Sad imamo 9000 redova u test tabeli:
SELECT COUNT(*) FROm #Data

-- Sad cemo svaki sedmi rekord da uklonimo iz tabele, 
-- da bi malo transakcije bile razlicite od konta do konta, obveznika do obveznika
-- paznj! oVo izvrsite samo jednom!
; WITH SlucajniRedosled AS
(
SELECT 
D.*
, RedniBroj = Row_number() OVER (ORDER BY NewID())
FROM #DAta AS D
-- Ne diramo pocetni konto, zbog provere
WHERE NOT (Obveznik = 1 AND Konto = 2)
)
DELETE SlucajniRedosled
WHERE RedniBroj % 7 = 0
-- (1284 row(s) affected)

SELECT COUNT(*) FROM #Data    -- 7716


-- Sve do sada bila je samo priprema podataka. Nije potrebno razumeti,
-- dovoljno je odraditi skriptu ---

/**************************************************************************/
-- Odavde pa nadalje  radimo stvarni posao ---

-- Resenje bez temp tabela, citi kveri --
-- 
DECLARE @KamatnaStopa AS decimal (10,6)
--DECLARE @OBveznik int
--DECLARE @Konto int

SET @KamatnaStopa = 0.0003
--SEt @Obveznik = 1
--SEt @KOnto = 5

--SELECT * FROM #Data AS D
--WHERE D.Obveznik = @Obveznik 
--AND D.KOnto = @Konto

; WITH DnevniBalans AS
(
SELECT 
    Obveznik
    , Konto
    , Datum
    , DnevniSaldo = SUM(Potrazuje-Duguje)
FROM #Data AS D
-- Ako treba, ovde ubacujemo WHERE da bi racunali samo sta treba
-- isti where ubacujemo i kad racunamo OdDatuma DOdatuma
-- vidi dole.....
--WHERE D.Obveznik = @Obveznik AND D.KOnto = @Konto 
GROUP BY Obveznik, Konto, Datum
)
, Kumulativ AS
(
SELECT 
    Obveznik
    , Konto
    , Datum
    , RunningSum = (SELECT SUM(DnevniSaldo) 
                    FROM DnevniBalans AS B
                    WHERE B.datum <= A.Datum
                    AND A.Obveznik = B.Obveznik
                    AND A.konto = B.Konto
                    )                                        
FROM DnevniBalans AS A
)
, OdDatumDoDatuma AS
(
SELECT 
    Obveznik
    , Konto
    , OdDatuma = (SELECT MAX(Datum) 
                    FROM #Data AS B 
                    WHERE B.datum < A.Datum
                    AND A.Obveznik = B.Obveznik
                    AND A.konto = B.Konto
                )
    , DoDatuma = Datum
FROM #Data AS A
-- i ovde ubacujemo WHERE da bi racunali samo sta treba
--WHERE A.Obveznik = @Obveznik AND A.KOnto = @Konto 
GROUP BY Obveznik, Konto, Datum
)
SELECT 
    K.Obveznik
    , K.Konto
    , K.Datum
    , K.RunningSum AS Saldo
    , D.DoDAtuma
    , BrojDana = DATEDIFF (day, K.Datum, COALESCE(D.DoDatuma, Getdate())) 
    , KamatnaStopa_Pct = @KamatnaStopa * 100.0
    , Kamata = K.RunningSum 
                * DATEDIFF (day, K.Datum, COALESCE(D.DoDatuma, Getdate()))  
                * @KamatnaStopa
FROM Kumulativ AS K
JOIN OdDatumDoDatuma AS D ON K.Obveznik = D.Obveznik
                            AND K.Konto = D.Konto
                            AND K.Datum = D.OdDatuma





U zdravle i srecan rad



 
Odgovor na temu

Zidar
Canada

Član broj: 15387
Poruke: 3085
*.100.46-69.q9.net.



+79 Profil

icon Re: Spora stored procedure, sta sad? OOPS, ne prikazuje poslednji interval16.06.2009. u 21:21 - pre 180 meseci
OOPS, greska, kveri ne prikazuje interval od poslednje transakcije do danas. Ni originalni kveri to ne radi, pa nisam samo ja kriv
Originalni kveri pogresno koristi GetDate() funkciju. U movoj skripti ima kako se to radi pravilno.
Code:

-- kreiramo #Temp tabelu #Data
IF OBJECT_ID('tempdb..#Data') IS NOT NULL DROP TABLE #Data
CREATE TABLE #Data    -- DROP TABLE Data
(
Obveznik int
, Konto int
, Potrazuje money
, Duguje Money
, Datum DateTime
, PRIMARY KEY (Obveznik, Konto, Datum)
)

-- SELECT COUNT(*) FROM #DAta
-- DELETE #Data

-- Podaci za (Obveznik = 1, Konto = 2)
-- Ove podatke necemo menjati tokom testiranja
INSERT INTO #Data (Obveznik, Konto, Datum, Duguje,Potrazuje ) VALUES (1 , 2,   '1-1-2009',    15,   0);
INSERT INTO #Data (Obveznik, Konto, Datum, Duguje,Potrazuje ) VALUES (1,  2,   '1-15-2009',   23,   0);
INSERT INTO #Data (Obveznik, Konto, Datum, Duguje,Potrazuje ) VALUES (1,  2,   '3-2-2009',    0,   40);
INSERT INTO #Data (Obveznik, Konto, Datum, Duguje,Potrazuje ) VALUES (1 , 2,   '4-13-2009',   15,   0);
INSERT INTO #Data (Obveznik, Konto, Datum, Duguje,Potrazuje ) VALUES (1 , 2,   '5-1-2009',    0,   10);
INSERT INTO #Data (Obveznik, Konto, Datum, Duguje,Potrazuje ) VALUES (1,  2,   '6-10-2009',   20,  0 );

-- pomocna tabela brojeva, trebace nam da sagradimo test records
IF OBject_ID('tempdb..#Numbers') IS NOT NULL DROP TABLE #Numbers
CREATE TABLE #NUmbers (Num int PRIMARY KEY)
DECLARE @N as int
SEt @N=1
WHILE @N<=100
BEGIN
INSERT INTO #NUmbers VALUES (@N)
SET @N = @N+1
END
--SELECT * FROM #NUmbers

-- SELECT * FROM Data
-- da napravimo malo test podataka:
-- Dodajmo jos konta za istog obveznika
INSERT INTO #DAta (    Obveznik, Konto,          Datum, Duguje, Potrazuje )
SELECT        Obveznik, Konto = Num, Datum, Duguje, Potrazuje
FROM #DAta 
JOIN #NUmbers ON 1=1
WHERE Obveznik = 1 AND Konto = 2
AND Num <=15
AND NUm <> 2
-- Sada imamo 15 konta za korisnika 1, sva imaju iste transakcije
-- Dovoljno dobro za testiranje

-- Sad cemo da napravimo po 15 konta za jos 100 korisnika
INSERT INTO #Data (Obveznik , Konto, Datum, Duguje, Potrazuje)
SELECT
Obveznik = Num, Konto, Datum, Duguje, Potrazuje
FROM #Data 
JOIN #NUmbers ON 1=1
WHERE Obveznik = 1
AND Num > 1

-- Sad imamo 9000 redova u test tabeli:
SELECT COUNT(*) FROm #Data

-- Sad cemo svaki sedmi rekord da uklonimo iz tabele, 
-- da bi malo transakcije bile razlicite od konta do konta, obveznika do obveznika
-- paznj! oVo izvrsite samo jednom!
; WITH SlucajniRedosled AS
(
SELECT 
D.*
, RedniBroj = Row_number() OVER (ORDER BY NewID())
FROM #DAta AS D
-- Ne diramo pocetni konto, zbog provere
WHERE NOT (Obveznik = 1 AND Konto = 2)
)
DELETE SlucajniRedosled
WHERE RedniBroj % 7 = 0
-- (1284 row(s) affected)

SELECT COUNT(*) FROM #Data    -- 7716


-- Sve do sada bila je samo priprema podataka. Nije potrebno razumeti,
-- dovoljno je odraditi skriptu ---

/**************************************************************************/
-- Odavde pa nadalje  radimo stvarni posao ---

-- Resenje bez temp tabela, cisti kveri --
-- 
DECLARE @KamatnaStopa AS decimal (10,6)
DECLARE @OBveznik int
DECLARE @Konto int

SET @KamatnaStopa = 0.0003
SEt @Obveznik = 1
SEt @KOnto = 2

-- Ovo je za testiranje
--SELECT * FROM #Data AS D
--WHERE D.Obveznik = @Obveznik 
--AND D.KOnto = @Konto
--ORDER BY Obveznik, Konto, Datum

; WITH MyUnion AS
(
-- Ako treba, ovde ubacujemo WHERE da bi racunali samo sta treba
-- isti where ubacujemo i kad racunamo OdDatuma DOdatuma
-- vidi dole.....
SELECT Obveznik, Konto, Potrazuje, Duguje, Datum
FROM #Data
--WHERE D.Obveznik = @Obveznik AND D.KOnto = @Konto 
UNION ALL
SELECT Obveznik, Konto, Potrazuje=0, Duguj=0, Datum = CAST(CONVERT(CHAR(11),GETDATE(),113) AS datetime)
FROM #Data
--WHERE D.Obveznik = @Obveznik AND D.KOnto = @Konto 
GROUP BY Obveznik, Konto

-- Kako se GetDate() svodi na oblik 'samo datum, bez minuta i sekundi'
-- SELECT Getdate() AS GetDate, CAST(CONVERT(CHAR(11),GETDATE(),113) AS datetime) AS SamoDatum
)
, DnevniBalans AS
(
SELECT 
    Obveznik
    , Konto
    , Datum
    , DnevniSaldo = SUM(Potrazuje-Duguje)
FROM MyUnion AS D
GROUP BY Obveznik, Konto, Datum
)
--SELECT * FROm DnevniBalans WHERE Obveznik = 1 AND KOnto =2 -- ovo je ostalo od testiranja kverija korak po korak
, Kumulativ AS
(
SELECT 
    Obveznik
    , Konto
    , Datum
    , RunningSum = (SELECT SUM(DnevniSaldo) 
                    FROM DnevniBalans AS B
                    WHERE B.datum <= A.Datum
                    AND A.Obveznik = B.Obveznik
                    AND A.konto = B.Konto
                    )                                        
FROM DnevniBalans AS A
)
--SELECT * FROM Kumulativ WHERE Obveznik = 1 AND KOnto =2
, OdDatumDoDatuma AS
(
SELECT 
    Obveznik
    , Konto
    , OdDatuma = (SELECT MAX(Datum) 
                    FROM MyUnion AS B 
                    WHERE B.datum < A.Datum
                    AND A.Obveznik = B.Obveznik
                    AND A.konto = B.Konto
                )
    , DoDatuma = Datum
FROM MyUnion AS A
GROUP BY Obveznik, Konto, Datum
)
--SELECT * FROm OdDatumDoDatuma WHERE Obveznik = 1 AND KOnto =2
SELECT 
    K.Obveznik
    , K.Konto
    , K.Datum
    , K.RunningSum AS Saldo
    , D.DoDAtuma
    , BrojDana = DATEDIFF (day, K.Datum, COALESCE(D.DoDatuma, Getdate())) 
    , KamatnaStopa_Pct = @KamatnaStopa * 100.0
    , Kamata = K.RunningSum 
                * DATEDIFF (day, K.Datum, COALESCE(D.DoDatuma, Getdate()))  
                * @KamatnaStopa
FROM Kumulativ AS K
JOIN OdDatumDoDatuma AS D ON K.Obveznik = D.Obveznik
                            AND K.Konto = D.Konto
                            AND K.Datum = D.OdDatuma
WHERE K.Obveznik = @Obveznik AND K.Konto = @Konto    -- ovo je za testiranje, treba obrisati ovaj WHERE
----- WHERE ne bi stavljali ovde nego  na pocetku, u MyUnion
ORDER BY
    K.Obveznik
    , K.Konto
    , K.Datum

-- 7716 rows in 0 seconds :-)


kako bi silo sa temp tabelama? Svaka stavka iz WITH bila bi posebna temp tabela.
Prvo bi islo:
SELECT *
INTO #MyUnion
FROM
(
SELECT * FROM #Data
UNION ALL
SELECT Obveznik, Konto, Potrazuje=0, Duguj=0, Datum = CAST(CONVERT(CHAR(11),GETDATE(),113) AS datetime) FROM #Data
) AS X

Pa onda:
SELCT
......
INTO #DnevniBalans
FROM #MyUnion

pa dalje

SELECT
.....
INTO #Kumulativ
FROM #DnevniBAlans


i tako redom.

U svakom koraku bismo kreirali jednu temp tabelu koja bi cuvala medjurezultate. To bismo mogli da kontrolisemo, pregledamo i doterujemo dok ne proradi.

Za stored proceduru, obicno je dovoljno napraviti temp atbelu za set podataka koji vraca najvise rekorda.

 
Odgovor na temu

Mikelly

Član broj: 16730
Poruke: 389
85.94.126.*



Profil

icon Re: Spora stored procedure, sta sad?17.06.2009. u 10:31 - pre 180 meseci
Zidar, hvala ti puno, stvarno se dosta moze naucit iz tvoje 'pisanije'. Dao si mi domaci zadatak. Mada ce mi trebat vremena da sve ovo protumacim.

Pitacu te sigurno neku sitnicu iz svega ovog sto si napisao.

A zasto kazes da originalni query ne racuna interval od zadnje transakcije do danas i zasto moram GetDate() konvertovat u samo datum? Da Datediff(day,....) ne pogrijesi za 1, jeli, ili nesto drugo?

Pozdrav i hvala puno.

 
Odgovor na temu

Zidar
Canada

Član broj: 15387
Poruke: 3085
*.100.46-69.q9.net.



+79 Profil

icon Re: Spora stored procedure, sta sad?17.06.2009. u 14:07 - pre 180 meseci
Pitaj slobodno :-)

Zasto se GetDate mora konvertovati u 'Samo datum bez sasti, minuta i sekundi'? Vidi primer:
Code:

DECLARE @NekiDatum DateTime

SET @NekiDatum = '20090617'    -- YYYYMMDD, 16 Juli 2009

SELECT 
    @NekiDatum AS NekiDatum
    , GetDAte() AS Danas
    , DaLiSuIsti = CASE 
                    WHEN @NekiDatum = GetDAte() THEN 'Isti su' 
                    ELSE 'Nisu isti' 
                END
    , SadSuIsti = CASE 
                    WHEN @NekiDatum <= (GetDAte()+1)  THEN 'Isti su' 
                    ELSE 'Nisu isti' 
                END


NekiDatum               Danas                   DaLiSuIsti SadSuIsti
----------------------- ----------------------- ---------- ---------
2009-06-17 00:00:00.000 2009-06-17 09:01:21.030 Nisu isti  Isti su

(1 row(s) affected)

GetDate() vraca sadsanji TRENUTAK, ne sadasnji datum. Tvoji datumi u tabeli su bez sati, minuta i sekundi. Primeti da kad sam definisao @NekiDatum, samo sam zadao godinu, mesec i datum. Kad to otvoris sa SELECT, prikazu se i 00:00:00.000 za sate, minute i sekunde. Moj @NekiDatum se slaze sa GetDate samo u godina/mesec/datum delu. U ostatku s ene slazu, pa prema tome nisu isti.

Da se uvesri, odvrti tvoj spori kveri i pogledaj bas inaj primer Obveznik = 1 Konto = 2. Nemas interval od 10 jula pa nadalje. Nemam ga ni ja u prvom kveriju, ali ga imam u drugom.

Dobro je sto su ti datumi u tabeli samo godina, mesec, dan. Inace bi morao i njih ili da konvertujes, ili da umesto '=' koristis '<= (GetDAte()+1)'. Opcija '<= (GetDate() +1) bi radila i u kveriju koji pises, ali sam zeleo da skrenem paznju na drugu mogucnost. Konverzija vodi do ocigledna jednakosti. Ako koristimo '<= (GetDAte()+1)' onda treba da razumemo zasto je to bas tako, posto nije bas ocigledno.

MS SQL 2008 dodnosi novi tip podataka DATE, koji je 'samo godina, mesec i dan' kao i TIME koji je 'samo sati, minuti i sekunde' pa bi trebalo da bude lakse. Dotle, pazljivo sa GetDate() i pazljivo proveri rezultate koje dobijes.

:-)
 
Odgovor na temu

Mikelly

Član broj: 16730
Poruke: 389
78.155.55.*



Profil

icon Re: Spora stored procedure, sta sad?19.06.2009. u 13:23 - pre 180 meseci
Evo, poslije dosta muke, zakljucak: originalni kveri radi sporo zbog WITH klauzule. Kada WITH eliminisem iz procedure i zamijenim samo sa tabelom DATA, vrijeme se sa 10 sekundi spusta na 2-3. Ali tada ne dobijam tacne rezultate, ni blizu.

Originalni kveri, medjutim, ispravno racuna intervale. Obrati paznju na zadnji UNION zapis (podesavam korisnika i konto na -1) i datum na danasnji. Taj zapis ce biti zadnji zapis za SVE parove korisnik, konto prilikom racunanja intervala izmedju zadnjeg zapisa i danasnjeg datuma.

Pogledaj krajnje unutrasnje korelisane kverije, za racunanje salda i razlike dva uzastopna datuma.

Code:

SELECT(SUM(t.Potrazuje - t.Duguje)) AS Saldo FROM Buff t 
WHERE t.Datum_dospijeca <= Buff.Datum_dospijeca 
AND t.Datum_dospijeca < Buff.Datum_brisanja
AND t.Obveznik = Buff.Obveznik
AND t.Konto = Buff.Konto
AND t.Kamata = 1

i
Code:

SELECT MIN(t.Datum_dospijeca) AS Sledeci FROM Buff t 
WHERE t.Datum_dospijeca > Buff.Datum_dospijeca
AND (t.Datum_dospijeca < Buff.Datum_brisanja)
AND (t.Obveznik = Buff.Obveznik OR t.Obveznik = -1)
AND (t.Konto = Buff.Konto OR t.Konto = -1)


Racuna se saldo do ODREDJENOG ( SUM do datuma <= od trenutnog ) zapisa (uzmimo slucaj da to bude zadnji zapis) i interval izmedju tog zapisa i njemu SLEDECEG (MIN datum > od trenutnog ) gledajuci sortirano po datumu (u ovom slucaju ce to biti dummy zapis koji na konto i korisnik ima -1, a za datum ima danasnji). U svakom drugom slucaju racunaju se salda i intervali izmedju dva validna zapisa.

Running sum za saldo uzima u obzir (naravno) samo zapise za taj korisnik i taj konto, dok prilikom racunanja intervala korelisani query uzima u obzir i te zapise i dummy zapis (taj zapis se tako prilijepi na kraj svakog seta zapisa za par korisnik, konto):
Code:

AND (t.Obveznik = Buff.Obveznik OR t.Obveznik = -1)
AND (t.Konto = Buff.Konto OR t.Konto = -1)


Upravo je taj dummy zapis i, posredno, izazvao sporost. Zbog njega sam i uveo WITH.



E sad, bio bih ti jako zahvalan, kada bi mi pomogao oko alternative za WITH.

Probao sam sa CREATE TABLE unutar procedure ali mi uvijek prijavljuje gresku na zadnjoj liniji prije BEGIN.

Znaci sustina onoga sto trazim je ono sto si rekao na pocetku prvog posta. Kreirati temp tabelu (gdje bih mogao smjestiti podset podataka iz tabele DATA i dodati joj dummy zapis na kraju). Kako kreirati tu temp tabelu? Mozda je to stvarno jako jednostavno, ali ja stvarno ne znam kako...


Pozdrav, i jos jednom puno hvala.

 
Odgovor na temu

Zidar
Canada

Član broj: 15387
Poruke: 3085
*.100.46-69.q9.net.



+79 Profil

icon Re: Spora stored procedure, sta sad?19.06.2009. u 17:31 - pre 180 meseci
Ama bre, zar nema u Books on line nesto temp tabelama? Pametan si decko, umes da napises onaj monstrum od kverija, a ne umes da pronadjes kako se pravi temp tabela???
Code:

CREATE TABLE #MyTemp
(
Ime varchar(50)
, Prezime varchar(50)
)

---A moze i ovako (kao Make TAble query u Accessu):

SELECT 

INTO #SysColumns
FROM SySColumns


Evo tvoje procedure:
Code:

ALTER PROCEDURE [dbo].[Sumarno]

@obveznik int = Null,
@konto int = Null,
@datum1 datetime = Null,
@datum2 datetime = Null
    
AS
--BEGIN    -- sta ce ti BEGIN/END?

--    WITH Buff(ID, Obveznik, Konto, Datum_knjizenja, Datum_dospijeca, Potrazuje, Duguje, [Status], Kamata, Datum_brisanja) AS 
-- SELECT ... INTO #Buff FROM .. WHERE ....

-- 1) napravi #Buff
SELECT 
    ID, Obveznik, Konto, Datum_Knjizenja, Datum_Dospijeca
    , Potrazuje, Duguje, [Status], Kamata
    , Datum_brisanja = CASE 
                            WHEN(Coalesce(@datum2, Getdate()) <= Coalesce(Datum_brisanja, Getdate())) 
                            THEN Coalesce(@datum2, Getdate()) 
                            ELSE Coalesce(Datum_brisanja, Getdate()) 
                        END
INTO #Buff
FROM Data 
INNER JOIN Konta ON Konta.ID_Konto = Data.Konto 
INNER JOIN Obveznici ON Obveznici.ID_Obveznik = Data.Obveznik 
WHERE [Status] <> 1 
AND Obveznik = Coalesce(@obveznik, Obveznik) 
AND Konto = Coalesce(@konto, Konto)
AND Datum_dospijeca >= Coalesce(@datum1, '1900-01-01') 
AND Datum_dospijeca <= Coalesce(@datum2, Getdate())

--UNION (SELECT (SELECT MAX(ID)+1 FROM Data), -1, -1, Getdate(), Getdate(), 0, 0, 0, 0, NULL)


-- 2) Umesto UNION, dodajemo jos jedan dummy rekord u #Buff, INSERT INTO #Buff:
INSERT INTO #Buff
(ID, Obveznik, Konto, Datum_knjizenja, Datum_dospijeca
, Potrazuje, Duguje, [Status], Kamata, Datum_brisanja)
SELECT 
    MAX(ID)+1 AS ID
    , -1 AS Obveznik
    , -1 AS Konto
    , Getdate() AS Datum_knjizenja
    , Getdate() AS Datum_dospijeca
    , 0 AS Potrazuje
    , 0 AS Duguje
    , 0 AS [Status]
    , 0 AS Kamata
    , NULL AS Datum_brisanja
FROM Data

--3) dalje valjda moze kako si napisao, a mozes i to da razbijes u temp tabele ako treba:
    
    SELECT a.Obveznik, a.Konto, a.Potrazuje, a.Duguje, a.Saldo, Coalesce(b.Kamata,0) AS Kamata, (a.Saldo + Kamata) AS Total FROM
    
    (
    SELECT Obveznik, Konto
    , SUM(Potrazuje) AS Potrazuje
    , SUM(Duguje) AS Duguje
    , SUM(Potrazuje - Duguje) AS Saldo
    FROM #Buff GROUP BY Obveznik, Konto
    WHERE Obveznik = Coalesce(@obveznik, Obveznik) AND Konto = Coalesce(@konto, Konto)
--    HAVING Obveznik = Coalesce(@obveznik, Obveznik) AND Konto = Coalesce(@konto, Konto)    
    ) a
     
    LEFT JOIN
        
    (
    SELECT Obveznik, Konto, SUM(Kamata) AS Kamata
    
    FROM
        (
        SELECT DISTINCT 
            #Buff.Obveznik, #Buff.Konto,
            (                
            Coalesce(
                (
                SELECT(SUM(t.Potrazuje - t.Duguje)) AS Saldo FROM #Buff t 
                WHERE t.Datum_dospijeca <= #Buff.Datum_dospijeca 
                AND t.Datum_dospijeca < #Buff.Datum_brisanja
                AND t.Obveznik = #Buff.Obveznik
                AND t.Konto = #Buff.Konto
                AND t.Kamata = 1
                )
                ,
                0
                )
            )
            * 0.0003 *    ---- Zasto kamata nije parametar? Sta ako se promeni?
            Coalesce(
                DateDiff(
                    day, 
                    #Buff.Datum_dospijeca, 
                    (
                    Coalesce(
                        (
                        SELECT MIN(t.Datum_dospijeca) AS Sledeci FROM #Buff t 
                        WHERE t.Datum_dospijeca > #Buff.Datum_dospijeca
                        AND (t.Datum_dospijeca < #Buff.Datum_brisanja)
                        AND (t.Obveznik = #Buff.Obveznik OR t.Obveznik = -1) 
                        AND (t.Konto = #Buff.Konto OR t.Konto = -1)
                         )
                        ,
                        CASE 
                        WHEN(#Buff.Datum_dospijeca < #Buff.Datum_brisanja) 
                        THEN #Buff.Datum_brisanja
                        ELSE #Buff.Datum_dospijeca
                        END
                        )                        
                    )
                )
            ,0)AS Kamata
            FROM #Buff                                
        ) Temp
    
    GROUP BY Temp.Obveznik, Temp.Konto
    
    HAVING Temp.Obveznik <> -1    
    
    )b
    
    ON
    
    b.Konto = a.Konto AND b.Obveznik = a.Obveznik 

    ORDER BY a.Obveznik, a.Konto
--END
GO


Kad vec radis stored proceduru, zar nije lepse da i kamata bude parametar? Sta ako se promeni? Ja sam ziveo u doba kad se kamata menajla svaki dan.

Sto se tice toga da li procedura vraca interval do danasnjeg datuma, to sam zakljucio na osnovu greske u mojoj proceduri. Moja procedura ja zaboravljala na taj interval bez obzira na UNION sa pocetka. Razlog je bio GetDate(), kako sam ti vec objasnio. I primer koji si bio dao, krajnji rezultat, nije pokazivao nista za tekuci rdatum, poslednji interval nije bio tamo. Ako kazes da ipak jeste, OK, neka bude. Kod mene nije htelo sa Getdate, nego sam morao da se dovijam. Moguce je da se kod tebe ono COALESCE ne vraca GetDate() jer drugi podaci postoje. To samo znaci se greska moze javiti kasnije, kad se tako podese podaci.

 
Odgovor na temu

Mikelly

Član broj: 16730
Poruke: 389
*.186.crnagora.net.



Profil

icon Re: Spora stored procedure, sta sad?22.06.2009. u 13:02 - pre 180 meseci
Gotovo!

Sa temp tabelom procedura radi za 2-3 sekunde. Ima li nacina da vidim tacno koliko joj je trebalo a ne samo ono dolje u cosku management studia, jer mi tako daje samo sekunde, nista preciznije?

Hvala ti puno na uputima, probao sam ja i prije na osnovu skripte sto si napisao, ali sam pravio glupu gresku. Isao sam:

Code:

CREATE TABLE #Buff
(
     int Obveznik,
     int Konto
)


umjesto

Code:

CREATE TABLE #Buff
(
     Obveznik int,
     Konto int
)


Kompajlira mi proceduru, ali prilikom execute prijavi gresku. Sad znam, i ove temp tabele su bas super stvar.

Razmisljao sam i zasto sa WITH radi toliko sporije. Mozda, posto je WITH tu primarno da podrzi rekurziju, on prilikom svakog FROM Buff, nanovo izvrsi upit koji definise Buff, ocekujuci neke promjene u rezultujucem setu, i tu gubi vrijeme.

Uglavnom, sad je sve podnosljivo OK.

Hvala ti puno jos jednom, i ocekuj mozda jos po koje pitanje iz skripte, posebno ono RowNumber OVER (...)

Pozdrav.
 
Odgovor na temu

Zidar
Canada

Član broj: 15387
Poruke: 3085
*.100.46-69.q9.net.



+79 Profil

icon Re: Spora stored procedure, sta sad?22.06.2009. u 13:52 - pre 180 meseci
OK, srecan rad, i slobodno pitaj.

Citat:
Mozda, posto je WITH tu primarno da podrzi rekurziju, on prilikom svakog FROM Buff, nanovo izvrsi upit koji definise Buff, ocekujuci neke promjene u rezultujucem setu, i tu gubi vrijeme.
Ovo nije bas 100% tacno. WITH jeste primarno za pisanje slozenih kverija, rekurzije su samo jedna specificnost. I moj kveri je napisan sa WITH, pa radi brzo. Tvoj originalni kveri je prekomplikovan i optimizer jednostavno ne moze da ga bas optimizuje.

Rekao ti je Mmix sta bi moglo da bude problem, subkveriji, CASE i indeksi. Medjutim, pravilo broj 1 glasi: kveri treba da vrati tacne rezultate. Koliko razumem, tvoj kveri to radi. To sto nije bas brz, to je sekundarno. Dok ga ubrzas, taman nesto novo naucis.



 
Odgovor na temu

[es] :: MS SQL :: Spora stored procedure, sta sad?

[ Pregleda: 2797 | Odgovora: 17 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.