Wolno działajacy komponenet TQuery

0

Witam

    Czy komponent TQuery jest dużo wolniejszy od komponnentu TTable jeśli się go używa w przypadku bazy lokalnej? Jakie są wasze odczucia? Baze danych mam zapisana w tabelach paradoxa i do wyciagania z niej danych uzywam  kompnenetu TQuery poprzez zapytania. Jednak mam wrazenie ze dziala to duzo wolniej niz jak robilem to za pomoca komponenetu TTable. A moze cos zle robie? Ale nie mam czegos ustawionego w tym komponencie?
0

Najważniejsza sprawa (zaraz po tym jak przeczytasz książkę o SQLu) to składnia zapytań. Spowolnienie może pochodzić i prawdopodobnie tak jest od nietypowo (lub błednie) skonstruowanego zapytania SQL. Najlepiej jakbyc podał zapytanie to się pomyśli, bo jak nie to można powróżyć z patków śniegu za oknem...

0
  1. ile rekordów masz w tabeli
  2. jak wygląda jeden rekord
  3. jakie masz indexy
  4. jak wygląda zapytanie
  5. wolno, czyli ile czasu

TTable a TQuery to dwa całkiem odmienne sposoby na dostanie się do danych. Jeśli używasz Query jak Table (tzn. robisz SELECT * FROM tabela) i potem szukasz w tym przez Find, Locate, Seek itp to się nie dziw, że wolno działa

0

Ponizszy fragment kodu sluzy mi do dodawania do CheckListBox wszystkich Wlasciwosci materialow jakie sa w tabeli Wlasciwosci dzielac je na grupy w zaleznosci do jakiej sa przypisane w tabeli Rodzaje Wlasciwosci. Czy dana wlasciwosc jest zaznaczona zalezy od tego czy znajduje sie jej id w tabeli WlasciwosciMaterialowe. Mimo ze mam tych rekordow dosyc malo okolo 30 lista z takim podzialem w CheckListBox rysuje sie dlugo. Nie wiem co jest tego przyczyna.

 
procedure DodajGlowe(id : integer);
begin
   Query2.Close;
   Query2.Sql.Clear;
   Query2.Sql.Add('select * from RodzajeWlasciwosci where id_rodzaj_wlasciwosci = :id_wlasciwosci');
   Query2.Params[0].value:=id;
   Query2.Open;

   CheckListBox1.Items.Add(Query2.Fields[1].AsString);
   CheckListBox1.Header[CheckListBox1.Items.Count-1]:=True;
end;
function zaznaczone(id_wla,id_mat : integer) : boolean;
begin
   Query2.Close;
   Query2.Sql.Clear;
   Query2.Sql.Add('select * from WlasciwosciMaterialowe where id_materialu = :id_materialu and id_wlasciwosci = :id_wlasciwosci');
   Query2.Params[0].value:=id_mat;
   Query2.Params[1].Value:=id_wla;
   Query2.Open;

   if Query2.Eof then zaznaczone:=false else zaznaczone:=true;

end;
var
 i : byte;
 pamietaj : integer;
begin
   //wyswietl wlasciwosci   (FrmWprowadzanie.tag=0) or
   //jesli nie ma id_materialu nie wyswietlaj wlasciwosci
   if DBEdit4.Text='' then begin GroupBox1.Visible:=False;  Exit; end;
   if GroupBox1.Visible=False then GroupBox1.Visible:=True;
  //  GroupWlasciwosciMaterialowe.Visible:=False;

   pamietaj:=-1;  //bo -1 nigdy nie bedzie kluczem
   CheckListBox1.Clear;
   Query1.Close;
   Query1.Sql.Clear;
   Query1.Sql.Add('select * from Wlasciwosci order by id_rodzaj_wlasciwosci');
   Query1.Open;
   while not Query1.Eof do
   begin
     //jesli poprzednie id_rodzaj_wlasciwosci jest rozne od biezacego
     //to trzeba dodac glowe czyli Rodzaj wlasciwosci
     if pamietaj<>Query1.Fields[1].AsInteger then DodajGlowe(Query1.Fields[1].AsInteger);
     CheckListBox1.Items.Add(Query1.Fields[2].AsString);
     if zaznaczone(Query1.Fields[0].AsInteger,DataModule3.Materialy.FieldByname('id_materialu').Value) then CheckListBox1.Checked[CheckListBox1.Items.Count-1]:=True;
     pamietaj:=Query1.Fields[1].AsInteger;
     Query1.Next;
   end;

Czemu kod mam wysrodkowany :)?

0
  1. zadajesz pytanie, masz z czymś problem to może byś z łąski swojej odpowiadał na wszystkie pytania w miarę dokładnie a nie tylko na te, na które ci się podoba!!

<font size="4">1. ile rekordów masz w tabeli
2. jak wygląda jeden rekord
3. jakie masz indexy
4. jak wygląda zapytanie
5. wolno, czyli ile czasu</span>

  1. najlepiej daj całą strukturę bazy bo coś mi się wydaje, że masz tam namieszane
0

Po pierwsze nie do końca dokopiowałeś kod, ale mniej więcej widzę co chcesz zrobić. Używam nieco innych komponentów, lecz składnai podobna.

  1. Zacznijmy od uwagi stylistycznej, choć pewnie neiwiele ona wniesie. Staraj się unikac select * jeśli chcesz tylko jedną kolumnę wyciągnąć. Generalnie na twoje zapytanei zostaje zwrócona duża ilość danych których nie będziesz używał. Przy większych ilościach danych, zwłaszcza przesyłanych po sieci robi to kolosalną róznicę. Uwywaj np. select wlasciwosci.wlasciwosci_id.
  2. nie wiem jak na zasadzie transakcji chodzi open i close, ale aż się prosi aby po open w procedurze było close, a nie close w następnej procedurze (zakładam poprawność otwierania i zamykania bo jest to w kodzi)
  3. Sprawdz ile da ci założenie indeksów na wszystkich polach występujących w warunku where: id_materialu, id_wlasciwosci , id_rodzaj_wlasciwosci
  4. Ta druga procedura wymaga SQLa select count(), lub zastosowania exists, ale jeśli count() zwróci zero to nie ma rekordów, a jeśli zwróci >0 to jest przynajmniej 1.
  5. Trzecia procedura jest chora, tak chora że aż mi niedobrze.
    Pytanie co chciałeś osiagnąć?
    Chyba sie domyślam i da się to jednym zapytaniem zrobić, ale musisz podać mi strukturę tabel i klucze obce, abym wiedzial co z czym wiazac.

Kryspi: I nie przejmuj się krytyką, namieszałeś straszliwie, ale to wynika z faktu braku wiedzy a nie wrodzonej głupoty (jak u sporej liczby osób tutaj). Co prawda mógłbys zauważyć że bez większej ilości informacji nikt ci nie pomoże, np. MisiekD pytał o wazne dane. Podejrzewam jednak że masz mgliste pojęcie o co byłeś pytany, musisz trochę poczytać o bazach danych, sqlu, indeksach itp.
Spowolnienie u ciebie wynika prawdopodobnie z nagromadzenia zbędnych połączeń z BD, an dokładkę nie wiem czy słusznie się rozłaczasz po każdym (mam inne komponenty, a tych co ty używałem wieki temu).
Podaj to o co prosił MisiekD i o co ja prosiłem.
jak wyglądają tabele (pola), jakie masz klucze obce - czyli pola po których dokonujesz złączeń pomiędzy tabelami (np. w tabeli x jest id które oznacza (jest odpowiednikiem) pole X_ID w tabeli Y). Podaj przykładowe rekordy po 1-2 na każdą tabelę. Określ czy masz i gdzie indexy (na jakich polach). Zapytania już widziałem, powiedz co oznacza wg. ciebie wolno najlepiej w jednostkach układu SI (sekundach - ile jest a ile było poprzednio).
Sądzę że to co potrzebujesz da sie zrobić jednym zapytaniem SQL.

Wiem, wiem MisiekD mam dziś dzień dobroci i łagodności - święta idą.

0

Witam ponownie.

    Dziekuje za probe pomocy jak rowniez za slowa krytyki. Kod wyglada tak dziwnie bo widocznie mam dziwny tok myslenia :) albo poprostu przez to ze nieznam wszystkich procedur i funkcji delphy oraz dobrze skladni SQL. Ale do rzeczy: 

Moze najpierw odpowiem na pytania osoby o ksywce MisiekD :), bo slusznie sie troszke zdenerwowal, gdyz nie odpowiedzialem na jego pytania. Ale akurat bylem w pracy i niezabardzo sie moglem przylozyc do napisania postu. Więc tak:
Ad 1)

1. Rekordów jest narazie malutko, około 20. Ale docelowo moze byc okolo 600.
2. Jak wyglada jeden rekord? Nie wiem dokladnie co miales na mysli. Bo rekordy sa rozne w roznych tabelach. Ponizej zamieszczam strukture bazy ![user image](http://luber.homelinux.org/screeny/relacje.jpg) 
3. Nie mam indexow bo nie wiem jak sie je tworzy. Albo mam i nie jestem tego swiadom :).
4. Zapytanie wyglada tak jak to widac w kodzie.
5. Wolno tzn. jak sie przechodzi po rekordach to dosyc wolno rysuje sie CheckBox (widoczny na screenie ) z jego elementami. Na 1,6 Athlonie jeszcze to tak nie przeszkadza, ale jak to uruchomilem na 800 to dosyc wolno to dziala. Rysuje sie moze ze 2 s. Nie wiem czym to jest spowodowane. Przy tak malej liczbie rekordow to wydaje mi sie ze nawet zle sformulowane zapytania nie powinni miec wplywu.
Teraz notka do Dabana:

Ad 3) nie wiem niestety jak sie zaklada te indexy :( poszukam w materialach to sprawdze to czy szybciej bedzie:)
Ad 4) wiedzialem ze trzeba z counta skorzystac ale zapomnialem o gwiazde w srodku tzn wpisywalem count() zamiast count(*) i wyrzucalo mi blad i postanowilem to tymczasowo obejsc tak jak jest w kodzie
Ad 5) Szkoda ze nie widziales poprzedniej procedury opartej o tabele :) to dopiero bylo zagmatwane i chore ale szybciej chodzilo :) Ale na tabelach nie wiedzialem jak sie sortuje tak wiec postanowilem skorzystac z SQLi. To chcialem uzyskac: user image Pewnie by trzeba skorzystac w zapytaniu z jakiegos joina?

Jak mozecie to napiszcie jak byscie to rozwiazali. Dziekuje za pomoc i mam nadzijee ze tym razem troszke jasniej napisalem.

0
daban napisał(a)

Wiem, wiem MisiekD mam dziś dzień dobroci i łagodności - święta idą.

LOL [rotfl] no czasami i ja mówię ludzkim głosem ;P

0

kryspi na samym początku pozakładaj indexy na wszystkie pola główne (robi się to przechodząc na pole KEY w restructure table i naciskając spację - pojawia się tam gwiazdka). Następnie trzeba założyć indexy na pola, które są kluczami obcymi - restructure table, Table property - Secondary indexes, define i dodajesz jedno pole, ok i nadajesz nazwę indexowi (najlepiej idx_nazwa_pola), potem save i już

pola które powinny byc kluczami głównymi
typ_materiału.id_typ_materialu
materialy.id_materialu
stan_skupienia.id_stan_skupienia
wlassciwosci_materialu.id_materialu wlassciwosci_materialu.id_wlasciwosci (powinny być * przy obu tych polach)
wlasciwosci.id_wlasciwosci
rodzaje_wlasciwosci.id_rodz_wlasciwosci
na pozostałych polach zaczynających się od id_ powinny być założone secondary indexes (na każde pole jeden index)

w nazwach tabel, pól nie stosuj ani spacji ani pl literek

a co do kodu to nie mam siły się weń zagłębić dzisiaj

0

Wydaje mi się, że powinno się udać z zapytaniem: (sprawdź poprawnośc składni, na wszelki wypadek, nazwy tabel i pól):

select * from własciwosci_materialu,wlasciwosci,rodzaje_wlasciwosci
where własciwosci_materialu.id_wlasciwosci=wlasciwosci.id_wlasciwosci
and wlasciwosci.id_rodzaj_wlasciwosci=rodzaje_wlasciwosci.id_rodz_wlasciwosci
and wlasciwosci_materialu.id_materialu= :id_materialu
order by rodzaje_wlasciwosci.nazw_wlasciwosci, wlasciwosci.nazwa_wlasciwosci ASC

To zapytanei powinno ci dac co potzrebuejsz za jednym zamachem, klauzula order by służy do posegregowania po kolumnachm, najpierw rodzaj a potem konkretne (ale jujz tylko tego rodzaju). W select dałem * ale wpisz co ci potrzebne, przy czym zawsze musisz mieć to co wypisane w order by czyli rodzaje_wlasciwosci.nazw_wlasciwosci, wlasciwosci.nazwa_wlasciwosci .

zapytanie powinno zwrocic cos w rodzaju:
Fizyczne , gestosc
Fizyczne , objetosc molowa
Termiczne , cieplo parowania
Termicze , cieplo topnienia

bedziesz musial zapytanie zdejmowac po kolei, czyli w 1 kroku odczytac rodzaj wpisac go (Fizyczne), a potem wypisac wlasciwosc (gestosc), a w nastepnym kroku (wierszu) sprawdzic czy zmienil sie rodzaj (fizyczne - nie zmeinil), i jesli sie nie zmienil to dodac tylko wlasciwosc (objetosc molowa). Następny wiersz czy się zmienil rodzaj (Termiczne-tak) wpisac najpierw nowy rodzaj, a potem wlasciwosc (cieplo parowania). Następny wiersz, czy sięzmienil rodzaj - nie, wiec tylko nowa wlasciwosc (cieplo topnienia) itd itd az sie skoncza wiersze.

Dokładnie sprawdz mój sql mogą być będy w pisowni, ale sens powinien być ok.

Wiem że masz braki w wiedzy, ale sposób w jaki kombinowałeś mi się spodobał, a jak się douczysz SQLa będziesz potrafił wiele więcej robić. Myśle że poradzisz sobie już tym problemem nawet jakbyć miał jakieś przeróbki robić.

0

Hmm... Daban, a coś takiego jak JOIN to nie istnieje? Jest to sporo szybsze rozwiązanie, jeśli interesuje Cię czas wykonywania zapytania po stronie serwera. Oczywiście przy niewielkiej bazie nie ma to znaczenia, ale jak rekordów się robi więcej, to złożoność wyciągania tego z bazy jest wolniejsza. Spowodowane jest to faktem, że przy zapytaniu łączącym za pomocą WHERE wynajduje Ci wszystkie możliwe kombinacje (a biorąc pod uwagę, że nie mamy 2 tabel tylko z 6 (jak dobrze pamiętam), to jest tego dużo), po czym dopiero z tych kombinacji wybiera wszystkie te, które spełniają zadane warunki. Są tacy, którzy optymalizują zapytania poprzez odpowiednie przestawianie warunków, by maksymalnie szybko wyeliminować jak największą liczbę przypadków, by następne warunki były sprawdzane na mniejszej ilości.
//Daban: No offence jak to mawiają :]. Widziałem w jakimś innym temacie, że zajmujesz się bazami danych, dlatego zaskoczyło mnie użycie takiego zapytania :)
//night: Być może zależy to od bazy danych, albo tego jak to się skonstruuje. Ja dawniej też używałem łączenia poprzez WHERE ale ktoś z 4p (Chyba Dryobates, ale nie chcę kłamać, mogę się mylić, w każdym razie ktoś z tych, co się znają na rzeczy) wytłumaczył mi, że JOIN'y są szybsze i podał argumentację DLACZEGO tak jest. Więc nie widzę powodu, by w to nie wierzyć :)

0

:) Widzę że uparłeś się szukać dziury w całym, oczywiście że mogę przerobić to zapytanei na 5 sposobów, ale jeśli chłopak ma docelowo mieć 600 rekordów, nie zna SQLa i nie wie co to indeks... Za to potrafi kombinować to chyba najlepiej dać mu podrecznikowe zapytanie, aby potrafił po krótkim doczytaniu je poprzerabiać. Jesli uzna że jeszcze wolno chodzi to można mu je pozmieniać. Z tabel korzysta 3, przy czym z tego co widziałem jedna ma z 5-10 rekordów, a następne też nie są przesadnie obszerne. Najlepiej dac początkującemu najprostsze rozwiązanie które mu sie przyda, a zamiast krytykować może byś wziął się i odpowiedział komuś, aby po prostu pomóc.
A jeśli chodzi o joiny to pracuję na FireBirdzie i mam bazy po kilkaset tysięcy rekordów w jednym zapytaniu. tam bez odpowiedniego indeksowania, joinów i left joinów, oraz mieszania z warunkami nic bym nie zdizałał. Ostatnie 2 tygodnie spędziłem na szukaniu sposobów na przyspieszenie zapytań, poprzez SQLa, ustawień systemu operacyjnego i samego Firebirda. Do tego nawet przebudowywałem koncepcję BD. Wynik z standrdowego zapytania potzrebującego 6,5 minuty zszedłem do około 50 sekund. To nadal dużo, ale to zapytanie bez dodatkowych ograniczeń, jak wrzucę ograniczenie np. po dacie do wybrania ok.25000 rekordów to czasy mam poniżej sekundy. I abyś znowu nie zarzucał mi braku znajomości tematu, nie wyświetlam wszystkiego ale porcjuję, musiałem w tym celu algorytmy przyspieszające przerzucanie "stron" wyników, ale się opłacało.

0

Ja sie nie zgodze ze JOIN jest szybki !!
Nie wiem czy jest cos wolniejszego od joinów, najlepiej jest łączyć wherem po kolumnach kluczowanych(indexowanych).
Dalej szybkość składania takego select zalezy też w duuzej mierze od jakości optymalizatora, aktualnosci statystyk na serwerze, aktualnosci indexow, szybkosci dyskow oraz rozmiaru RAMu, jak również konfiguracji pamieci podrecznej bazy :)
to tyle :))
Pozdrawiam

0

I ilości danych do posortowania.... U mnie sortowanie zajmuje mnóstwo czasu :(
Bez neigo sql działa w ułamku sekundy...

0
daban napisał(a)

I ilości danych do posortowania.... U mnie sortowanie zajmuje mnóstwo czasu :(
Bez neigo sql działa w ułamku sekundy...

Może jekieś hint'y dodaj do zapytań, albo zaloz indexy na wszystkie kolumny po jakich sortujesz, albo po prostu mocniejszego kompa :/ (serwera ;P )

0

Adam.Pilorz napisał:

//night: Być może zależy to od bazy danych, albo tego jak to się skonstruuje. Ja dawniej też używałem łączenia poprzez WHERE ale ktoś z 4p (Chyba Dryobates, ale nie chcę kłamać, mogę się mylić, w każdym razie ktoś z tych, co się znają na

Może powiem tak, nie widziałem w żadnym większym systemie zeby używać joinów w innym przypadku niz do znalezienia wszystkich wartosci z tab nadrzednej, ktore nie maja odpowiedników z podrzednej. Osobiscie uważam że joinowanie tylko zaciemnia sens zapytania.
drugi powod - access domyślnie tworzy joiny i jak działa ? Wciśnij tam w 4-5 tabel po 10-15 tys wierszy i zrób zapytanie ze wszystkich( złącznone zeby Ci kartezjana nie stworzył) spokojnie bedziesz mógł isc na piwo. A jak pewnie wiesz 15 tys w tabeli to przecież całe nic.

0

Hmm... Ale to jest z całym szcunkiem Access :P. Ja używam MySQL i mi śmiga na JOINach w ułamku sekundy. Przy powiedzmy kilku tysiącach rekordów w każdej tabelce, nie mam takich baz danych, żeby było po kilkanaście/kilkadziesiąt tysięcy. A nie będę przecież sztucznie generował bazy tylko po to, by porównać szybkość działania :]
P.S. Z Accessem nie mam styczności od czasu drugiej klasy liceum (nie licząc matury z infy) - Nie stać mnie na kupowanie oprogramowania Microsoftu jak są darmowe i dużo lepsze.
P.S. Uprzedzając pytania moderatorów o mojego Windowsa - dostałem go za darmo z uczelni na zasadach licencji MSDN AA. Niestety MS stwierdził, że programistom Office jest niepotrzebny, więc nam go nie udostępnił :P

0

Heh po prostu nie przepadam za M$ i nie lubie tego co Bill robi => nie przepadam za joinami.
Tak czy inaczej duzo zalezy od implamentacji, i zastosowania. Ja wolę where, u mnie w robocie nikt join nie używa poza przypadkami o których wyżej napisałem.
O ile się orientuje (mogę się mylić) Oracle u siebie zaleca stos. WHERE.
Pozdrawiam.

1 użytkowników online, w tym zalogowanych: 0, gości: 1