Autor Zpráva
martin1
Profil *
Ahoj,
nejsem zrovna velky expert na SQL, tak bych se rad poradil ohledne ulozeneych procedur. (Pouzivam MySQL databazi).
Jak moc je vhodne pouzivat ulozene procedury? Nezpomaly se tim DB? Je rozumne mit procedury "skoro na vsechno"?
Zda se mi lepsi napsat proceduru, nez pak vsechno resit v koncove aplikaci.

Kouknete prosim na nasledujici kod (jenom priklad):
CREATE TABLE adresa (
    id INTEGER NOT NULL AUTO_INCREMENT,
    ulice VARCHAR(50),
    cp CHAR(5),
    mesto VARCHAR(25) NOT NULL,
    psc CHAR(5),
    PRIMARY KEY (id)
) DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci ;

CREATE TABLE uzivatel (
    id INTEGER NOT NULL AUTO_INCREMENT,
    login VARCHAR(20) NOT NULL,
    telefon CHAR(14),
    heslo CHAR(128) NOT NULL,
    adresa_id INTEGER NOT NULL,
    PRIMARY KEY (id),
    UNIQUE UQ_uzivatel_login(login),
    KEY (adresa_id)
) DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci ;

ALTER TABLE uzivatel ADD CONSTRAINT FK_uzivatel_adresa 
    FOREIGN KEY (adresa_id) REFERENCES adresa (id);


delimiter $$ 
create procedure SP_vlozUzivateleSAdresou ( login VARCHAR(20), heslo CHAR(20), ulice VARCHAR(50), cp CHAR(5), mesto VARCHAR(25), psc CHAR(5) ) 
begin 
    if exists(SELECT id FROM adresa WHERE `ulice`=ulice AND `cp`=cp AND `mesto`=mesto AND `psc`=psc) then 
        INSERT INTO uzivatel (`login`, `heslo`, `adresa_id`) VALUES (login, SHA2(heslo,512), (SELECT id FROM adresa WHERE `ulice`=ulice AND `cp`=cp AND `mesto`=mesto AND `psc`=psc) );
    else 
        INSERT INTO adresa (`ulice`, `cp`, `mesto`, `psc`) VALUES (ulice, cp, mesto, psc);
        INSERT INTO uzivatel (`login`, `heslo`, `adresa_id`) VALUES (login, SHA2(heslo,512), (SELECT id FROM adresa WHERE `ulice`=ulice AND `cp`=cp AND `mesto`=mesto AND `psc`=psc) );
    end if; 
end $$ 
delimiter ; 

call SP_vlozUzivateleSAdresou ("martin", "abc123", "Ulice", "1024", "Město", "12345");
call SP_vlozUzivateleSAdresou ("pepa",   "456def", "Ulice", "1024", "Město", "12345");

Pridavam uzivatele a k nemu adresu. Normalne musim vytvorit nejdriv zaznam v tabulce adresa a pote uzivatele. Jeste musim ve sve aplikaci hledat, jestli uz adresa existuje.
Takhle jenom zavolam ulozenou proceduru a mam po starostech :-)

Jaky na to mate nazor?

Dekuji za vase nazory!
Joker
Profil
Podle mě to není problém a je to tak správně. Teda až na slovo „nezpomalý“.
Alphard
Profil
S výkonem problém nevidím, spíš naopak, bude to rychlejší, ale uvedený případ se mi na obvyklých webech zdá moc náročný na psaní a údržbu. Inserty běžně nechávám sestavovat z položek polí, představa, že bych měl udělat hromady podobných jednoduchých procedur a při přidání nějakého sloupce vše upravovat, mě zrovna neláká.
Situace se výrazně změní ve chvíli, kdy k db přistupuje více aplikací. Čím složitější systém, tím výhodnější to bude. Pro velké aplikace jsou uložený procedury/funkce/pohledy někdy jediný přístupový bod k db.
Camo
Profil
Alphard:
Ale ak pridáš nejaký stĺpec, tak máš jedno či ti to urobí bordel v php kóde, alebo v procedúre, nie? Ja tiež rozmýšľam, že by som to zaviedol u seba. Mne to vychádza ako efektívnejšie. Všetky tie testy a opakovanie kódu ti vypadnú. Len nevieš, čo to presne robí. Jedine to okomentovať.
martin1
Profil *
Alphard:
>> ale uvedený případ se mi na obvyklých webech zdá moc náročný na psaní a údržbu

Mas pravdu, dal jsem to jen jako ukazku.
Napada me jiny pripad. Existujici uzivatel si bude chtit zmenit adresu. Zada mi novou adresu a ja musim najit jestli uz exituje. Kdyz ano, tak adresa_id nastavim na spravne id.
Pokud pouziju ulozenou proceduru, tak do db jenom poslu nove udaje a vic neresim. Jaky na to mas nazor?

A jeste jedna vec. jaky mas nazor na pouzivani pohledu? Kdyz vyse uvedeny kod rozsirim o tabulku stat a budu chtit vypsat login vsech uzivatelu z ceska, je dobry napad si udelat pohled a ten pak volat z aplikace, nebo je lepsi z aplikace volat select s joinem?

CREATE TABLE stat (
    id INTEGER NOT NULL AUTO_INCREMENT,
    nazev VARCHAR(50) NOT NULL,
    PRIMARY KEY (id)
) DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci ;

CREATE TABLE adresa ( 
    id INTEGER NOT NULL AUTO_INCREMENT,
    ulice VARCHAR(50),
    cp CHAR(5),
    mesto VARCHAR(25) NOT NULL,
    psc CHAR(5),
    stat_id INTEGER NOT NULL,
    KEY (stat_id),
    PRIMARY KEY (id)
) DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci ;
 
CREATE TABLE uzivatel (
    id INTEGER NOT NULL AUTO_INCREMENT,
    login VARCHAR(20) NOT NULL,
    telefon CHAR(14),
    heslo CHAR(128) NOT NULL,
    adresa_id INTEGER NOT NULL,
    PRIMARY KEY (id),
    UNIQUE UQ_uzivatel_login(login),
    KEY (adresa_id)
) DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci ;
 
ALTER TABLE uzivatel ADD CONSTRAINT FK_uzivatel_adresa 
    FOREIGN KEY (adresa_id) REFERENCES adresa (id);

ALTER TABLE adresa ADD CONSTRAINT FK_adresa_stat 
    FOREIGN KEY (stat_id) REFERENCES stat (id); 

INSERT INTO `stat` (`id`, `nazev`) VALUES
(1, 'Česká Republika'),
(2, 'USA'); 

CREATE VIEW vwUzivateleCZ AS 
    SELECT stat.nazev, uzivatel.login 
    FROM uzivatel
    INNER JOIN adresa ON uzivatel.adresa_id = adresa.id
    INNER JOIN stat ON adresa.stat_id = stat.id;
--------
SELECT stat.nazev, uzivatel.login
FROM uzivatel
INNER JOIN adresa ON uzivatel.adresa_id = adresa.id
INNER JOIN stat ON adresa.stat_id = stat.id
--------
SELECT * FROM vwUzivateleCZ
Jan Tvrdík
Profil
martin1:
Doporučuji ti zvážit přechod na PostgreSQL, které je přeci jenom na tento styl vývoje (psaní pohledů a procedur) vhodnější.
Alphard
Profil
Camo [#4]:
Já nemluvím o bordelu, já mluvím o nutnosti změny. PHP musím změnit v každém případě, přinejmenším předat další parametr (pokud nechci přímo expandovat pole, což by možná taky šlo). Čím více míst, kde bude nutná změna, tím hůře. Dělat jen obálku nad insertem se mi nezdá užitečné. Pokud by se ale insert prováděl z více různých aplikací, je to úplně jiná situace, to jsem psal hned na začátku.

martin1 [#5]:
Já nechci bez znalosti kontextu odhadovat nějakou hranici, když ještě ne a kdy už ano. Sám uložené procedury používám v místech, kde se provádí složitější práce s daty a je tedy výhodné být k těm datům co nejblíže. Občas jsem měl také určité snahy přenést víc aplikační logiky na databázi, ale narazil jsem na velkou složitost při programování. Jak píše [#6] Jan Tvrdík, MySQL má v této oblasti oproti konkurenci rezervy.
Pak vznikají konstrukce jako
declare curs cursor for select ...;
 declare continue handler for not found set bDone = 1;
 open curs; 
 drop temporary table if exists __tmp;
 create temporary table ...
Ta dočasná tabulka je tam jen proto, že MySQL nemá žádné pole, do kterého by šlo dočasně odložit pár záznamů. Procházení přes poměrně složité cursory.

Pohledy používám, ale taky to s nimi nepřeháním. Pro opakující se joiny, které nemám v pohledech, mám pomocí dibi sestavený základní dotaz a ten potom rozvíjím do konkrétních případů.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: