Jak robic zapytania do bazy danych

0

WItam

zaczynam ostatnio miec doczynienia z bazami danych
(tak! przez ladnych pare lat pisalem programy bez kontaktu z nimi!!)
[uzywam Firebird embedded 2.x]

No i zastanawiam sie w ktora strone isc.
Zeby wykonac jakies tam zestawienie musze polaczyc dane z wielu tabel.
i widze dwie mozliwosci:

  1. zrobic SELECT'a z mega-JOIN'em laczacym wszystkie potrzebne tabele
    a nastepnie w jednej petli przerobic wynik zapytania na to czego potrzebuje

  2. Zrobic prostego SELECTa wydobywajacego glowne dane a potem dla kazdego rekordu
    robic kolejne SELECTy dociagajac szczegolowe informacje ze slownikow itp

Tworzac mega-JOINa wydaje mi sie ze zuzywam duzo pamieci na trzymanie powtarzajacych sie danych
natomiast robic wiele malych SELECTow trace czas na laczenie sie z baza i wykonywanie zapytan.

Poradzcie jaka droge wybrac?

0

Ja robię to tak, że tworzę sobie tabelę, która ma strukturę, której potrzebuję, a potem tworzę procedurę składowaną, która wypełnia mi tą tabelę.

Z programu masz tylko wywołanie procedury i jednego prostego selecta :)

Jeśli chodzi o joiny itp, to zastanów się, czy nie lepiej będzie zrobić z tego widok. A jeśli takie zapytanie wykorzystujesz w kilku miejscach w aplikacji to widok na bank.

0

No wlasnie robie juz widoki.
Mysle ze procedury skladowane sa tym do czego powininem dazyc ale to jeszcze chwile zanim do tego dojde:-)

Zastanawia mnie kwestia tego czy powininem sie martwic tym jak moje zapytania sa realizowane przez silnik bazy danych? czy wystarczy miec nadzieje ze jesli zapytanie jest w miare sensownie skonstruowane to baza danych sama to zoptymalizuje.

Nie daje mi spokoju to ze robiac JOINA zuzywa sie miejsce na ogromna ilosc powtarzajacych sie w kazdym rekordzie danych.... (a moze baza jest na tyle sprytna ze nigdzie tego fizycznie nie trzyma???)
Nie wierze ze przy duzych bazach jest to bez znaczenia.... (a moze sie myle?)

0

W pracy z bieżącej z bazą np. przy wyświetlaniu grida nie obędziesz się bez często skomplikowanych zapytań z joinami. Tak jak napisał Juhas warto wtedy takie zapytania "ubrać" w widok.

Wypełnianie tabel z danymi opłaca się głównie do generowania raportów. Dopisywanie danych do takiej tabeli powinno następować już przy dopisywaniu pojedynczych rekordów przez użytkownika.

Zastanawia mnie kwestia tego czy powininem sie martwic tym jak moje zapytania sa realizowane przez silnik bazy danych? czy wystarczy miec nadzieje ze jesli zapytanie jest w miare sensownie skonstruowane to baza danych sama to zoptymalizuje.

W przypadku Firebirda nie licz na wiele. Najlepiej będzie jeżeli podszkolisz się w tym zagadnieniu i będziesz konstruował poprawne i optymalne zapytania.

Johny_Morfina napisał(a)

Nie daje mi spokoju to ze robiac JOINA zuzywa sie miejsce na ogromna ilosc powtarzajacych sie w kazdym rekordzie danych.... (a moze baza jest na tyle sprytna ze nigdzie tego fizycznie nie trzyma???)
Nie wierze ze przy duzych bazach jest to bez znaczenia.... (a moze sie myle?)

Tutaj wszystko zależy od architektury Twojej bazy. Jeżeli poprawnie ją zaprojektujesz i założysz poprawnie indeksy i klucze to zapytanie lecące po indeksach będzie naprawdę szybkie. Jeżeli chodzi o ilość danych to powinieneś dążyć do tego aby pobierać z bazy tylko to co jest Tobie w danej chwili potrzebne z tego też względu nigdy nie rób widoków z widoków i tym podobnych konstrukcji.

0

ja dodam tylko, że jeden 'mega' select z kilku/nastu/dziesięciu tabel zadziała szybciej niż kilka/naście/dziesiąt mniejszych selectów

Mądre BD nie tworzą od razu 'miejsca' na wszystkie zwracane dane (chyba, że jest ich mało) tylko na tyle ile chce klient (w IBX z tego co pamiętam jest to porcjowane i dopóki nie dasz FetchAll albo Last to nie doczyta wszystkich)

0

To ze szybciej to oczywiste.
pytanie jest czy ilosc miejsca potrzebna na powtarzajace sie dane
nie spowoduje ze ta szybkosc wyjdzie nam bokiem!?

0

@Johny_Morfina - przecież szybkość jest najważniejsza! Użytkownik korzystający z Twojej aplikacji nie będzie się zastanawiał ile to zajmuje miejsca ale jak długo będzie czekał na wynik działania programu. Bieżąca praca z programem nie powinna wymagać od użytkownika zauważalnego oczekiwania.

Kolejną sprawą jest to, że dziś taniej zaopatrzymy się w duży dysk niż w dobry serwer z duża ilością RAM i szybkim dyskiem.

0

ja dalej nie jestem przekonany...
Oto prosty przyklad:
tabela sprzedawcy i tabela klienci
chce zrobic zetawienie ktory sprzedawca obsluguje ktorego klienta.

zrobilbym:

QueryS.sql := 'SELECT * FROM sprzedawcy;';
QueryS.open;
while not QueryS.eof do begin
  writeln('Sprzedawca '+QueryS.fieldByName('Sprzedawca').asstring);
  QueryK.close;
  QueryK.sql := 'SELECT * FROM klienci';
  QueryK.open;
  while not QueryK.eof do begin
    writeln(QueryK.fieldByName('klient').asstring);
    QueryK.next;
  end;
  QueryS.next;
end;

a z tego co rozumiem sugerujecie ze lepiej robic

Query.sql := 'SELECT * FROM sprzedawcy LEFT OUTER JOIN klienci;';
Query.open
Sprzedawca := '';
while not Query.eof do begin
  if sprzedawca <> Query.fieldbyname('Sprzedawca').asstring then begin
    sprzedawca := Query.fieldbyname('Sprzedawca').asstring;
    writeln(sprzedawca);
  end;
  writeln(Query.fieldbyname('Klient').asstring);
  Query.next;
end;

Jesli tak to czeka mnie powazna zmiana sposobu myslenia...

0
SELECT * FROM sprzedawcy LEFT OUTER JOIN klienci

Hej a co to w ogóle jest za zapytanie?! Gdzie jest złączenie?

Powinno być coś takiego:

SELECT * FROM sprzedawcy s LEFT OUTER JOIN klienci k on k.idsprzedawcy = s.idsprzedawcy

idsprzedawcy to identyfikator sprzedawcy, który powinien być zarówno w tabeli sprzedawców jak i klientów.

i wtedy cały kod wygląda tak:

Query.sql := 'SELECT * FROM sprzedawcy s LEFT OUTER JOIN klienci k on k.idsprzedawcy = s.idsprzedawcy;';
Query.open
Sprzedawca := '';
while not Query.eof do begin
  writeln(Query.fieldbyname('Sprzedawca').asstring);
  writeln(Query.fieldbyname('Klient').asstring);
  Query.next;
end;

Czym prędzej łap się za jakiś kurs SQL albo kup książkę.

0

[wstyd] ups... pisalem kod w przegladarce, nie uruchamiajac, z tad bledy.

Masz racje, jade na jakichs wczesniej napisanych zapytaniach i na ich podstawie robie nowe, chyba musze sie troszkie podszkolic.

ale chodzi mi o idee
rozumiem ze mam robic joiny zamias podwojnych petli?

konczmy ten temat i do pracy...
ale chce jeszcze uslyszec jana odpowiedz na te pytania:
czy na prawde dane powtarzajace sie w grupach rekordow nie stanowia problemu??
po co zatem w ogole dzielic baze na tabele skoro i tak pytajac sie o dane sklejam je w jedna calosc?

0
Johny_Morfina napisał(a)

rozumiem ze mam robic joiny zamias podwojnych petli?

Tak. Korzyści chyba są oczywiste. Jeden select wykona się szybciej niż 100 selectów mimo tego, że dotyczą tych samych danych. Po drugie nie masz dwóch pętli tylko jedną.

Johny_Morfina napisał(a)

po co zatem w ogole dzielic baze na tabele skoro i tak pytajac sie o dane sklejam je w jedna calosc?

Po pierwsze dane trzymane w wielu tabelach się nie powtarzają. Np. masz tabelę kontrahentów oraz tabelę miast, w tabeli kontrahentów trzymasz tylko idmiasta w którym ma siedzibę kontrahent dzięki temu w tabeli kontrahentów nazwa miast nie powtarza się tyle razy ilu kontrahentów jest z danego miasta. Dzięki temu dane zajmują mniej miejsca. Gdybyś trzymał miasto w tabeli kontrahentów to z pewnością część kontrahentów miała by wpisane: 'Warszawa', 'WARSZAWA', 'Warszawka', 'Wa-wa' itp. dzięki powiązaniu po idmiasta wszyscy kontrahenci z Warszawy będą mieli wpisaną nazwę miasta identycznie tak jak w tabeli miasta np. 'Warszawa'.

Po drugie dzielenie danych na wiele tabel sprzyja bezpieczeństwu i spójności. Jeżeli masz w tabeli kontrahentów klucz obcy do tabeli miast to nie będziesz mógł skasować z tabeli miast - miasta z którego pochodzi choć jeden Twój kontrahent. Dzięki temu nigdy nie zdarzy się sytuacja, że nie wiesz skąd pochodzi Twój kontrahent. Bardziej obrazowy przypadek to taki, że masz tabelę z nagłówkami dokumentu (w której masz kto kupił, kiedy itd) oraz tabelę z linijkami dokumentu (w której masz co kupił i w jakiej ilości). Nie będziesz mógł skasować nagłówka dokumentu dopóki istnieje choć jedna linijka dla tego nagłówka. Dzięki temu nigdy nie zdarzy się sytuacja, że w bazie będą linijki bez nagłówka o których nie wiadomo którego dokumentu dotyczą. Nie zdarzy się też sytuacja w której Pani Basia pomyliła się przy wpisywaniu daty dokumencie i zmieniła tą datę dla trzech linijek ale zapomniała o czwartej. Jeżeli będzie zmieniała datę tylko w nagłówku to nie będzie tego musiała robić cztery razy tylko jeden raz.

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