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

Kako ubrzati upit - optimizovati

[es] :: Access :: Kako ubrzati upit - optimizovati

[ Pregleda: 3828 | Odgovora: 8 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

gorancho
Srbija

Član broj: 149371
Poruke: 89
79.101.221.*



Profil

icon Kako ubrzati upit - optimizovati19.01.2009. u 00:13 - pre 185 meseci
Imam tabelu tipa BrRacuna, SifraKorisnika, ProcitanoStanje. Po jednom racunu su evidentirani svi korisnici kojima je procitano tada stanje (dakle NE SVIM KORISNICIMA). Kako da dobijem potrošnju po proizvoljnom računu

PotrošnjaPoRačunu(X) = StanjePoRačunu(X)- StanjePoRačunu(prvom predhodniku od X)

Problem sam rešio sa funkcijom i rekord setovima po modelu filtriranja tabele za sve NE VEĆE RAČUNE od željenog, filtriranja po korisniku i rs.MoveLast i rs.MovePrevious. ALI OVAKO RADI NEVEROVATNO SPORO.

MOŽE LI OVO BRŽE i što je još važnije KAKO ????

 
Odgovor na temu

Getsbi

Moderator
Član broj: 124608
Poruke: 2831



+45 Profil

icon Re: Kako ubrzati upit - optimizovati19.01.2009. u 05:48 - pre 185 meseci
Probaj da index-siraš tabelu po onom polju po kojem radiš filtriranje.
Predpostavljam po: BrRacuna + SifraKorisnika.
 
Odgovor na temu

Zidar
Canada

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



+79 Profil

icon Re: Kako ubrzati upit - optimizovati19.01.2009. u 14:42 - pre 185 meseci
Dobro je da stavis index kako je Getsbi rekao ali te to nece ubrzati. Treba ti kveri koji ce odrariti posao umesto rekordseta. Ako postavis tabelu sa test podacima, mozemo d anapravimo nesto.

Generalno pitanje koje resavas jeste:

za zadati racun, pronaci ProcitanoStanje onog racuna koji pripada istom korisniku kao zadati racun a pripada [prethodnom citanju. kako ce kveri da odredi 'prethodno citanje'? Ako je BrRacuna stalno rastuci broj, onda prethodni racun ima manji BrRacuna nego tekuci. Problem je za N citanaj postoji N-1 citanja gde je BrRacuna manji nego tekuci. Koji je bas prethodni? Pa to je maksimalan od onih gde je broj racuna manji od tekuceg. Komplikovano? Donekle, bice to kveri sa dva nivoa subkverija. Daj konkretne podatke pa da ga napisemo.

:-)
 
Odgovor na temu

Zidar
Canada

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



+79 Profil

icon Re: Kako ubrzati upit - optimizovati19.01.2009. u 15:05 - pre 185 meseci
Evo kako sam ja to zamislio: trebaju ti dva kverija. Prvi kveri odredjuje sta je to 'prethodni racun'. Drugi kveri dovlaci citanje za taj 'prethodni racun' i vrsi oduzimanje tako da dobijes potrosnju izmedju dva citanja. Sve moze da se napise kao jedan kveri, ali mi se cini da je ovako jasnije. Nadam se da je ovo pomoglo.


Medjutim, hteo bih da skrenem paznju na jos nesto, u vezi sa kodom. Ako mozes, prikaci primer, sa tvojim kodom, hteo bih da skrenem paznju na jednu caku koja mze da kod sa rekordsetima ubrza znacajno. U ovom konkretnom slucaju, kveri ce uvek raditi brze, ali hocu da skrenem paznju na nesto sto verovatno postoji u tvom kodu a moze se resiti mnogo brze, isto tako u kodu.

Prikačeni fajlovi
 
Odgovor na temu

Getsbi

Moderator
Član broj: 124608
Poruke: 2831



+45 Profil

icon Re: Kako ubrzati upit - optimizovati19.01.2009. u 19:57 - pre 185 meseci
Ja sam razumeo da je on već napravi SQL upit u VBA kodu jer spominje filtriranje i kaže:

Citat:
gorancho: ......Problem sam rešio sa funkcijom i rekord setovima po modelu filtriranja tabele za sve NE VEĆE RAČUNE od željenog, filtriranja po korisniku i rs.MoveLast i rs.MovePrevious. ALI OVAKO RADI NEVEROVATNO SPORO......


Tako da mi je ostalo jedino da mu posavetujem indeksiranje.
 
Odgovor na temu

Zidar
Canada

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



+79 Profil

icon Re: Kako ubrzati upit - optimizovati19.01.2009. u 22:08 - pre 185 meseci
@Getsbi: moguce da si u pravu. Meni se opet ucinilo da nije umeo da resi problem drugacije nego preko funkcije koja koristi rekordsete pa onda mozda u kveriju poziva tu funkciju....
Citat:
Kako da dobijem potrošnju po proizvoljnom računu

PotrošnjaPoRačunu(X) = StanjePoRačunu(X)- StanjePoRačunu(prvom predhodniku od X)

Mozfd je moje rezonovanje komplikovano (poziv funkcije iz kverija) ali sam video da to rade ljudi u praksi, i to ljudi koji znaju sta rade. Nije greh u ovom slucaju. Ne cudim se jer problem u stvari nije jednostavan. U MS SQL ja bih to napisao kao kveri sa dva nivoa subkverija, a to nije bas trivijalno. Trablo mi je malo da promozgam da bih to prebveo na Access SQL dijalekt. Nije bas mozgalica, ali nije ni trivijalno.

U svakom slucaju hteo bih da vidim kod, ne da bih ga kritikovao, nego da skrenm paznju na moguce jednostavno ubrzanje u slucajevima kad se zaista motra ici preko rekordseta.

Tacno je da je 'no code the best coda of all' ali kad ne mozes da se setis kako to da uradis, i 'slow code is better solution than no solution at all'.

 
Odgovor na temu

Trtko
Koprivnica

Član broj: 69494
Poruke: 695
*.bilokalnik.hr.



+8 Profil

icon Re: Kako ubrzati upit - optimizovati20.01.2009. u 07:27 - pre 185 meseci
Nebi trebalo biti sporo izvrsavanje do while petlje ... pogotovo ako se uzmu podaci koji ti trebaju a
ne sva polja iz tablice, ni ne primjetiš kako se brzo izvrsi.
i ne vidim što če ti funkcija za računanju, negdje si pogrijesio u logici.

Daj da vidimo taj tvoj kod.


@Zidar, ni ja nisam za koristenje poziva funkcije iz kverija, ali ponekad Da, kad su mali zahvati podataka i kad za to ima smisla.
Primjer. Spajam se na oracle bazu , a tamo su sva nasa slova bivše juge upisana pod 437 kodnom stranicom znači Š=[
e onda tu koristim ovu dolje funkciju za pretvaranje u naša slova.


Public Function pretvori(dovezi As String) As String
Dim staraslova As String

staraslova = dovezi
staraslova = Replace(staraslova, "[", "Š")
staraslova = Replace(staraslova, "{", "š")
staraslova = Replace(staraslova, "©", "Š")

staraslova = Replace(staraslova, "]", "Ć")
staraslova = Replace(staraslova, "}", "ć")

staraslova = Replace(staraslova, "^", "Č")
staraslova = Replace(staraslova, "~", "č")

staraslova = Replace(staraslova, "@", "Ž")
staraslova = Replace(staraslova, "`", "ž")

staraslova = Replace(staraslova, "\", "Đ")
staraslova = Replace(staraslova, "|", "đ")
pretvori = staraslova
End Function





 
Odgovor na temu

Zidar
Canada

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



+79 Profil

icon Re: Kako ubrzati upit - optimizovati21.01.2009. u 15:27 - pre 185 meseci
@Trtko: ma OK je da se koriste funkcije u kverijima, ali kad to ima smisla. Ali, ako funkcija u sebi sadrzi otvranaje rekordseta pa petlju kroz rekordset, to uglavnom moze da se izbegne. Ako ne moze - ne moze i to je OK. Medjutim, i kada ne moze da se izbegne funkcija sa rekordsetima, moze se uraditi na brzi i sporiji nacin.

Recimo, trazi se kveri sa kumulativima,

SELECT A.BrRacuna
, A.Iznos
, (SELECT SUM(B.Iznos) FROM Racuni AS B WHERE B.BrRacuna <= A.BrRacuna) AS Kumulativ
FROM Racuni AS A


Sad, neko ne ume da napise ovaj prilicno komplikovan kveri i odluci da napise funkciju koja za svaki racun sabira iznose svih prethodnih racuna plus tekuci. Funkcija bi izgledala otprilike ovako:

Code:

function Kumulativ(intBrRacuna AS integer) AS long
DIM db AS DAO.database
DIM rs AS DAO.recordset
DIM strSQL AS String
DIM lngKumulativ AS Long Integer

SET db = currentdb
strSQL = "SELECT SUM(Iznos) AS Kumul FROM Racuni WHERE BrRacuna <=" & cstr(intBrRacuna)
SET rs = db.openrecordset(strSQL)

lngKumulativ  = 0

if rs.count <> 0 THEN
   rs.movefirst
   lngKumulativ   = rs("Kumul")
end if

Kumulativ = lngKumulativ

rs.close
set db = nothing

end function


Funkcija izracunava isto sto i subquery. I vrlo je verovatno da JET engine koristi slicnu funkciju da bi izracunao rezultat subkverija.
Zasto ne bi onda nasa funkcija radila isto brzo kao i JET engine? Zato sto mi pravimo greske koje ne vidimo jer ni ne znamo da su greske.

Za 1000 rekorda, sto nije mnogo, funkcija bi se izvrsila 1000 puta. Ako zaboravimo da odradimo rs.close, imacemo 1000 instanci baze otvorene sa SET db = currentdb i 1000 rekordsetova otvorenih. Znas i sam sta se mose desiti kad se otvori a ne zatvori rekordset....
No, recimo da smo mi majstori i takve greske ne pravimo. Funkcija ce ipak biti sporija jedno 100 puta od kverija. asto? Primeti da sam bazu otvorio sa SET db = currentdb. To je spora operacija. Ima drugi, brzi nacin da se otvori baza kroz kod. Treba mi malo da pronadjem. Ako se neko seti neka mnapise odgovor, ako ne, ja cu ga napisati nadam se do kraja dana.


 
Odgovor na temu

Zidar
Canada

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



+79 Profil

icon Re: Kako ubrzati upit - optimizovati21.01.2009. u 18:57 - pre 185 meseci
Ako je dakle neka funkcija koja koristi rekordsete:
Code:

function Kumulativ(intBrRacuna AS integer) AS long
DIM db AS DAO.database
DIM rs AS DAO.recordset
DIM strSQL AS String
DIM lngKumulativ AS Long Integer

SET db = currentdb
strSQL = "SELECT SUM(Iznos) AS Kumul FROM Racuni WHERE BrRacuna <=" & cstr(intBrRacuna)
SET rs = db.openrecordset(strSQL)

lngKumulativ  = 0

if rs.count <> 0 THEN
   rs.movefirst
   lngKumulativ   = rs("Kumul")
end if

Kumulativ = lngKumulativ

rs.close
set db = nothing




ona ce se mnogo brze izvrsavati ukoliko umesto currentdb upotrebimo funkciju GetCurrentdb.

Code:

Function GetCurrentDB() As Database
  Static db As DAO.Database
  Dim strName As String
  
  On Error Resume Next
  
  strName = db.Name
  'Previous line produces error if db = nothing (first time we call the function)
  'That error is ignored and db is set to currentdb()
  'This will crash if Break On All Errors
  'Next time, db.name does not produce error, for it is STATIC, means it remebers
  'its value between function calls
  
  If Err.Number <> 0 Then
    Set db = CurrentDb
  End If
  
  Set GetCurrentDB = db

End Function


Ako zamenite u prvoj funkciji currentdb sa GetCurrentdb i izvrsite funkciju Kumulativ samo jednom, necete primetiti razliku. Medjutim, ako funkciju Kumulativ pozovete iz kverija, razlika ce biti ogromna. Zasto?

Ko programira, trebalo bi da zna kako se iz Jet-a poziva tekuca baza. Koristi se DbEngine.Workspaces(0).Datbases(0) sto se moze pisati i kao DbEngine(0)(0). CurrentDb() nije uopste funkcija iz JET-a, to je funkcija koju ima Access. Access i JET su dve razlicite stvari, Access poziva JET kad mu zatreba. I Excel, i Word i VB pozivaju JET, a JET moze da 'otvara' Access fajlove. Elem, CurentDB() i DBEngine(0)(0) vracaju referncu na tekucu Acces bazu, ali ne rade ina isti nacin. Svaki put kad pozovete CurentDb(), Access otvara novu instancu datbase objekta koja pokazije na tekuci MDB fajl. JET to radi jednom. Kad prvi put u kdo pozovete DbEngine(0)(0) pa to ucinite opet, JET vam vrati ono isto od prvi put, ne otvara novu instancu. Zato je DbEngine(0)(0) brze od Currentdb(). Zasto ljudi koriste GEtCurrentDB umesto DbEngine(0)(0)? Pa lakse se pise, a i ne zna svako razliku.

Funkciju GetCurentDB() napisao je Ken Getz, autor serije knjiga ".. Developers HAndbook". Funkcija otvori bazu jednom i posto je varijabla db deklarisna kao STATIC, ona se cuve izmedju poziva funkcije => dobije se isti efekat kao sa DbEngine(0)(0). Gospodin Getz tvrdi da je u svojim testovima DbEngine(0)(0) radilo od 5 do 10 puta brze nego CurrentDB().

Eto zasto je "the best code no code at all" - ne morata da se zamrate sa ovakvim zackoljicama.

:-)
 
Odgovor na temu

[es] :: Access :: Kako ubrzati upit - optimizovati

[ Pregleda: 3828 | Odgovora: 8 ] > FB > Twit

Postavi temu Odgovori

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