Alkalmazható természettudományok oktatása a Tudásalapú Társadalomban TÁMOP-4.1.2.A/1-11/1-2011-0038



Hasonló dokumentumok
Adatbázis rendszerek. dr. Siki Zoltán

Adatbázisok. 8. gyakorlat. SQL: CREATE TABLE, aktualizálás (INSERT, UPDATE, DELETE), SELECT október október 26. Adatbázisok 1 / 17

Adatbázis-lekérdezés. Az SQL nyelv. Makány György

SQL ALAPOK. Bevezetés A MYSQL szintaxisa Táblák, adatok kezelésének alapjai

A gyakorlat során MySQL adatbázis szerver és a böngészőben futó phpmyadmin használata javasolt. A gyakorlat során a következőket fogjuk gyakorolni:

SQL haladó. Külső összekapcsolások, Csoportosítás/Összesítés, Beszúrás/Törlés/Módosítás, Táblák létrehozása/kulcs megszorítások

Java és web programozás

A relációs adatbáziskezelés szabványos nyelve Két fő csoportba sorolhatók az utasításai

Adatbáziskezelő-szerver. Relációs adatbázis-kezelők SQL. Házi feladat. Relációs adatszerkezet

A gyakorlat során MySQL adatbázis szerver és a böngészőben futó phpmyadmin használata javasolt. A gyakorlat során a következőket fogjuk gyakorolni:

ADATBÁZIS-KEZELÉS FÉLÉVES FELADAT

Java és web programozás

Adatbáziskezelı-szerver SQL. Relációs adatbázis-kezelık. Relációs adatszerkezet. Házi feladat

Bevezetés: az SQL-be

Az SQL nyelv Structured Query Language (Struktúrált lekérdező nyelv)

Adatbázis, adatbázis-kezelő

Adatbázis-kezelő rendszerek. dr. Siki Zoltán

Adatbázisok. 9. gyakorlat SQL: SELECT október október 26. Adatbázisok 1 / 14

AB1 ZH mintafeladatok. 6. Minősítse az állításokat! I-igaz, H-hamis

Célkitűzések Az Oracle10 g felépítésének, használatának alapszíntű megismerése

Adattípusok. Max. 2GByte

Adatbázis-kezelés. Harmadik előadás

Adattípusok. Max. 2GByte

Programozás. Adatbázis-kezelés (alapok) Fodor Attila

Adatbázisok elmélete 9. előadás

Tartalomjegyzék. Tartalomjegyzék 1. Az SQL nyelv 1 Az SQL DDL alapjai 2

Adatbázisok. 2. gyakorlat SQL november november 12. Adatbázisok 1 / 31

MySQL. Elektronikus jegyzet Széchenyi István Egyetem Távközlési tanszék

Dr. Pál László, Sapientia EMTE, Csíkszereda WEB PROGRAMOZÁS 4.ELŐADÁS. Adatbázis alapú alkalmazások készítése PHP-ben

ADATBÁZIS-KEZELÉS - BEVEZETŐ - Tarcsi Ádám, ade@inf.elte.hu

Adatbázis rendszerek SQL nyomkövetés

Bevezetés az SQL-be. Tankönyv: Ullman-Widom: Adatbázisrendszerek Alapvetés Második, átdolgozott kiadás, Panem, 2009

ADATBÁZISOK gyakorlat: SQL 2. rész SELECT

Webfejlesztés 4. alkalom

Tábla létrehozása: CREATE TABLE alma( ID INT( 3 ) NOT NULL PRIMARY KEY, Leiras VARCHAR( 100 ) );

Adatbázismodellek. 1. ábra Hierarchikus modell

SQL. 1.rész. 1.elıadás // Adatbázisok-1 elıadás // Ullman-Widom (Stanford) tananyaga alapján // Hajas Csilla (ELTE IK) 1

Adatbázisok elmélete 10. előadás

SQL parancsok feldolgozása

Adatbázisok. 8. gyakorlat. SQL: CREATE TABLE, aktualizálás (INSERT, UPDATE, DELETE) október október 22. Adatbázisok 1 / 14

BGF. 4. Mi tartozik az adatmodellek szerkezeti elemei

B I T M A N B I v: T M A N

PHP-MySQL. Adatbázisok gyakorlat

Relációsémák létrehozása SQL nyelvben

ADATBÁZIS RENDSZEREK I BEADANDÓ

Adatbázis I. 11. előadás. Kulcsok az SQL ben. Hivatkozásépségi megszorítások és idegen kulcsok.

Adatbázis Rendszerek I. 10. SQL alapok (DML esettanulmány)

Az indexelés újdonságai Oracle Database 12c R1 és 12c R2

Adatbázisok elmélete 9. előadás

Adatbázisok* tulajdonságai

SQL*Plus. Felhasználók: SYS: rendszergazda SCOTT: demonstrációs adatbázis, táblái: EMP (dolgozó), DEPT (osztály) "közönséges" felhasználók

Vizuális programozás gyakorlat

Adatbázis kezelés Delphiben. SQL lekérdezések

SQL. Táblák összekapcsolása lekérdezéskor Aliasok Allekérdezések Nézettáblák

Gyakorlás: Hozzunk létre egy Alkalmazottak táblát AZO szám, Részleg szöveg, Munkakör szöveg és BelépésDátuma dátum típussal.

Adatmodellezés. 1. Fogalmi modell

ALAPOK. 0 és 255 közé eső számértékek tárolására. Számértékek, például távolságok, pontszámok, darabszámok.

Az SQL adatbázisnyelv: DML

MS ACCESS 2010 ADATBÁZIS-KEZELÉS ELMÉLET SZE INFORMATIKAI KÉPZÉS 1

SQL PÉLDATÁR. készült a PTE TTK Iskolai informatika III. kurzus teljesítésére

Adatbázis tartalmának módosítása

SQL jogosultság-kezelés. Privilégiumok Grant és Revoke Grant Diagrammok

Az SQL nyelv. SQL (Structured Query Language = Strukturált Lekérdező Nyelv).

Lekérdezések az SQL SELECT utasítással

Készítette: Szabóné Nacsa Rozália

Adatbázis rendszerek. 4. előadás Redundancia, normalizálás

Adatbázis Rendszerek II. 8. Gyakorló környezet

Adatmodellezés, alapfogalmak. Vassányi István

Adatbázis Rendszerek I. 9. SQL alapok (DDL esettanulmány)

Fájlszervezés. Adatbázisok tervezése, megvalósítása és menedzselése

OO PDO. Tehát PDO használatával, könnyen átállhatunk egy másik adatbáziskezelőre, anélkül hogy a kódot teljes egészében újraírnánk.

C++ programozási nyelv

Hogyan fogalmazzuk meg egyszerűen, egyértelműen a programozóknak, hogy milyen lekérdezésre, kimutatásra, jelentésre van szükségünk?

Elemi alkalmazások fejlesztése IV.

Adatbázis használat I. 2. gyakorlat

2 Access 2016 zsebkönyv

STRUCTURED QUERY LANGUAGE(SQL) - ALAPOK

Adatbázisok II. rész

LOGISZTIKAI ADATBÁZIS RENDSZEREK JOIN, AGGREGÁCIÓ

SQL DDL-1: táblák és megszorítások

LOGISZTIKAI ADATBÁZIS RENDSZEREK UNIÓ, ALLEKÉRDEZÉSEK

Adatbázis-kezelés alapok Adatbázisok című tárgyhoz, ismétlés kapcsán

8. Gyakorlat SQL. DDL (Data Definition Language) adatdefiníciós nyelv utasításai:

Többtáblás lekérdezések megjelenítése

Operációs rendszerek. 10. gyakorlat. AWK - bevezetés UNIVERSITAS SCIENTIARUM SZEGEDIENSIS UNIVERSITY OF SZEGED

file:///d:/okt/ad/jegyzet/ad1/b+fa.html

SQL DDL-2 (aktív elemek) triggerek

BEVEZETÉS Az objektum fogalma

RELÁCIÓS ADATBÁZISSÉMÁK. Egyed-kapcsolat modellről átírás

Adatbázis rendszerek Definíciók:

Operációs rendszerek. 9. gyakorlat. Reguláris kifejezések - alapok, BASH UNIVERSITAS SCIENTIARUM SZEGEDIENSIS UNIVERSITY OF SZEGED

sallang avagy Fordítótervezés dióhéjban Sallai Gyula

Az SQL*Plus használata

Programozási alapismeretek 4.

A wiki módszer. Internetes tartalom kooperatívan, szabad szoftveres alapon. Gervai Péter

ADATBÁZIS-KEZELÉS. Adatbázis-kezelő rendszerek

Adatbázis-kezelés. alapfogalmak

Magas szintű adatmodellek Egyed/kapcsolat modell I.

Adatbázis Rendszerek II. 3. SQL alapok

Választó lekérdezés létrehozása

Átírás:

Alkalmazható természettudományok oktatása a Tudásalapú Társadalomban TÁMOP-4.1.2.A/1-11/1-2011-0038

SQL antipatternek Útmutató az adatbázis-kezelés csapdáinak elkerüléséhez Bill Karwin

A mű a következő kiadás alapján készült: Bill Karwin: SQL Antipatterns Pragmatic Bookshelf, 2010 ISBN 978 193 4356 555 A Pragmatic Bookshelf engedélyével. The translation is published by arrangement with Pragmatic Bookshelf publishing. Fordította: Dippold Ádám Szerkesztette: Hedvig Olga Lektorálta: Dr. Czenky Márta Bill Karwin, 2010 Hungarian translation Dippold Ádám, 2013 Műszaki Könyvkiadó Kft., 2013 ISBN 978 963 16 4613 9 Kiadja a Műszaki Könyvkiadó Kft. Felelős kiadó: Orgován Katalin ügyvezető igazgató Felelős szerkesztő: Csík Zoltán Műszaki szerkesztő: Haász Anikó Tördelőszerkesztés: Weep Bt. Terjedelme: 36 A5 ív 1. magyar nyelvű kiadás e-mail: vevoszolg@muszakikiado.hu www.muszakikiado.hu 2

Tartalom 1. Bevezetés..................7 1.1 Kiknek szól ez a könyv? 8 1.2 Miről szól ez a könyv? 9 1.3 Mi nem szerepel ebben a könyvben? 10 1.4 Konvenciók 11 1.5 Adatbázis példa 12 1.6 Köszönetnyilvánítás 14 I. rész Logikai adatbázisokkal kapcsolatos antipatternek 2. Toronyiránt................ 17 2.1 A cél: többértékű attribútumok tárolása 17 2.2 Az antipattern: vesszőkkel elválasztott listák használata 18 2.3 Hogyan ismerjük föl az antipatternt? 21 2.4 Az antipattern indokolt használata 21 2.5 A megoldás: egy kapcsoló tábla létrehozása 21 3. Naiv fák................... 25 3.1 A cél: hierarchiák tárolása és lekérdezése 25 3.2 Antipattern: mindig függjön a szülőjétől 26 3.3 Hogyan ismerjük föl az antipatternt? 29 3.4 Az antipattern indokolt használata 30 3.5 A megoldás: alternatív famodellek használata 31 4. ID szükséges................. 41 4.1 A cél: az elsődleges kulcs létezésének megalapozása 42 4.2 Az antipattern: egy kaptafa 43 4.3 Hogyan ismerjük föl az antipatternt? 46 4.4 Az antipattern indokolt használata 47 4.5 A megoldás: testreszabás 48 5. Kulcsok nélkül................. 51 5.1 A cél: az adatbázis architektúrájának egyszerűsítése 51 5.2 Az antipattern: hagyjuk ki a megszorításokat! 52 5.3 Hogyan ismerjük föl az antipatternt? 55 5.4 Az antipattern indokolt használata 55 5.5 A megoldás: megszorítások deklarálása 55 6. Egyed attribútum érték............. 59 6.1 A cél: változó attribútumok támogatása 59 6.2 Az antipattern: egy általános attribútumtábla használata 60 6.3 Hogyan ismerjük föl az antipatternt? 65 6.4 Az antipattern indokolt használata 65 6.5 A megoldás: az altípusok modellezése 66 3

7. Polimorf kapcsolatok............... 73 7.1 A cél: több szülőre való hivatkozás 74 7.2 Az antipattern: többcélú idegen kulcs használata 74 7.3 Hogyan ismerjük föl az antipatternt? 77 7.4 Az antipattern indokolt használata 78 7.5 A megoldás: a kapcsolat egyszerűsítése 78 8. Többoszlopos attribútumok............. 85 8.1 A cél: többértékű attribútumok tárolása 85 8.2 Az antipattern: több oszlop létrehozása 86 8.3 Hogyan ismerjük föl az antipatternt? 89 8.4 Az antipattern indokolt használata 89 8.5 A megoldás: egy kapcsolódó tábla létrehozása 90 9. Metaadattribblik................ 93 9.1 A cél: a skálázhatóság támogatása 93 9.2 Az antipattern: klóntáblák vagy klónoszlopok 94 9.3 Hogyan ismerjük föl az antipatternt? 98 9.4 Az antipattern indokolt használata 98 9.5 A megoldás: particionálás és normalizálás 99 II. rész Fizikai adatbázis tervezésével kapcsolatos antipatternek 10. Kerekítési hibák............... 105 10.1 A cél: valós számok használata egész számok helyett 105 10.2 Az antipattern: a FLOAT adattípus használata 106 10.3 Hogyan ismerjük föl az antipatternt? 109 10.4 Az antipattern indokolt használata 109 10.5 A megoldás: a NUMERIC adattípus használata 109 11. 31 íz................... 111 11.1 A cél: az oszlop adott értékekre történő korlátozása 111 11.2 Az antipattern: az értékek megadása az oszlop definiálásakor 112 11.3 Az antipattern felismerése 115 11.4 Az antipattern indokolt használata 115 11.5 A megoldás: adjuk meg az értékeket az adatok között! 115 12. Fantomfájlok................ 119 12.1 A cél: képek vagy egyéb nagyobb terjedelmű médiafájlok tárolása 119 12.2 Az antipattern: tegyük föl, hogy fájlokat kell használnunk 120 12.3 Hogyan ismerjük föl az antipatternt? 123 12.4 Az antipattern indokolt használata 123 12.5 A megoldás: használjunk BLOB-ot, ha kell! 124 13. Indexvadászpuska............... 127 13.1 A cél: a teljesítmény optimalizálása 127 13.2 Az antipattern: ötletszerű indexhasználat 128 13.3 Hogyan ismerjük föl az antipatternt? 131 13.4 Az antipattern indokolt használata 132 13.5 A megoldás: az indexek MENTORálása 132 4

III. rész Lekérdezés antipatternek 14. Félelem az ismeretlentől............. 139 14.1 A cél: a hiányzó értékek megkülönböztetése 139 14.2 Az antipattern: a NULL érték közönséges értékként történő használata és megfordítva 140 14.3 Hogyan ismerjük föl az antipatternt? 143 14.4 Az antipattern indokolt használata 143 14.5 A megoldás: használjuk a NULL értéket egyedi értékként 144 15. Kétértelmű csoportok............. 149 15.1 A cél: a csoport legnagyobb értékű sorának megtalálása 149 15.2 Az antipattern: hivatkozás nem csoportosított oszlopokra 150 15.3 Hogyan ismerjük föl az antipatternt? 152 15.4 Az antipattern indokolt használata 153 15.5 A megoldás: egyértelmű oszlopok használata 153 16. Véletlenszerű kiválasztás............ 159 16.1 A cél: egy mintasor lekérdezése 159 16.2 Az antipattern: adatok véletlenszerű rendezése 160 16.3 Hogyan ismerjük föl az antipatternt? 161 16.4 Az antipattern indokolt használata 161 16.5 A megoldás: ne fontossági sorrendben 161 17. A szegény ember keresőmotorja.......... 165 17.1 A cél: full-text keresés 165 17.2 Az antipattern: mintaillesztő-predikátumok 166 17.3 Hogyan ismerjük föl az antipatternt? 167 17.4 Az antipattern indokolt használata 167 17.5 A megoldás: használd a helyes munkaeszközt 167 18. Spagettilekérdezés.............. 177 18.1 A cél: az SQL lekérdezések csökkentése 177 18.2 Az antipattern: összetett probléma megoldása egy lépésben 178 18.3 Hogyan ismerjük föl az antipatternt? 180 18.4 Az antipattern indokolt használata 180 18.5 A megoldás: oszd meg és uralkodj 181 19. Implicit oszlopok............... 185 19.1 A cél: a gépelés csökkentése 185 19.2 Az antipattern: a hivatkozás (shortcut), amely az őrületbe kerget 186 19.3 Hogyan ismerjük föl az antipatternt? 188 19.4 Az antipattern indokolt használata 188 19.5 A megoldás: explicit oszlopnevek 189 5

IV. rész Alkalmazásfejlesztési antipatternek 20. Olvasható jelszavak.............. 193 20.1 A cél: jelszavak visszaállítása vagy alaphelyzetbe állítása 193 20.2 Az antipattern: egyszerű szövegben tárolt jelszó 193 20.3 Hogyan ismerjük föl az antipatternt? 196 20.4 Az antipattern indokolt használata 196 20.5 A megoldás: tárold a jelszó sózott (salted) hashét 197 21. Az SQL-befecskendezés............. 203 21.1 A cél: dinamikus SQL lekérdezések írása 203 21.2 Az antipattern: ellenőrizetlen input végrehajtása kódként 204 21.3 Hogyan ismerjük föl az antipatternt? 210 21.4 Az antipattern indokolt használata 210 21.5 A megoldás: Ne bízz senkiben! 210 22. Pszeudokulcsok folytonos sorrendben........ 217 22.1 A cél: az adatok rendbe rakása 217 22.2 Az antipattern: a hiány kitöltése 218 22.3 Hogyan ismerjük föl az antipatternt? 220 22.4 Az antipattern indokolt használata 220 22.5 A megoldás: tedd túl rajta magad! 220 23. Nem látok.................... 225 23.1 A cél: írjunk kevesebb kódot! 225 23.2 Az antipattern: téglát szalma nélkül 226 23.3 Hogyan ismerjük föl az antipatternt? 228 23.4 Az antipattern indokolt használata 228 23.5 A megoldás: méltósággal javítsuk a hibákat 229 24. Diplomáciai védettség............. 231 24.1 A cél: a jó gyakorlatok alkalmazása 231 24.2 Az antipattern: az SQL mint másodosztályú állampolgár 232 24.3 Hogyan ismerjük föl az antipatternt? 232 24.4 Az antipattern indokolt használata 233 24.5 A megoldás: a minőség egyháza 233 25. Az égig érő paszuly.............. 243 25.1 A cél: a modellek egyszerűsítése az MNV-ben 244 25.2 Az antipattern: a modell egy Active Record 245 25.3 Hogyan ismerjük fel az antipatternt? 250 25.4 Az antipattern indokolt használata 250 25.5 A megoldás: a modell rendelkezzen Active Recorddal 250 Függelék.................... 257 1. A normalizálás szabályai............. 259 F1.1 Mit jelent az, hogy relációs? 259 F1.2 A normalizáció mítoszai 261 F1.3 Mi az a normalizáció? 262 F1.4 A józan ész 270 2. Irodalomjegyzék.............. 271 3. Index................... 273 6

A szakértő az az ember, aki minden lehetséges hibát elkövetett csak mindezt egy igen szűk szakterületen belül. (Niels Bohr) 1. FEJEZET Bevezetés Az első SQL-es munkámat visszautasítottam. Nem sokkal azután, hogy informatikusként végeztem a Kaliforniai Egyetemen, megkeresett egy menedzser, aki az egyetemen dolgozott, és a campusról ismert. A cége egy adatbázis-kezelő programot is fejlesztett, amely shell scriptek és egyéb hasonló eszközök segítségével (mint az awk) hordozható lett volna a különböző UNIX platformok között. Ebben az időben a modern dinamikus programnyelvek, mint például a Ruby, a Python, a PHP vagy akár a Perl, nem voltak különösebben elterjedtek. Az illető azért keresett meg, mert szüksége volt egy programozóra, aki megírja a kódot azért, hogy a program még ha korlátozottan is képes legyen felismerni és végrehajtani az SQL utasításokat. Azt mondta, hogy nincs szüksége az egész nyelv támogatottságára, ezzel egyébként is túl sok munka lenne csak egy programutasításra van szüksége: a SELECT-re. Az egyetemen nem tanultam az SQL-ről. Akkoriban az adatbázisok még nem voltak megtalálhatók minden bokorban mint ma, a nyílt forráskódú adatbázis-kezelők pedig (mint például a MySQL vagy a PostgreSQL) még nem léteztek. Ennek ellenére több komplett alkalmazást is leprogramoztam már shellben, tudtam egyet és mást a szintaktikai elemzőkről (parser), és részt vettem néhány egyetemi projektben, amelyeken fordítóprogramokat terveztünk, vagy épp számítógépes nyelvészettel foglalkoztunk. Mégis, milyen nehézséget okozhat egyetlen olyan utasítás értelmezőjének megírása, amely egy olyan specializált nyelvhez tartozik, mint az SQL? Úgy döntöttem, hogy elvállalom a munkát. Találtam egy kézikönyvet az SQL-ről, és csakhamar rá kellett jönnöm, hogy ez a nyelv nagyban különbözik azoktól a nyelvektől, amelyek az if és while-féle utasításokkal, változó értékadásokkal, kifejezésekkel és függvényekkel dolgoznak. A SE- LECT-et egyetlen parancsnak hívni ebben a nyelvben olyan, mintha a motort csupán a kocsi egy részének neveznénk. Szó szerinti értelemben mindkét kijelentés igaz, de nem érzékeltetik az általuk felhozott tárgyak bonyolultságát és mélységét. Rájöttem, azért, hogy lehetővé tegyem ennek az egyetlen utasításnak a végrehajtását, meg kell írnom egy tökéletesen működőképes relációsadatbázis- és lekérdezéskezelő rendszer motorját. Nem vállaltam a munkát, ehelyett egy SQL elemzőt és egy RDBMS (relációsadatbázis-kezelő rendszer) motort kódoltam inkább shell scriptben. A menedzser nem hangsúlyozta eléggé a projekt fontosságát talán épp azért, mert ő maga sem értette, hogy mire is képes egy relációsadatbázis-kezelő rendszer. Úgy tűnik, hogy a korai SQL-es tapasztalataim nagyjából hétköznapinak számítanak a szoftverfejlesztők körében még azok között is, akik informatikai diplomával rendelkeznek. A legtöbben autodidakta módon kerültek közel az SQL-hez: egyfajta 7

önvédelmi reakcióként próbálták megoldani a problémákat, amelyek egy-egy projekt kapcsán felmerülhettek, de nem tanulmányozták úgy a nyelvet, ahogy a többi programozási nyelvvel tették. Úgy tűnik, függetlenül attól, hogy az ember profi, vagy csak hobbiszinten programozik vagy akár tudományos kutatómunkát végez egy PhD-hez, az SQL-lel nem szokás a hagyományos keretek között megismerkedni. Amikor jobban megismerkedtem a nyelvvel, meglepett, hogy mennyire különbözik az eljárásorientált programozási nyelvektől: a C-től, a Pascaltól, valamint az olyan shell- vagy objektumorientált nyelvektől is, mint a C++, a Java, a Ruby vagy a Python. Az SQL a LISP-hez, a Haskellhez vagy az XSLT-hez hasonlóan egy deklaratív programozási nyelv, és halmazokra épül, az objektumorientált nyelvek viszont objektumokon alapulnak. A hagyományos képzésben részt vett fejlesztők gyakran visszarettennek ettől az úgynevezett impedancia-összeegyeztethetetlenségi problémától, így sokan inkább az objektumorientált nyelvekre koncentrálnak ahelyett, hogy elvesznének a hatékony SQL-használat dzsungelében. 1992 óta rengeteg SQL-es munkám volt. SQL-t használtam, amikor alkalmazásokat és könyvtárakat fejlesztettem Perlben és PHP-ban, valamint technikai segítséget, képzést és dokumentációt nyújtottam az InterBase RDBMS-hez. Sok száz netes és levelezőlistás kérdésre válaszoltam, és úgy vettem észre, hogy a fejlesztők rendre ugyanazokat a hibákat követik el. 1.1 Kiknek szól ez a könyv? Ezt a könyvet azoknak a szoftverfejlesztőknek írtam, akiknek SQL-t kell használniuk, és abban szeretnék nekik segítséget nyújtani, hogy hatékonyabban kezeljék ezt a nyelvet. Lehetnek kezdők vagy öreg rókák is: nagyon sok különböző tapasztalattal rendelkező emberrel beszéltem, akik mind profitálhatnak abból, amit itt leírtam. Ha már olvastál egy-két kézikönyvet az SQL-szintaxisról, és ismered egy SELECT utasítás minden záradékát, akkor már sikerrel használhatod a nyelvet. Fokozatosan egyre jobban megérted a nyelv működését: cikkeket olvasol és egyéb alkalmazásokat tanulmányozol de hogyan különböztetheted meg a jó megoldásokat a rosszaktól? Honnan tudhatod, hogy a legjobb megoldásokat választottad, és nem szorítottad magad sarokba azzal, amit elvégeztél? Lehetséges, hogy a könyv egyes részeiben leírtakat már jól ismered, de segíthetnek abban, hogy más nézőpontból közelíthesd meg a problémákat még akkor is, ha a megoldásokkal már tisztában vagy. Mindig jó, ha többszörösen is meggyőződsz róla, hogy a módszereid megfelelők, ehhez pedig nem árt megvizsgálni néhány programozási tévhitet. Más témák újdonságot jelenthetnek számodra; bízom benne, hogy ezek a részek hasznodra válnak majd. Ha képzett adatbázis-adminisztrátor vagy, lehetséges, hogy már megtanultad elkerülni a könyvben ismertetett SQL-programozás kelepcéit ez a könyv ebben az esetben is megismertethet a szoftverfejlesztők nézőpontjaival. Az adatbázis-adminisztrátorok és a szoftverfejlesztők viszonya gyakorta meglehetősen ellenséges, de a kölcsönös tisztelet és a csapatmunka eredményesebbé teheti a közös munkát. Ezt a könyvet arra is használhatjuk, hogy elmagyarázzuk a fejlesztőknek a helyes eljárásokat, és rávilágítsunk annak következményeire, ha eltérnek ezektől az utaktól. 8

1.2 Miről szól ez a könyv? De mit is jelent az, hogy antipattern? A szó egy olyan technikát jelöl, amelyet egy probléma megoldására szántak, de gyakran csak újabb problémákat generál. Az antipatterneket meglehetősen széles körben és sokféleképpen alkalmazzák, de mindig valamilyen általános célnak megfelelően. A programozók maguktól vagy egy kolléga, egy újságcikk vagy egy könyv segítségével is előállhatnak egy-egy olyan ötlettel, amelyet be lehet építeni egy antipatternbe. A Portland Pattern Repository honlapján egy csomó objektumorientált szoftverfejlesztéssel és projektmenedzseléssel kapcsolatos antipattern leírását megtalálhatjuk. További leírásokat találhatunk William J. Brown és társai könyvében, az AntiPatternsben [BMMM98]. Ez a könyv a leggyakrabban elkövetett SQL-es hibákról szól. Ezekkel akkor találkoztam, amikor technikai támogatással foglalkoztam, de jó néhánnyal összefutottam különböző továbbképzéseken, szoftverfejlesztések közben és internetes fórumokon is. Én is jó párat elkövettem: semmiből sem lehet többet tanulni, mint abból, amikor késő éjszaka órákon át próbálod kijavítani azokat a hibákat, amelyeket te magad követtél el. A könyv részei A könyvet az antipatternek négy alábbi kategóriájának megfelelően négy részre osztottam: A logikaiadatbázis-tervezés an pa ernjei Mielőtt nekiállnál kódolni, először is el kell döntened, hogy miféle információk tárolására szánod az adatbázist, és meg kell választanod az adatszervezés és az adatok közti kapcsolatok legjobb módját is. Ehhez hozzátartozik a táblák, oszlopok és kapcsolatok megtervezése is. A fizikaiadatbázis-tervezés an pa ernjei Miután már tudod, hogy milyen adatokat kell tárolnod, úgy kell a tárolást megvalósítanod, hogy a lehető legjobban kihasználd az adatbázis mögött lévő RDBMS-t. Ehhez hozzátartozik a táblák és az indexek definiálása, valamint az adattípusok megválasztása is. Ehhez az SQL adatdefiniáló nyelvét használod, például a CREATE TABLE parancsot. Lekérdezési an pa ernek Először is adatokra van szükségünk az adatbázishoz ezután jön az a rész, amikor lekérdezzük az adatot. Az SQL-lekérdezések adatmanipulációs nyelvet olyan parancsokat, mint a SELECT, UPDATE és DELETE használnak. Alkalmazásfejlesztési an pa ernek Az SQL-t más nyelvekben írott alkalmazásokban is szokás használni például C++-ban, Javában, PHP-ben, Pythonban vagy Rubyban. Az SQL-t lehet jól és rosszul is használni ezekben az alkalmazásokban a könyvnek ebben a részében néhány gyakori hibát ismertetek. Több fejezetnek humoros vagy kétértelmű címet adtam: valamiféle hagyománynak számít a patternek és az antipatternek esetében is a metaforikus vagy valamilyen más fogalomra utaló nevek használata. A függelékben néhány relációsadatbázis-elmélet gyakorlati leírását találhatjátok. Sok antipattern éppen az adatbázis-elmélettel kapcsolatos félreértéseken alapszik. 9

Az antipatternek anatómiája Minden fejezet az alábbi alfejezeteket tartalmazza: A cél Az a feladat, amelyet épp megpróbálnál megoldani. Az antipatterneket ennek a megoldására használnánk, de végső soron jóval több problémát okoznak, mint amennyit megoldanak. Az antipattern Ebben a részben ismertetem a bevett megoldást, valamint azt, hogy milyen nem várt következményekkel járhat az alkalmazása vagyis miért tekinthetjük antipatternnek. Hogyan ismerjük fel az antipatternt? Vannak bizonyos jelek, amelyek arra utalhatnak, hogy a munkád során egy antipatternt alkalmazol: egy-egy árulkodó akadály, esetleg valami, amit akár te mondasz, akár valaki más mond a dologgal kapcsolatban, lebuktathatja a rejtőzködő antipatternt. Az antipattern indokolt használata A legtöbb szabályhoz tartoznak kivételek is. Lehetségesek olyan körülmények, amelyek ismeretében egy általában antipatternnek tekintett megoldást is bátran alkalmazhatunk vagy legalábbis ez a legkisebb rossz, amit tehetünk. A megoldás Ebben a részben ismertetem az általam előnyben részesített megoldásokat, amelyek anélkül oldják meg a szóban forgó problémát, hogy az antipatternhasználat által okozott kényelmetlenségekkel kellene szembesülnünk. 1.3 Mi nem szerepel ebben a könyvben? Nem fogok leckéket adni az SQL-szintaxisról vagy a nyelv terminológiájáról: az alapokról már számtalan könyv és internetes forrás szól. Úgy tekintem, hogy az olvasó már ismeri annyira az SQL-szintaxist, hogy használni tudja a nyelvet, és meg tud vele oldani néhány problémát. A teljesítmény, a növekvő igényekhez való alkalmazkodás és az optimalizáció a legtöbb adatbázis-alapú alkalmazás fejlesztőjének fontos különösen, ha webes programról van szó. Több olyan könyv is megjelent, amelyek speciálisan az adatbázis-kezeléssel és a teljesítménnyel foglalkoznak jómagam az SQL Performance Tuning [GP03] és a High Performance MySQL [SZTZ08] második kiadását javasolnám ebben a témában. Ez a könyv is érint néhány olyan dolgot, amely fontos lehet a teljesítmény szempontjából, de nem ezt helyeztem a könyv középpontjába. Megpróbáltam olyan problémákat összegyűjteni, amelyek minden adatbázis-kezelő nyelvvel kapcsolatban felmerülhetnek, és ennek megfelelően olyan megoldásokat is igyekeztem javasolni, amelyek a legtöbb rendszeren belül működőképesek lehetnek. Az SQL megfelel az ANSI- és az ISO-szabványoknak ahogy a legtöbb adatbázis-kezelő nyelv is. Ha csak lehet, megpróbálom úgy körülírni a problémákat és a megoldásokat, hogy minden nyelvre és problémára alkalmasak lehessenek (emellett a továbbiakban igyekszem nyilvánvalóvá tenni, ha ez másképp lenne). 10

Az adat-hozzáférési keretrendszerek és objektumorientált leképezési könyvtárak hasznosnak bizonyulhatnak, de ezek sem tartoznak ennek a könyvnek a főbb témái közé. A legtöbb kódot PHP-ban írtam, olyan egyszerűen, ahogy csak tudtam: csak arra jók, hogy a legtöbb programozási nyelvben hasonlóan működnek. Az adatbázis-kezelés olyan kérdései, mint a szerver méretének eldöntése, az installálással és konfigurációval kapcsolatos problémák, a monitorozás, a mentések, a naplóelemzés és a biztonság fontos ügyek de erről egy külön könyvet is lehetne írni. Ezt a könyvet nem annyira a rendszergazdák számára írtam, mint az SQL-es adatbázis-fejlesztők számára, így erről itt nem is fogok sokat szólni. Ez a könyv az SQL-ről és a relációs adatbázisokról szól, nem pedig az objektumorientált adatbázisokról, a kulcs/érték párokról, az oszloporientált, a dokumentumorientált, a hierarchikus és hálós adatbázisokról. Ebben a könyben nem foglalkozom a map/reduce keretrendszerekkel és a szemantikus adattárolással sem. Az előbb felsorolt adattárolási módszerek előnyeinek és hátrányainak összahasonlítása és optimális felhasználásuk tárgyalása érdekes feladat lenne ugyan, de ez már túlmutatna ennek a könyvnek a keretein. 1.4 Konvenciók Az alábbiakban a könyvben használt konvenciókat ismertetem. Írásmód Az SQL-kulcsszavakat csupa nagybetűvel adtam meg, hogy jobban látszódjanak a szövegben lásd például a SELECT parancsot. A táblanevek minden szava nagybetűvel kezdődik mint pl. az Accounts vagy a BugsProducts neveknél. Az SQL-oszlopneveket kisbetűvel adtam meg, a névben szereplő szavakat pedig aláhúzással választottam el (például: account_name). A szövegliterálokat dőlt betűvel adtam meg, például bill@example.com. Terminológia Az adatbázisokkal kapcsolatosan az index szó alatt az adatbázis-kezelésben megszokott rendezett információhalmazt értjük. Az SQL-ben a lekérdezés és a programutasítás szavak jobbára felcserélhetőnek tűnnek ez a legtöbb komplett SQL-parancs esetében így is van. Az érthetőség kedvéért én a lekérdezést csak a SELECT parancsok esetében alkalmazom, a programutasítást pedig minden egyéb esetben (például UPDATE, INSERT, DELETE és az adatdefiniáló parancsok esetében is). Egyedkapcsolat-diagramok A relációs adatbázisok megtervezésének legelterjedtebb módja egy egyedkapcsolat-diagram készítése. A táblákat ebben az esetben dobozokba zárjuk, a kapcsolatokat pedig az őket összekötő vonalak jelképezik. A vonalak végén található jelölések tájékoztatnak bennünket a kapcsolatok típusáról (lásd például a könyv 1. ábráját, amely az egyedkapcsolat-diagramokat mutatja be a 7. oldalon). 11

1. ábra. Példák az egyedkapcsolat-diagramokra 1.5 Adatbázis példa A könyvben szereplő legtöbb problémát egy hipotetikus hibanyomkövető alkalmazáson keresztül szemléltetem. Az alkalmazás egyedkapcsolat-modellje a könyv 2. ábráján látható a 14. oldalon. Érdemes megfigyelni a Bugs és az Accounts táblázatok közötti három kapcsolódást: ezek három különböző idegen kulcsot jeleznek. Az alábbi kódból látszik, hogy miképpen definiálom a táblákat. Néhány esetben a könyv későbbi részeiben leírt esetek miatt választottam ezt vagy azt a megoldást, így ezek nem feltétlenül esnek egybe egy éles helyzetben alkalmazott kóddal. Leg- 12

többször megpróbálok a szabványos SQL-hez igazodni, így a példa használható különféle adatbázis-kezelő rendszerekben, de néha használok MySQL adattípusokat is ide tartozik például a SERIAL vagy a BIGINT. Introduction/setup.sql CREATE TABLE Accounts ( account_id SERIAL PRIMARY KEY, account_name VARCHAR(20), first_name VARCHAR(20), last_name VARCHAR(20), email VARCHAR(100), password_hash CHAR(64), portrait_image BLOB, hourly_rate NUMERIC(9,2) ); CREATE TABLE BugStatus ( status VARCHAR(20) PRIMARY KEY ); CREATE TABLE Bugs ( bug_id SERIAL PRIMARY KEY, date_reported DATE NOT NULL, summary VARCHAR(80), description VARCHAR(1000), resolution VARCHAR(1000), reported_by BIGINT UNSIGNED NOT NULL, assigned_to BIGINT UNSIGNED, verified_by BIGINT UNSIGNED, status VARCHAR(20) NOT NULL DEFAULT NEW, priority VARCHAR(20), hours NUMERIC(9,2), FOREIGN KEY (reported_by) REFERENCES Accounts(account_id), FOREIGN KEY (assigned_to) REFERENCES Accounts(account_id), FOREIGN KEY (verified_by) REFERENCES Accounts(account_id), FOREIGN KEY (status) REFERENCES BugStatus(status) ); CREATE TABLE Comments ( comment_id SERIAL PRIMARY KEY, bug_id BIGINT UNSIGNED NOT NULL, author BIGINT UNSIGNED NOT NULL, comment_date DATETIME NOT NULL, comment TEXT NOT NULL, FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id), FOREIGN KEY (author) REFERENCES Accounts(account_id) ); CREATE TABLE Screenshots ( bug_id BIGINT UNSIGNED NOT NULL, image_id BIGINT UNSIGNED NOT NULL, screenshot_image BLOB, caption VARCHAR(100), PRIMARY KEY (bug_id, image_id), FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id) ); CREATE TABLE Tags ( bug_id BIGINT UNSIGNED NOT NULL, tag VARCHAR(20) NOT NULL, PRIMARY KEY (bug_id, tag), FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id) ); 13

CREATE TABLE Products ( product_id SERIAL PRIMARY KEY, product_name VARCHAR(50) ); CREATE TABLE BugsProducts ( bug_id BIGINT UNSIGNED NOT NULL, product_id BIGINT UNSIGNED NOT NULL, PRIMARY KEY (bug_id, product_id), FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id), FOREIGN KEY (product_id) REFERENCES Products(product_id) ); 2. ábra. A példa-hibaadatbázis diagramja Néhány fejezetben, leginkább a logikai adatbázisokkal összefüggő antipatternek kapcsán, más definíciókat is alkalmazok vagy azért, hogy bemutassam az antipatternt, vagy pedig azért, hogy egy olyan megoldást mutassak be, amellyel elkerülhető az antipattern használata. 1.6 Köszönetnyilvánítás Legelőször is feleségemnek, Janenek nyilvánítanék köszönetet az ő szeretete, támogatása és inspirációja nélkül nem tudtam volna megírni ezt a könyvet, nem is említve, hogy mennyit nyaggatott, hogy munkára ösztönözzön. Szintén megköszönném kritikusaim munkáját is: rengeteg időt áldoztak rám. Az általuk tett javaslatok nagyban hozzájárultak ahhoz, hogy ez a könyv napvilágot lásson. Marcus Adams, Jeff Bean, Frederic Dadoud, Darby Felton, Arjen Lentz, Andy Lester, Chris Levesque, Mike Naberezny, Liz Nealy, Daev Roehr, Marco Romanini, Mark Schmidt, Gale Straney és Danny Thorpe is bábáskodtak a könyv megszületésekor köszönet érte. Köszönöm továbbá szerkesztőmnek, Jacquelyn Carternek és a Pragmatic Book-shelf kiadójának, akik értették, hogy miért is írom ezt a könyvet. 14

I. rész Logikai adatbázisokkal kapcsolatos antipatternek

Egy Netscape-programozó, akinek a nevét inkább elhallgatnám, egyszer átadott egy pointert a JavaScriptnek, sztringként tárolta, majd visszaadta a C-nek. Ezzel legalább harminc embernek okozott álmatlan éjszakákat. Blake Ross 2. FEJEZET Toronyiránt Tegyük föl azt kell megoldanod, hogy egy hibanyomkövető alkalmazásban egy felhasználót megjelölj elsődleges kapcsolattartóként egy termékhez. Az eredeti programban egy termékhez csak egyetlen felhasználót lehetett hozzárendelni, ennek ellenére nem ért különösebb meglepetésként, amikor megkaptad a feladatot, hogy ezentúl egy termékhez több felhasználót is meg lehessen adni. Első ránézésre elég egyszerű megoldásnak tűnt az adatbázis megváltoztatása úgy, hogy a felhasználók listáját ezentúl vesszőkkel elválasztva tároljuk, ahelyett, hogy csupán egyetlen azonosítót használnánk. Kisvártatva megjelenik a főnököd, és elújságolja, hogy a kollégák hibára akadtak: a mérnökséghez fölvettek néhány új embert, de legfeljebb csak ötöt tudnak bevezetni a rendszerbe, különben hibaüzenetet kapnak. Mi lehet a probléma? Bólogatsz, és felvilágosítod, hogy ez már csak így van legfeljebb ennyi embert tudsz egy-egy projekthez társítani. Mintha ennek így is kéne működnie. Mindenesetre úgy érzed, hogy a főnök szerint ennek nem így kellene működnie, és bővebb magyarázatra vágyik. Bele is fogsz: Hát, öt-tíz, esetleg tízegynéhány embert tudsz hozzájuk társítani, attól függ, hogy milyen régi a felhasználó azonosítója. A főnök felhúzza a szemöldökét. Folytatod a magyarázkodást: A felhasználók azonosítóját egy vesszőkkel elválasztott listában tárolom, de az azonosítóknak bele kell férniük egy adott hosszúságú sztringbe. Ha az azonosítók rövidek, több fér belőlük a sztringbe; a régi felhasználók pedig 99-nél kisebb azonosítóval rendelkeznek, vagyis rövidebbel, mint az újabbak. A főnök még mindig nem tűnik valami elégedettnek. Kezded úgy érezni, hogy ma nem fogsz egyhamar hazajutni. A programozók általában azért választják az előbb ismertetett megoldást, mert el szeretnék kerülni egy kapcsoló tábla létrehozását egy több a többhöz kapcsolatban. Ezt az antipatternt azért nevezem toronyiránti megoldásnak, mert a legfőbb célja az, hogy valahogy levágja az utat. 2.1 A cél: többértékű attribútumok tárolása Amikor egy tábla egy oszlopához csak egy érték tartozik, meglehetősen egyszerű a dolgunk: kiválaszthatunk egy SQL-es adattípust, mely az adott érték egyetlen példányának megfelel. Ez lehet egész, dátum vagy sztring is. De hogyan tárolhatjuk a kapcsolódó értékek halmazát egy oszlopban? 17

A már említett hibanyomkövető adatbázisunk esetében egy terméket egy egész oszlop használatával hozzárendelhetünk egy kapcsolattartóhoz a Products táblában. A felhasználókhoz több termék is tartozhat, illetve minden termékhez csak egyetlen felhasználó tartozik, így ebben az esetben egy több az egyhez kapcsolatról beszélhetünk a termékek és a felhasználók között. Jaywalking/obj/create.sql CREATE TABLE Products ( product_id SERIAL PRIMARY KEY, product_name VARCHAR(1000), account_id BIGINT UNSIGNED, --... FOREIGN KEY (account_id) REFERENCES Accounts(account_id) ); INSERT INTO Products (product_id, product_name, account_id) VALUES (DEFAULT, Visual TurboBuilder, 12); Idővel előfordulhat, hogy egyetlen termékhez adott esetben több kapcsolattartó is tartozik, így a több az egyhez kapcsolat mellett lehetővé kell tennünk az egy a többhöz kapcsolatot is a termékek és a felhasználók között. A Products tábla egy-egy sorához egynél több kapcsolattartó is tartozhat. 2.2 Az antipattern: vesszőkkel elválasztott listák használata Annak érdekében, hogy minél kevesebbet kelljen változtatni az adatbázis felépítésén, úgy határozol, hogy megváltoztatod az account_id oszlop adattípusát VAR- CHAR-ra. Így, ha vesszőkkel választod el őket, több felhasználói azonosítót is tárolhatsz a mezőben. Jaywalking/anti/create.sql CREATE TABLE Products ( product_id SERIAL PRIMARY KEY, product_name VARCHAR(1000), account_id VARCHAR(100), -- comma-separated list --... FOREIGN KEY (account_id) REFERENCES Accounts(account_id) ); INSERT INTO Products (product_id, product_name, account_id) VALUES (DEFAULT, Visual TurboBuilder, 12,34 ); Úgy néz ki, hogy az ötlet bevált: nem volt szükség új táblák és mezők létrehozására, csupán egyetlen mező adattípusának megváltoztatását kellett elvégezned. De érdemes egy pillantást vetnünk azokra az adatintegritási és teljesítménybeli problémákra, amelyeket ezzel a felépítéssel hoztunk létre. Egy adott felhasználóhoz tartozó összes termék lekérdezése A lekérdezések meglehetősen bonyolultak lehetnek, ha az idegen kulcsokat egyetlen mezőben szeretnénk tárolni. Ilyenkor már nem egyenlőségvizsgálattal dolgozunk, hanem egy szövegmintás keresést kell futtatnunk. MySQL-ben ez valahogy így néz ki, ha például a 12-es felhasználóhoz tartozó termékeket szeretnénk megtalálni: 18

Jaywalking/anti/regexp.sql SELECT * FROM Products WHERE account_id REGEXP [[:<:]]12[[:>:]] ; A mintának megfelelő kifejezésekkel előfordulhat, hogy hamis egyezéseket hoznak ki, és nem képesek indexeket használni. Mivel az efféle szintaxis minden adatbázis-kezelőnél másképp néz ki, az így készített kód nem lesz hordozható. Felhasználók lekérdezése egy adott termékhez Az előbbi esethez hasonlóan a vesszőkkel elválasztott lista használata akkor is szerencsétlen megoldás, ha megpróbáljuk összekapcsolni a hivatkozott tábla megfelelő sorával. Jaywalking/anti/regexp.sql SELECT * FROM Products AS p JOIN Accounts AS a ON p.account_id REGEXP [[:<:]] a.account_id [[:>:]] WHERE p.product_id = 123; Két tábla összekapcsolásakor egy ehhez hasonló kifejezés alkalmazása lehetetlenné teszi az indexek használatát. A lekérdezésnek mindkét táblán végig kell futnia, létre kell hoznia a keresztszorzatot, és minden sorkombinációra ki kell értékelnie a reguláris kifejezést. Összesítő lekérdezések Az összesítő lekérdezéseket függvények használatával hajthatjuk végre (például: COUNT(), SUM(), AVG()). Ezek a függvények viszont elsősorban arra alkalmasak, hogy sorokból képzett csoportokra alkalmazzuk őket, nem pedig vesszőkkel elválasztott listákra. Ez utóbbi esetben az alábbi kódban bemutatotthoz hasonló trükkre lesz szükségünk ahhoz, hogy működjön a dolog: Jaywalking/anti/count.sql SELECT product_id, LENGTH(account_id) - LENGTH(REPLACE(account_id,,, )) + 1 AS contacts_per_product FROM Products; Az ilyen megoldások gyakran elég ügyesen felépítettek, de sosem igazán átláthatók. Elég sokáig tart lekódolni őket, és a hibákat is nehéz utólag megtalálni bennük. Akadnak olyan összesítő lekérdezések is, amelyeket az ehhez hasonló vargabetűkkel sem lehet megoldani. Felhasználók frissítése egy adott termékhez A lista végéhez sztringösszefűzéssel hozzáadhatunk egy új azonosítót, de ez még nem garantálja, hogy a listánk rendezettsége változatlan marad. Jaywalking/anti/update.sql UPDATE Products SET account_id = account_id, 56 WHERE product_id = 123; A lista egy elemének törléséhez két SQL-utasítást kell futtatnunk: egyet, hogy lekérdezzük a régi listát, a másodikat pedig a frissített lista mentéséhez. 19