Practici proaste în proiectarea bazelor de date: faceți aceste greșeli?

Publicat: 2022-03-11

Ori de câte ori, în calitate de dezvoltator, ți se oferă o sarcină bazată pe codul existent, trebuie să faci față multor provocări. O astfel de provocare – cel mai adesea cea mai solicitantă – implică înțelegerea modelului de date al unei aplicații.

În mod normal, vă confruntați cu tabele, vizualizări, coloane, valori, proceduri stocate, funcții, constrângeri și declanșatoare confuze, care necesită mult timp pentru a avea sens pentru dvs. Și, odată ce o fac, începi să observi multe modalități de a îmbunătăți și de a profita de informațiile stocate.

Dacă sunteți un dezvoltator cu experiență, sunt șanse să observați și lucruri care ar fi putut fi făcute mai bine la început, adică defecte de design.

În acest articol, veți afla despre unele dintre practicile obișnuite de proiectare a bazelor de date, de ce sunt proaste și cum le puteți evita.

Proasta practică nr. 1: Ignorarea scopului datelor

Datele sunt stocate pentru a fi consumate ulterior, iar scopul este întotdeauna de a le stoca și de a le recupera în cel mai eficient mod. Pentru a realiza acest lucru, proiectantul bazei de date trebuie să știe dinainte ce vor reprezenta datele, cum vor fi achiziționate și cu ce ritm, care va fi volumul operațional al acesteia (adică, câte date sunt așteptate) și, în final , cum va fi folosit.

De exemplu, un sistem informatic industrial în care datele sunt colectate manual în fiecare zi nu va avea același model de date ca un sistem industrial în care informațiile sunt generate în timp real. De ce? Pentru că este foarte diferită gestionarea a câteva sute sau mii de înregistrări pe lună în comparație cu gestionarea a milioane de ele în aceeași perioadă. Considerații speciale trebuie făcute de către proiectanți pentru a menține eficiența și utilitatea bazei de date, dacă volumele de date vor fi mari.

Dar, desigur, volumul de date nu este singurul aspect de luat în considerare, deoarece scopul datelor afectează și nivelul de normalizare, structura datelor, dimensiunea înregistrării și implementarea generală a întregului sistem.

Prin urmare, cunoașterea temeinică a scopului sistemului de date pe care îl veți crea duce la considerații în alegerea motorului bazei de date, entitățile de proiectat, dimensiunea și formatul înregistrării și politicile de gestionare a motorului bazei de date.

Ignorarea acestor obiective va duce la proiecte care sunt defecte în ceea ce privește elementele de bază, deși corecte din punct de vedere structural și matematic.

Practica proastă nr. 2: Normalizare slabă

Proiectarea unei baze de date nu este o sarcină deterministă; doi designeri de baze de date pot urma toate regulile și principiile de normalizare pentru o anumită problemă și, în cele mai multe cazuri, vor genera aspecte diferite de date. Acest lucru este inerent naturii creative a ingineriei software. Cu toate acestea, există câteva tehnici de analiză care au sens în fiecare caz și să le urmați este cea mai bună modalitate de a ajunge la o bază de date care are performanțe optime.

Imagine a unui set de date care duce la două aspecte diferite

În ciuda acestui fapt, ne confruntăm adesea cu baze de date care au fost concepute din mers fără a respecta cele mai elementare reguli de normalizare. Trebuie să fim clari cu privire la asta: fiecare bază de date ar trebui, cel puțin, să fie normalizată la a treia formă normală, deoarece aspectul este cel care va reprezenta cel mai bine entitățile tale și a cărui performanță va fi cel mai bine echilibrată între interogarea și inserarea-actualizarea-ștergerea înregistrărilor. .

Dacă vă împiedicați de mese care nu respectă 3NF, 2NF sau chiar 1NF, luați în considerare reproiectarea acestor mese. Efortul pe care îl investiți în acest sens va da roade pe termen foarte scurt.

Proasta practică nr. 3: Redundanță

Foarte legat de punctul anterior, deoarece unul dintre scopurile normalizării este reducerea acesteia, redundanța este o altă practică proastă care apare destul de des.

Câmpurile și tabelele redundante sunt un coșmar pentru dezvoltatori, deoarece necesită o logică de afaceri pentru a menține la zi multe versiuni ale aceleiași informații. Aceasta este o suprasolicitare care poate fi evitată dacă regulile de normalizare sunt respectate cu atenție. Deși uneori redundanța poate părea necesară, ea trebuie utilizată numai în cazuri foarte specifice și să fie documentată în mod clar pentru a fi luată în considerare în evoluțiile viitoare.

Efectele negative tipice ale redundanței sunt o creștere inutilă a dimensiunii bazei de date, datele fiind predispuse la inconsecvență și scăderea eficienței bazei de date, dar – mai important – poate duce la coruperea datelor.

Practică proastă nr. 4: Integritate referenţială proastă (Constrângeri)

Integritatea referenţială este unul dintre cele mai valoroase instrumente pe care le oferă motoarele de baze de date pentru a menţine calitatea datelor la cea mai bună calitate. Dacă nu sunt implementate constrângeri sau foarte puține constrângeri încă din etapa de proiectare, integritatea datelor va trebui să se bazeze în întregime pe logica de afaceri, făcându-l susceptibil la eroarea umană.

Practică proastă nr. 5: Nu profitați de caracteristicile motorului DB

Când utilizați un motor de baze de date (DBE), aveți un software puternic pentru sarcinile dvs. de prelucrare a datelor, care va simplifica dezvoltarea software-ului și va garanta că informațiile sunt întotdeauna corecte, sigure și utilizabile. Un DBE oferă servicii precum:

  • Vizualizări care oferă o modalitate rapidă și eficientă de a vă analiza datele, de obicei denormalizându-le în scopuri de interogare fără a pierde corectitudinea datelor.
  • Indecși care ajută la accelerarea interogărilor pe tabele.
  • Funcții agregate care ajută la analiza informațiilor fără programare.
  • Tranzacții sau blocuri de propoziții care modifică datele, care sunt toate executate și comise sau anulate (retrocedate) dacă apare ceva neașteptat, păstrând astfel informațiile într-o stare perpetuă corectă.
  • Blocări care păstrează datele în siguranță și corecte în timp ce tranzacțiile sunt executate.
  • Proceduri stocate care oferă caracteristici de programare pentru a permite sarcini complexe de gestionare a datelor.
  • Funcții care permit calcule sofisticate și transformări de date.
  • Constrângeri care ajută la garantarea corectitudinii datelor și la evitarea erorilor.
  • Declanșatoare care ajută la automatizarea acțiunilor atunci când apar evenimente pe date.
  • Optimizator de comandă (planificator de execuție) care rulează sub capotă, asigurându-se că fiecare propoziție este executată la cel mai bun mod și păstrând planurile de execuție pentru ocazii viitoare. Acesta este unul dintre cele mai bune motive pentru a utiliza vizualizări, proceduri stocate și funcții, deoarece planurile lor de execuție sunt păstrate permanent în DBE.

Necunoașterea sau ignorarea acestor capacități va duce dezvoltarea pe o cale extrem de incertă și cu siguranță la bug-uri și probleme viitoare.

Practică proastă nr. 6: Chei primare compuse

Acesta este un fel de un punct controversat, deoarece mulți designeri de baze de date vorbesc în zilele noastre despre utilizarea unui câmp generat automat de ID întreg ca cheie primară în loc de una compusă definită prin combinația a două sau mai multe câmpuri. În prezent, aceasta este definită drept „cea mai bună practică” și, personal, tind să fiu de acord cu ea.

Imaginea unei chei primare compuse

Cu toate acestea, aceasta este doar o convenție și, desigur, DBE-urile permit definirea cheilor primare compozite, despre care mulți designeri consideră că sunt inevitabile. Prin urmare, ca și în cazul redundanței, cheile primare compozite sunt o decizie de proiectare.

Atenție, totuși, dacă tabelul cu o cheie primară compusă este de așteptat să aibă milioane de rânduri, indexul care controlează cheia compozită poate crește până la un punct în care performanța operațiunii CRUD este foarte degradată. În acest caz, este mult mai bine să folosiți o cheie primară simplă cu ID întreg, al cărei index va fi suficient de compact și va stabili constrângerile DBE necesare pentru a menține unicitatea.

Practică proastă nr. 7: Indexare slabă

Uneori, veți avea un tabel pe care trebuie să îl interogați după mai multe coloane. Pe măsură ce tabelul crește, veți observa că SELECT-urile de pe aceste coloane încetinesc. Dacă tabelul este suficient de mare, te vei gândi, în mod logic, să creezi un index pe fiecare coloană pe care o folosești pentru a accesa acest tabel doar pentru a descoperi aproape imediat că performanța SELECT-urilor se îmbunătățește, dar INSERT-urile, UPDATE-urile și DELETE-urile scad. Acest lucru, desigur, se datorează faptului că indicii trebuie menținuți sincronizați cu tabelul, ceea ce înseamnă o suprasarcină masivă pentru DBE. Acesta este un caz tipic de supraindexare pe care îl puteți rezolva în mai multe moduri; de exemplu, având un singur index pe toate coloanele diferit de cheia primară pe care o utilizați pentru a interoga tabelul, ordonarea acestor coloane de la cel mai folosit la cel mai puțin poate oferi performanțe mai bune în toate operațiunile CRUD decât un index pe coloană.

Pe de altă parte, a avea un tabel fără index pe coloanele care sunt folosite pentru a interoga, după cum știm cu toții, va duce la performanțe slabe pe SELECT-uri.

De asemenea, eficiența indicelui depinde uneori de tipul coloanei; indecșii de pe coloanele INT arată cea mai bună performanță posibilă, dar indicii de pe VARCHAR, DATE sau DECIMAL (dacă are vreodată sens) nu sunt la fel de eficienți. Această considerație poate duce chiar la reproiectarea tabelelor care trebuie accesate cu cea mai bună eficiență posibilă.

Prin urmare, indexarea este întotdeauna o decizie delicată, deoarece prea multă indexare poate fi la fel de proastă ca și prea puțină și pentru că tipul de date al coloanelor pe care trebuie să le indexeze au o mare influență asupra rezultatului final.

Practica proastă nr. 8: Convenții de numire slabe

Acesta este ceva cu care programatorii se luptă mereu când se confruntă cu o bază de date existentă: înțelegerea informațiilor stocate în ea după numele de tabele și coloane, deoarece, de multe ori, nu există altă cale.

Numele tabelului trebuie să descrie ce entitate deține și fiecare nume de coloană trebuie să descrie ce informație reprezintă. Acest lucru este ușor, dar începe să fie complicat atunci când tabelele trebuie să se relaționeze între ele. Numele încep să devină dezordonate și, mai rău, dacă există convenții de denumire confuze cu norme ilogice (cum ar fi, de exemplu, „numele coloanei trebuie să aibă 8 caractere sau mai puțin”). Consecința finală este că baza de date devine ilizibilă.

Prin urmare, o convenție de denumire este întotdeauna necesară dacă se așteaptă ca baza de date să dureze și să evolueze odată cu aplicația pe care o acceptă și iată câteva îndrumări pentru a stabili una succint, simplu și lizibil:

  • Fără limitări privind dimensiunea numelui tabelului sau coloanei. Este mai bine să ai un nume descriptiv decât un acronim pe care nimeni nu-și amintește sau nu-l înțelege.
  • Numele care sunt egale au același sens. Evitați să aveți câmpuri care au același nume, dar cu tipuri sau semnificații diferite; acest lucru va fi confuz mai devreme sau mai târziu.
  • Dacă nu este necesar, nu fi redundant. De exemplu, în tabelul „Articol”, nu este necesar să aveți coloane precum „NumeArticol”, „PrețOferăItem” sau nume similare; „Nume” și „Preț” sunt suficiente.
  • Atenție la cuvintele rezervate DBE. Dacă o coloană urmează să fie numită „Index”, care este un cuvânt rezervat SQL, încercați să utilizați unul diferit, cum ar fi „IndexNumber”.
  • Dacă respectați regula cheii primare simple (un singur întreg generat automat), numiți-o „Id” în fiecare tabel.
  • Dacă vă alăturați unui alt tabel, definiți cheia străină necesară ca un număr întreg, numit „Id” urmat de numele tabelului asociat (de exemplu, IdItem).
  • Dacă numiți constrângeri, utilizați un prefix care descrie constrângerea (de exemplu, „PK” sau „FK”), urmat de numele tabelului sau tabelelor implicate. Desigur, folosirea liniuțelor de subliniere („_”) cu ușurință ajută la ca lucrurile să fie mai lizibile.
  • Pentru a denumi indexurile, utilizați prefixul „IDX” urmat de numele tabelului și coloana sau coloanele indexului. De asemenea, utilizați „UNIQUE” ca prefix sau sufix dacă indexul este unic și subliniază acolo unde este necesar.

Există multe linii directoare de denumire a bazelor de date pe internet care vor aduce mai multă lumină asupra acestui aspect foarte important al designului bazei de date, dar cu acestea de bază, puteți ajunge cel puțin la o bază de date care poate fi citită. Ceea ce este important aici nu este dimensiunea sau complexitatea regulilor de denumire, ci consecvența în a le urma!

Câteva observații finale

Designul bazei de date este o combinație de cunoștințe și experiență; industria software-ului a evoluat mult de la începuturile sale. Din fericire, există suficiente cunoștințe disponibile pentru a ajuta designerii de baze de date să obțină cele mai bune rezultate.

Există linii directoare bune pentru proiectarea bazelor de date pe tot internetul, precum și practici proaste și lucruri de evitat în proiectarea bazelor de date. Doar alegeți și rămâneți de el.

Și, nu uita, doar prin experimentare, greșeli și succese înveți, așa că mergi mai departe și începe acum.