Baze na serveru, a server u bunkeru

November 14, 2007 – Dejan

Pošto je našoj firmi dostupnost Oracle baze veoma važna, serveri su smješteni u jednoj vrsti “bunkera”. Skromno ću reći - ukoliko se skrši Oracle baza, onda ili propada cijela firma ili više od pola ljudi u firmi ostaje bez posla.

“Bunker” je ogromna prostorija smještena 10 m ispod zemlje, sa zaštitom protiv požara, poplave i zemljotresa, a posjeduje i vlastito alternativno napajanje strujom (baterijske jedinice i 3 velika dizel agregata).

Pristup imaju samo ovlaštene osobe sa chip karticama, a danas smo i mi dobili jedinstvenu priliku da posjetimo taj bunker i iskoristimo priliku za fotografisanje. :D

Na prvoj slici smo ja (prvi s lijeva), moj šef Edi i radni kolega John (Oracle DBA, radio za Oracle Austrija ranije), a na ostalim slikama su naš stari server, naš novi server i na kraju SAN storage za novi server.

Dejan, Edi, John Stari production server Novi production server SAN storage za novi server

A gdje su smješteni vaši serveri? Koliko vam je važna dostupnost baze?


Stigao nam TOAD Oracle for Professional

November 14, 2007 – Dejan

TOAD for Oracle ProfessionalJuče nam je stigao paket sa novom verzijom “TOAD for Oracle Professional“, pa smo se obradovali kao mala djeca kad dobiju novu igračku. :D

Osjećaj je drugačiji kad dobiješ ovakav paket poštom u odnosu kad skineš neki software sa neta…

Inače, nova verzija ima dosta poboljšanja i nekoliko novosti, ali ne bih sad da vas gnjavim time. Detaljnu listu tih izmjena možete naći na službenom sajtu.


Čovek se uči dok je živ…..

November 9, 2007 – Zidar

Kada mi je Dejan ponudio da se pridružim “blogovanju”, bio sam veoma uzbuđen i počašćen. Međutim,  kad je trebalo sesti i nešto napisati, mozak mi je potpuno stao. Sve mi se činilo nekako nedovoljno dobro, već viđeno i slično. Ličio sam sâm sebi na pisce iz crno-belih filmova. Pisac sedi za pisaćom mašinom, cigareta u ruci (ja ne pušim, ali takva je slika), gomila izgužvanih papira okolo, pisac frustrirano umeće novi list u mašinu da bi ga odmah izvadio zgužvao i bacio na pod. Onda ustaje i nervozno šeta po sobi, povlači dim, trgne iz boce, oznojeno mu čelo, hladan znoj. Već je ponoć, ideja nikako da naiđe, a rok za predaju rukopisa je sutra u 8 … 

Kad se ideja napokon pojavila, shvatio sam da imam još jedan problem. Nije veliki, ali je neprijatan, “embarassing”, rekli bi englezi. Nisam umeo da koristim naša slova. To je OK možda na forumima, tamo je cilj da se što brže napiše odgovor. Blog je po meni nešto drugo, na malo višem nivou. Blog je dnevnik, a od mnogih dnevnika su nastale knjige, memoari i slične stvari. Ne kažem da će od ovog bloga postati knjiga, ali postovi zaslužuju da barem lepo izgledaju.  Dejan i Srđan ulažu mnogo truda da ovaj sajt izgleda lepo i profesionalno. Pa ko velim, ja mogu bar toliko da se potrudim, da na našem sajtu pišem našim pismom. Uz Srđanovu nesebičnu pomoć, evo naučio sam kako da dobijem naša slova. U privatnom životu naravno koristim i ćirilicu, ali ovo je tehnička materija, pa je nekako prirodno da bude na latinici. Ako ikad budem pisao poeziju u nekom blogu, biće na ćirilici, da se ne zaborave koreni…

Ja po profesiji nisam informatičar, niti programer. Ovo o čemu pričam po forumima, naučio sam silom prilika, trebalo mi je da rešim neke tadašnje profesionalne probleme u svom polju - građevinarstvu. Valjda su inženjeri takva sorta, da uvek moraju da znaju ne samo šta treba da se radi, nego i zašto je to tako i može li to bolje i efikasnije. Za prve pokušaje bio je dovoljan i FORTRAN, pa onda BASIC u raznim varijantama, pa Dbase i Clipper. Onda je došao Windows, pa Access i na kraju SQL, generalno, a konkretno MS SQL. Jedno kratko vreme život je bio lep. Dok se nije pojavila Objektno orijentisana priča i sve što uz to ide, UML, četiri amigosa, ćuse case, klase i Bog te pita šta još. I programeri su prestali da uče relacionu teoriju i SQL. Barem na ovoj strani Atlantika. Ne potpuno, ali se sve svelo na nekoliko stranica u knjizi o recimo C#, onako usput. I tako su ljudi svašta i naučili, onako usput. Naravno, slika na terenu počinje da se menja, na gore. Ono što je veoma jednostavno uraditi u SQL-u, radi se proceduralno, pišu se funkcije, klase i metodi. Ne želimo naravno špageti kod, sve je lepo i strukturno i objektno :-) I uglavnom užasno nefleksibilno. Pratimo specifikaciju doslovno, nema prostora za mrdanje levo ili desno. Posledica - za svaku, pa i najmanju izmenu, mora da se menja kod.

Iz ovoga je proizišla nova kategorija - nikada završeni programi, to jest završeni ali sa veoma kratkim vekom trajanja - do prve izmene. Ili po naški, “drži bure vodu dok majstori odu”. Što je najtužnije u celoj priči, razlog nije premalo znanja. Naprotiv, razlog za ovakvo stanje je previše znanja. Programeri su postali veoma dobri u onome što rade - pišu kod.

Onaj ko brzo piše kod, ne može da shvati zašto bi koristio SELECT … GROUP BY kad je njemu očas posla da otvori ADO rekordset, definiše konekcije, ODBC source i sve ostalo, deklariše nekoliko varijabli, protrči par puta kroz rekordset. DO WHILE je čarobna struktura, uživanje je pisati kod koji koristi petlje :-)

 Pošto rezultat treba mom šefu, onda je mali problem kako to predstaviti. Ništa lakše, napisaćemo .NET aplikacijicu, koja će to da prikaže. Ali nama to treba samo jednom, to je više ad-hoc. O, pa upotrebimo SQL Report Services, napravimo report, postavimo link, damo šefu userid i password i eto mu reporta. Da, ali zašto onda ADO? Nema problema, napisaćemo stored proceduru, sa temp tabelom unutra, pa ćemo odatle da pošaljemo podatke u Report Services. Dobro, ali smo sad sve podigli na nivo interneta, Reporting Services traži bar intranet. Zašto nam sve to treba? O, pa zbog skalabilnosti. Ali meni treba ad-hoc izveštaj, za tačno jednog korisnika. O, pa mi uvek mislimo na budućnost i moguća proširenja sistema (kao da će biti dvesta šefova širom kontinenta koliko iduće nedelje :-).

Dobro, a šta ako šef zatraži neke nove kolone u izveštaju? Ništa zato, samo nam javite par dana ranije šta vam treba, mislim dajte nam specifikaciju i mi ćemo to odraditi, tačno po specifikaciji, ako imamo raspoložive programere u tom mometu. Pa šta vam rade programeri ako nisu raspoloživi? Pa prepravljaju kod pošto vi svaki čas menjate specifikacije.

Verovali ili ne ovo je bila priča iz stvarnog života. A sve što nam je trebalo je bio najprostiji SELECT.. GROUP BY sa možda Cut-Paste u Excel. Znanje i mudrost su očigledno dve različite kategorije.

Kao što rekoh, inženjeri su takva sorta da uvek moraju da znaju ne samo šta treba da se radi, nego i zašto je to tako i može li to bolje i efikasnije. Pitam se, pitam, mora li sve ovako ili može efikasnije  :-)


“Used by”: Pretražite svoj source code

November 8, 2007 – Dejan

Često se ukaže potreba da provjerimo, gdje se u našem “source code-u” koristi neka tabela, paket, procedura i sl.

Mnogi IDE alati (npr. TOAD i PL/SQL Developer) mogu to vizuelno da prikažu, kada odaberete neki objekt i onda kliknete na “Used by”. Time dobijate listu objekata (objekat može biti neka procedura, funkcija, paket, trigger, view i td.) u kojima se koristi traženi objekat.

Ukoliko nemate pri ruci neki takav alat, onda možete jednostavno jednim SQL upitom saznati, gdje se šta koristi ili da jednostavno pretražite scoj “source code”:

SELECT *
FROM user_source s
WHERE UPPER(s.text) LIKE '%IME\_NEKE\_TABELE%' ESCAPE '\'; 

SELECT *
FROM user_source s
WHERE UPPER(s.text) LIKE '%MOJA\_USKLADISTENA\_PROCEDURA%' ESCAPE '\';

ORA-00600: internal error code, arguments: [pxTmpAlo_pkey]

November 7, 2007 – Dejan

Ukoliko koristite višeprocesorske servere, Real Application Cluster i/ili paralelizovane upite nad ogromnim tabelama, može se dogoditi da dobijete gorenavedenu grešku, npr.:
ORA-00600: internal error code, arguments: [pxTmpAlo_pkey], [2], [3], [], [], [], [], []

onda podesite parametar _slave_mapping_enabled na false:

alter system set "_slave_mapping_enabled"=false scope=both sid='*';

Edit (12.11.2007): Primijetio sam da se ovo dešava sa tabelama, koje su kreirane sa opcijom PARALLEL (DEGREE 2) . Kada prebacim te tabele u NOPARALLEL režim, onda se gorenavedena greška više ne pojavljuje. Inače, ova greška je riješena u patchu 10.2.0.4 i u verziji 11g.


Stanje na tržištu baza podataka

November 7, 2007 – Dejan

U okviru predavanja na HROUG konferenciji ove godine u Rovinju, gdin. Zoran Jovanović je napisao opširan tekst o stanju na tržištu upravljačkih sistema baza podataka, tj. o stanju na tržištu baza podataka.

Možete pročitati usporedne informacije o Oracleu, Microsoftu, IBM i drugim ponuđačima baza podataka, kao i mnoge druge interesantne novosti i informacije.


Kupovina TOAD for Oracle Professional

November 7, 2007 – Dejan

Zaposlili smo u firmi još nekoliko Oracle programera, pa smo povodom toga odlučili da kupimo još 3 nove licence za “TOAD for Oracle Professional”.

Pošaljem ja E-Mail poruku na službenu adresu i pitam šta sve dobijamo uz tu licencu, da li imamo pravo na besplatni upgrade, support i sl.
Idući dan stiže meni odgovor od jednog njihovog prodavca, da dobijam support, besplatni upgrade i da će mi čak spustiti cijenu za 10%!!!

Ja se obradovao, kontam to je 300 EUR uštede…

Ali prerano sam se obradovao. Naime, na njihovom sajtu (quest.com) stoji cijena od USD $ 1,465 za jednu licencu, što je pretvoreno u evre malo iznad 1 000 EUR. On meni poslao ponudu sa ”sniženom” cijenom od ”samo” 1330 EUR po licenci !? Kontam ja da se nije zeznuo, nazovem ga, ali se nije zeznuo. Izgleda da oni kurs USD->EUR još uvijek računaju po nekom starom kursu iz prošle godine ili ko zna kad, pa sam mu ja lijepo objasnio da će me jeftinije izaći, ako kupim direktno online.

Pokušao on meni nešto da petlja, kao to su cijene samo za Ameriku, pa onda da cijene nisu ažurirane, ali se nisam dao smesti. I kad je vidio čovjek da me ne može preveslati tako lako, pristao je da mi pošalje licence po online cijeni uz još neke bonus stvari. Super.

Sa par razmjenjenih E-Mail poruka i par telefonskih poziva,  uštedio sam nekoliko stotina EUR.

Mada, mogao sam možda odmah kupiti online, da se ne bakćem direktno sa prodavačima. :D


Pitanja u vezi Oracle Real Application Cluster?

November 7, 2007 – Dejan

Za 10-ak dana imam dvodnevni individualni “trening” u vezi Oracle Real Application Clustera, a što više znanja, trikova i “best practice” u vezi toga, pokušaće mi prenijeti gdin. Pierre Wagner, jedan od vodećih Oracle stručnjaka u Austriji. On je vođa “Expert Service” tima za Oracle u Austriji i jedan je od autora službene dokumentacije za “Oracle 11g Real Application Cluster  on Linux“.

Ja već imam neka pripremljena pitanja i par problema da mu postavim, a ukoliko i vi želite nešto da pitate u vezi Oracle RAC, ostavite ovdje komentar.


Recovery Oracle baze pomoću RMAN-a

October 31, 2007 – Dejan

U prethodnom tekstu sam pisao kako obaviti backup Oracle baze pomoću RMAN-a, u kojem sam pored ostalog naveo i da ću pokazati kako se vrši povratak (recovery) Oracle baze pomoću RMAN-a. Pošto je taj tekst ionako bio dug, odlučio sam ovaj dio objaviti kao nastavak.

Od mnogih mogućih situacija u kojima može doći do problema u radu baze, ja ću objasniti dva:
- Povratak izgubljenog/oštećenog SYSTEM tablespace
- Povratak obične datoteke ili tablespacea (NON-SYSTEM)

Pročitaj kompletan tekst »


Isti upit izražen na različite načine

October 28, 2007 – Srdjan

Većina upita može da se napiše na različite načine.  C.J. Date je u online članku “Fifty Ways to Quote Your Query” prikazao listu od 52 načina da se iskaže jedan upit! Nije mi namera da se u ovome takmičim sa Date-om, već želim da prikažem nekoliko praktičnih i pravolinijskih metoda pomoću kojih se izvesna forma upita može zameniti adekvatnom (a efikasnijom) formom.

Prikazaću dve slične metode za transformaciju upita.

1. Prvom metodom se upit oblika … IN (SELECT …) pretvara u upit oblika … EXISTS (SELECT …), a naknadno se EXISTS zamenjuje sa INNER JOIN.

2. Drugom metodom se upit oblika … NOT IN (SELECT …) pretvara u upit oblika … NOT EXISTS (SELECT …), a naknadno se EXISTS zamenjuje sa LEFT OUTER JOIN

Cilj ovih transformacija je da se pronađe oblik upita koji najbolje odgovara SQL optimizatoru konkretnog SUBP-a (sistema za upravljanje bazama podataka), to jest da se koristi oblik upita koji se najbrže izvršava.

Struktura testnih tabela i testni podaci

Prvo ću dati strukturu i podatke, koji će mi pomoći u demonstraciji metoda transformacije upita. (Strukturu sam pozajmio iz jednog od mojih predhodnih postova.)

CREATE TABLE partneri (
  sifra_partnera INTEGER NOT NULL,
  ime_partnera VARCHAR(50) NOT NULL,
  CONSTRAINT pk_par
    PRIMARY KEY (sifra_partnera)
);    

CREATE TABLE adrese (
  sifra_partnera INTEGER NOT NULL,
  opis_adrese VARCHAR(20) NOT NULL,
  CONSTRAINT pk_tra
    PRIMARY KEY (sifra_partnera, opis_adrese),
  CONSTRAINT fk_tra_par
    FOREIGN KEY (sifra_partnera) REFERENCES partneri
    ON DELETE CASCADE ON UPDATE CASCADE );    

INSERT INTO partneri (sifra_partnera, ime_partnera)
  VALUES (1, 'Mika str');
INSERT INTO partneri (sifra_partnera, ime_partnera)
  VALUES (2, 'Pera doo');
INSERT INTO partneri (sifra_partnera, ime_partnera)
  VALUES (3, 'MELANIJA');
INSERT INTO partneri (sifra_partnera, ime_partnera)
  VALUES (4, 'Joca doo');
INSERT INTO partneri (sifra_partnera, ime_partnera)
  VALUES (5, 'Doo ZIKA i SONS');    

INSERT INTO adrese (sifra_partnera, opis_adrese)
  VALUES (1, 'prodavnica');
INSERT INTO adrese (sifra_partnera, opis_adrese)
  VALUES (2, 'prodavnica br 1');
INSERT INTO adrese (sifra_partnera, opis_adrese)
  VALUES (2, 'prodavnica br 2');
INSERT INTO adrese (sifra_partnera, opis_adrese)
  VALUES (2, 'Kafana kod Pere');
INSERT INTO adrese (sifra_partnera, opis_adrese)
  VALUES (4, 'uprava');
INSERT INTO adrese (sifra_partnera, opis_adrese)
  VALUES (4, 'skladiste');
INSERT INTO adrese (sifra_partnera, opis_adrese)
  VALUES (4, 'prodavnica');
INSERT INTO adrese (sifra_partnera, opis_adrese)
  VALUES (5, 'Kafana Sinovi');

Prva metoda - zamena upita oblika … IN (SELECT …)

Ovu metodu ću demonstrirati na upitu koji daje odgovor na pitanje: Treba prikazati partnere koji imaju barem dve adrese.

Jedan od upita koji daje odgovor na ovo pitanje je upit koji koristi IN izraz:

SELECT p.sifra_partnera, p.ime_partnera
  FROM partneri AS p
 WHERE p.sifra_partnera IN
       (SELECT a.sifra_partnera
          FROM adrese AS a
         GROUP BY a.sifra_partnera
        HAVING COUNT(a.sifra_partnera) > 1
       )
 ORDER BY p.sifra_partnera

Kako od ovog upita napraviti ekvivalentan upit upotrebom izraza EXISTS? Ponoviću ponovo predhodan upit, ali ću bojom istaći ključne elemente upita koji učestvuju u transformaciji.

SELECT p.sifra_partnera, p.ime_partnera
  FROM partneri AS p
 WHERE p.sifra_partnera IN
       (SELECT a.sifra_partnera
          FROM adrese AS a
         GROUP BY a.sifra_partnera
        HAVING COUNT(a.sifra_partnera) > 1
       )
 ORDER BY p.sifra_partnera

Ekvivalentan upit je sledeći upit u kojem sam istakao šta se desilo sa ključnim elementima iz predhodnog upita. Treba primetiti da je p.sifra_partnera iz spoljašnjeg upita ušla u unutrašnji upit u sastavu WHERE klauzule.

SELECT p.sifra_partnera, p.ime_partnera
  FROM partneri AS p  WHERE EXISTS
       (SELECT a.sifra_partnera
          FROM adrese AS a
         WHERE p.sifra_partnera = a.sifra_partnera
         GROUP BY a.sifra_partnera
        HAVING COUNT(a.sifra_partnera) > 1
       )
 ORDER BY p.sifra_partnera

Kako od ovog upita doći do upita koji koristi INNER JOIN? Isti ključni elementi i dalje učestvuju u transformaciji i dobija se donji upit. Treba primetiti da konstrukcija p.sifra_partnera = a.sifra_partnera izlazi iz unutrašnjeg upita i pojavljuje se kao uslov spajanja u spoljašnjem upitu.

SELECT p.sifra_partnera, p.ime_partnera
  FROM partneri AS p
       INNER JOIN
       (SELECT a.sifra_partnera
          FROM adrese AS a
         GROUP BY a.sifra_partnera
        HAVING COUNT(a.sifra_partnera) > 1
       ) AS pa
         ON p.sifra_partnera = pa.sifra_partnera
 ORDER BY p.sifra_partnera

Ceo postupak, korak po korak, sam bolje demonstrirao pomoću Power Point prezentacije Isti upit 1.

Rezultat izvršavanja sva tri gornja upita je isti:

sifra_partnera   ime_partnera
--------------   ------------
             2   Pera doo
             4   Joca doo

Druga metoda - zamena upita oblika … NOT IN (SELECT …)

Ovu metodu ću demonstrirati na upitu koji daje odgovor na pitanje: Treba prikazati partnere koji nemaju adresu.

Jedan od upita koji daje odgovor na ovo pitanje je upit koji koristi IN izraz:

SELECT p.sifra_partnera, p.ime_partnera
  FROM partneri AS p
 WHERE p.sifra_partnera NOT IN
       (SELECT a.sifra_partnera
          FROM adrese AS a
       )
 ORDER BY p.sifra_partnera

Kako od ovog upita napraviti ekvivalentan upit upotrebom izraza NOT EXISTS? Ponoviću ponovo predhodan upit, ali ću bojom istaći ključne elemente upita koji učestvuju u transformaciji.

SELECT p.sifra_partnera, p.ime_partnera
  FROM partneri AS p
 WHERE p.sifra_partnera NOT IN
       (SELECT a.sifra_partnera
          FROM adrese AS a
       )
 ORDER BY p.sifra_partnera

Ekvivalentan upit je sledeći upit u kojem sam istakao šta se desilo sa ključnim elementima iz predhodnog upita. Treba primetiti da je p.sifra_partnera iz spoljašnjeg upita ušla u unutrašnji upit u sastavu WHERE klauzule.

SELECT p.sifra_partnera, p.ime_partnera
  FROM partneri AS p
 WHERE NOT EXISTS
       (SELECT a.sifra_partnera
          FROM adrese AS a
         WHERE p.sifra_partnera = a.sifra_partnera
       )
 ORDER BY p.sifra_partnera

Kako od ovog upita doći do upita koji koristi LEFT OUTER JOIN? Isti ključni elementi i dalje učestvuju u transformaciji i dobija se donji upit. Treba primetiti da konstrukcija p.sifra_partnera = a.sifra_partnera izlazi iz unutrašnjeg upita i pojavljuje se kao uslov spajanja u spoljašnjem upitu. Takođe je bitno napomenuti kako je potrebno dodati WHERE klauzulu pa.sifra_partnera IS NULL.

SELECT p.sifra_partnera, p.ime_partnera
  FROM partneri AS p
       LEFT OUTER JOIN
       (SELECT a.sifra_partnera
          FROM adrese AS a
       ) AS pa
         ON p.sifra_partnera = pa.sifra_partnera
 WHERE pa.sifra_partnera IS NULL
 ORDER BY p.sifra_partnera

Slično kao i kod prethodne metode, i ovde sam ceo postupak demonstrirao pomoću Power Point prezentacije Isti upit 2.

Rezultat izvršavanja sva tri gornja upita je isti:

sifra_partnera   ime_partnera
--------------   ------------
             3   MELANIJA

Zaključak

Koji od prikazanih upita daje rezultat najbrže? To se mora proveriti u zavisnosti od konkretnog SUBP-a, količine podataka, postojanja indeksa. Može se desiti da pojedini (stariji?) sistemi ni ne podržavaju sve prikazane verzije upita.

Moja iskustva sa PostgreSQL 8.1 i 8.2 sistemima pokazuju, da se najbolje ponašaju verzije upita koje koriste INNER JOIN i LEFT OUTER JOIN.