Ce formă de organizare a datelor este utilizată în relațional. Caracteristicile generale ale lucrului cu RDB. Baza de date relațională - Concepte de bază

Nivelul 1: Nivel modele externe- acesta este cel mai mult nivel superior unde fiecare model are propria sa vedere asupra datelor. Acest strat definește punctul de vedere al bazei de date a aplicațiilor individuale.

Nivel conceptual: Legătura centrală de control, unde baza de date este prezentată cel mai mult vedere generala, care combină datele utilizate de toate aplicațiile. De fapt, nivelul conceptual reflectă un model generalizat al disciplinei.

Strat fizic(Bază de date): Acestea sunt datele în sine aflate în fișiere sau în structuri de pagină situate pe medii de stocare externe.


Modele de date

Se disting următoarele modele de date:

1. Infologic

2. Data logică

3. Fizic

Procesul de proiectare a bazei de date începe cu proiectarea unui model de informații. Un model de date infologice este o descriere informală generalizată a bazei de date create, realizată folosind limbajul natural, formule matematice, tabele, grafice și alte instrumente care sunt ușor de înțeles pentru toți oamenii care lucrează la proiectarea bazelor de date.

Tuplu de domeniu

Modelul informațional reflectă lumea reală într-un concept ușor de înțeles de om, complet independent de mediul de stocare a datelor. Prin urmare, modelul de infologie nu ar trebui să se schimbe până când unele schimbări în lumea reală necesită o schimbare în afara definiției, astfel încât modelul să continue să reprezinte domeniul.

Există multe abordări pentru construirea acestui model: modele grafice, rețele semantice, conexiune-entitate și altele.

Model datalogic

Modelul infologic trebuie să fie afișat într-un model datalogic care să fie înțeles de SGBD. Un model datalogic este o descriere formală a unui model de informații în limbajul DBMS.

Model ierarhic

Acest model este o colecție de elemente înrudite care formează o structură ierarhică. Conceptele de bază ale ierarhiei includ nivelul, nodul și relația.

nivelul de comunicare


Un nod este o colecție de atribute de date care descriu un obiect. Fiecare nod este conectat la un nod la un nivel superior și la orice număr de noduri la un nivel inferior. Excepția este nodul de cel mai înalt nivel. Numărul de arbori din baza de date este determinat de numărul de rădăcini ale copacilor. Fiecare înregistrare a bazei de date are o singură cale de la înregistrarea rădăcină. Un exemplu simplu este sistemul de nume de domeniu de Internet\adresă. Pe primul nivel (rădăcina copacului) se află planeta noastră, pe al doilea Țara, pe al treilea Regiunea, pe al patrulea - așezarea, strada, casa, apartamentul. Un reprezentant tipic este un DBMS de la IBM - IMS.

Toate copiile de acest tip descendenții cu o instanță comună de tipul strămoșului se numesc gemeni. O ordine de parcurgere completă este definită pentru baza de date. De sus în jos și de la dreapta la stânga.

Modelul fizic

Un model fizic este construit pe baza modelului datalogic. Organizarea fizică a datelor are un impact major asupra performanței bazei de date. Dezvoltatorii DBMS încearcă să creeze cele mai productive modele de date fizice, oferind utilizatorilor unul sau altul instrument pentru a personaliza modelul pentru o anumită bază de date.

Exemplu: În special pentru o bază de date relațională, aceasta ia deja în considerare:

1. Aspecte fizice ale stocării tabelelor în fișiere specifice.

2. Crearea de indici care optimizează viteza operațiunilor de date folosind aplicația.

3. Executarea diverse actiuni peste date la anumite evenimente definite de utilizatori folosind declanșatoare și proceduri stocate.

Modele infologice X

Modele fizice


Pentru toate nivelurile și pentru orice metodă de reprezentare a disciplinei, există o codificare a conceptelor de relații între concepte. Un pas cheie în dezvoltarea oricărui Sistem informatic este de a efectua o analiză a sistemului:

Formalizarea disciplinei și reprezentarea sistemului ca ansamblu de componente.

Compoziția ca bază a analizei sistemului poate fi funcțională (construirea unei ierarhii).

Cu toate acestea, în majoritatea sistemelor, când vine vorba de baze de date, tipurile de date sunt un element mai static decât modul în care sunt procesate. Prin urmare, metode de analiză a sistemului, cum ar fi diagrama fluxului de date, au primit o dezvoltare intensivă. Dezvoltarea bazelor de date relaționale. A stimulat dezvoltarea metodologiilor de dezvoltare a datelor, în special diagramele ER ER. Modelul de date relațional folosește în mod direct conceptul de relație ca o mapare. Ea este cea mai apropiată de model conceptual prezentarea datelor. Și adesea se află în centrul acesteia.

Spre deosebire de teoreticianul modelului de graf, în modelul relațional, conexiunile dintre relații sunt implementate într-un mod neexplicit, pentru care se folosesc chei de relație. De exemplu, relațiile de tip ierarhic sunt implementate prin mecanismul cheilor primare și străine, când faptul de atribute trebuie să fie prezent în relația de subordonare.

Un astfel de atribut al relațiilor din relația principală va fi numit o cheie primară, iar într-o relație subordonată una secundară.

Progresul în dezvoltarea limbajelor de programare asociate în primul rând cu tastarea datelor și apariția limbajelor orientate pe obiecte a făcut posibilă abordarea analizei sistemelor complexe din punctul de vedere al reprezentărilor ierarhice, adică folosind clase de obiecte cu proprietăți de polimorfism, moștenire și încapsulare.

RELAȚIA ESTE O TABELĂ.

Editarea tabelelor, înregistrărilor...

Ștergerea a ceea ce ați creat și

Editare.


Modelul bazei de date relaționale

Modelele de date relaționale au câștigat în prezent cea mai mare popularitate tocmai pentru această reprezentare a datelor.

Modelul relațional poate fi gândit ca o metodă specială de reprezentare a datelor care conține propriile date (sub formă de tabele) și modalități de lucru și manipulare a acestora (sub formă de relații). Modelul relațional presupune trei elemente conceptuale: Structură, Integritate și Procesarea datelor. Aceste elemente au propriile lor concepte obligatorii care trebuie explicate pentru prezentare ulterioară.

Tabelul este considerat ca un depozit de date direct. În mod tradițional în sisteme relaționale se numește masa atitudine. Se numește un rând de tabel caravană, și coloana atribut. În acest caz, atributele au nume unice (în cadrul relației).

Numărul de tupluri dintr-un tabel este numit numar cardinal. Numărul de atribute grad. Se stabilește un identificator unic pentru o relație, adică unul sau mai multe atribute ale căror valori nu sunt aceleași în același timp - identificatorul se numește cheie primară.Domeniu acesta este setul de valori omogene valide pentru un anumit atribut. Astfel, un domeniu poate fi considerat ca un set de date numit, iar componentele acestui set sunt unități indivizibile din punct de vedere logic (de exemplu, o listă de nume de angajați ai unei instituții poate acționa ca un domeniu, dar nu toate numele pot fi prezente in masa).

SUMĂ Kireeva 25.50 Motyleva 17.05 … …. …

Atitudine

atribute

Câmpurile KOD, NAME, SUMM sunt atribute de tabel conținute în antet.

Perechile KOD 5216, NAME Kireeva, SUMM 25.50 sunt elemente ale corpului relației.

În bazele de date relaționale, spre deosebire de alte modele, utilizatorul specifică ce date este nevoie pentru el și nu cum să o facă. Din acest motiv, procesul de mutare și navigare a unei baze de date în sisteme relaționale este automat, iar această sarcină este efectuată într-un SGBD optimizator. Treaba lui este să profite la maximum mod eficient preluarea datelor din baza de date la cerere. Astfel, optimizatorul trebuie să fie cel puțin capabil să determine din ce tabele sunt selectate datele, câte informații sunt în aceste tabele și care este ordinea fizică a înregistrărilor din tabele și cum sunt grupate.

În plus, o bază de date relațională îndeplinește și funcții de director. Directorul stochează o descriere a tuturor obiectelor care alcătuiesc baza de date: tabele, indecși, declanșatoare etc. Evident, o componentă precum optimizatorul este vitală pentru buna funcționare a întregului sistem. Optimizatorul folosește informațiile stocate în director. Un fapt interesant este că catalogul în sine este un set de tabele, astfel încât SGBD-ul îl poate manipula în moduri tradiționale, fără a recurge la vreo tehnici sau metode speciale.

Domenii și relații

Definiții de bază: Domenii, tipuri de relații, predicate.

Relațiile au o serie de proprietăți de bază:

1. În cel mai general caz, nu există tuple comune în relații - acest lucru rezultă din însăși definiția relațiilor. Cu toate acestea, pentru unele SGBD-uri, în unele cazuri sunt permise abateri de la această proprietate. Atâta timp cât există o cheie primară în relație, tuplurile identice sunt excluse.

2. Tuplurile nu sunt ordonate de sus în jos - pur și simplu nu există un concept de număr pozițional într-o relație. În relații, fără a pierde informații, puteți aranja cu succes tupluri în orice ordine.

3. Atributele nu sunt ordonate de la stânga la dreapta. Atributele din antetul relației pot fi aranjate în orice ordine fără a compromite integritatea datelor. Prin urmare, nici conceptul de număr pozițional în raport cu un atribut nu există.

4. Valorile atributelor constau din unități logic indivizibile - acest lucru rezultă din faptul că valorile sunt preluate din domenii, în caz contrar, putem spune că relațiile nu conțin grupuri de repetiție; Adică sunt normalizate.

Sistemele relaționale suportă mai multe tipuri de relații:

1. Cele numite sunt relații variabile definite în SGBD de către operatorii de creație și, de regulă, necesare pentru o prezentare mai convenabilă a informațiilor pentru utilizator.

2. Relațiile de bază sunt o parte direct importantă a bazei de date, astfel încât în ​​timpul proiectării le este dat propriul nume.

3. O relație derivată este una care a fost definită prin alte relații, de obicei de bază, folosind instrumente DBMS.

4. Această reprezentare este de fapt o relație numită derivată, iar reprezentarea este exprimată exclusiv prin operatori DBMS aplicați relațiilor numite, deci nu există fizic în baza de date.

5. Rezultatul interogărilor este o relație derivată fără nume care conține date (rezultatul unei anumite interogări). Rezultatul nu este stocat în baza de date, dar există atâta timp cât utilizatorul are nevoie de el.

6. O relație stocată este una care este menținută fizic în memoria relațiilor stocate cel mai adesea includ baza relațiilor; Pe baza celor de mai sus, putem defini o bază de date relațională ca un set de relații interconectate.


O conexiune în acest caz este asocierea a două sau mai multe relații.

KOD ADRES
1 1 O relație unu-la-mulți este aceea că la un moment dat fiecărui element (tuplu A) îi corespunde mai multe elemente ale tuplurilor B
∞ Conexiune binară
Elevi
Profesori
Orarul cursurilor

Elevi

Conexiuni ternare


Integritatea datelor

În modelele relaționale, problemei integrității datelor i se acordă un loc special. Amintiți-vă că o cheie sau o cheie potențială este un set minim de atribute ale căror valori pot fi folosite pentru a găsi în mod unic tuplul necesar înseamnă că excluderea oricărui atribut din set nu permite identificarea tuplului prin atributele rămase;

Fiecare relație are cel puțin o cheie posibilă. Una dintre ele este luată ca cheie primară.

Atunci când alegeți o cheie primară, ar trebui să se acorde preferință cheilor non-compozite sau cheilor formate dintr-un set minim de atribute. De asemenea, nu este de dorit să folosiți chei cu valori de text lungi (este de preferat să folosiți atribute întregi ca chei). Deci, pentru a identifica un angajat, puteți utiliza fie un număr unic de personal, fie un număr de pașaport, fie un set de nume de familie, nume de mijloc și numere de departament. Nu este permis ca cheia primară a unei relații, adică orice atribut care participă la cheia primară, să ia valori nedefinite. În acest caz, va apărea o situație contradictorie ( coliziune): Apare un element cheie primară neunică. Prin urmare, acest lucru ar trebui monitorizat cu atenție atunci când proiectați o bază de date.

Despre cheile externe. Este de remarcat faptul că, deoarece relația C conectează relațiile B și A, trebuie să includă chei străine corespunzătoare cheilor primare ale relațiilor A și B.

Cheia externă a unui tabel este formată folosind mai multe chei primare ale altor tabele.

Astfel, atunci când luăm în considerare problema alegerii unei metode de conectare a unei relații într-o bază de date, se pune întrebarea care ar trebui să fie cheile străine. În același timp, pentru fiecare cheie străină este necesar să se rezolve problema asociată cu posibilitatea (sau imposibilitatea) apariției unor valori nedefinite în cheile străine (NULL - valori - valoare de atribut pentru informațiile lipsă). Cu alte cuvinte, poate exista un tuplu într-o relație pentru care tuplu în relațiile sale asociate nu este cunoscut?

Pe de altă parte, este necesar să ne gândim în avans la ceea ce se va întâmpla atunci când eliminați tuplurile dintr-o relație la care face referire o cheie străină. Există următoarele posibilități posibile:

· Operațiune cascade– adică ștergerea tuplurilor din relații duce la ștergerea tuplurilor asociate relației. De exemplu, ștergerea informațiilor despre nume, prenume etc. angajatul într-o privință duce la ștergerea salariului în altă privință;

· Operațiune limitat - adică numai acele tupluri pentru care nu există alte informații asociate sunt eliminate. Nu toate informațiile sunt șterse (nu în toate privințele), deoarece acestea pot fi utilizate și în altă privință, eliminarea informațiilor în care duce la o încălcare a integrității datelor. Dacă astfel de informații sunt disponibile, ștergerea nu poate fi efectuată, de exemplu, ștergerea informațiilor despre prenume, prenume etc. angajatul este posibil numai dacă nu există informații legate de salariul său.

Este necesar să oferiți tehnologie pentru ceea ce se va întâmpla atunci când încercați să actualizați cheia primară a unei relații la care se face referire printr-o cheie străină. Aici aveți aceleași opțiuni ca atunci când ștergeți:

· Operația este în cascadă, adică atunci când cheia primară este actualizată, cheia externă din relația aferentă este actualizată. De exemplu, actualizarea cheii primare în relația în care sunt stocate informații despre angajați duce la o actualizare a cheii străine în relația care conține informații despre salariu.

· Operația se limitează la actualizarea doar a acelor chei primare pentru care altfel nu există informații asociate. Dacă astfel de informații sunt disponibile, actualizarea nu poate fi făcută. De exemplu, actualizarea cheii primare într-o relație în care sunt stocate informații despre un angajat este posibilă numai dacă informațiile despre salariul său lipsesc în relația aferentă.1


Algebră relațională

Baza formală a modelului bazei de date relaționale este algebra relațională, bazată pe teoria mulțimilor și considerând operator special peste relații și calcul relațional bazat pe logica matematică.

Muncă

A A A B B C A Y D
G D
A
A B C A Y D F F W

Trebuie remarcat faptul că algebra relațională are o mare putere - interogări complexe la baza de date poate fi exprimată folosind o singură expresie. Din acest motiv, aceste mecanisme sunt incluse în modelul de date relaționale. Orice interogare exprimată folosind o expresie de algebră relațională sau o formulă de calcul relațional poate fi exprimată folosind un operator în acest limbaj.

Algebra relațională are o proprietate importantă - este închisă în raport cu conceptul de relație. Aceasta înseamnă că expresia algebră relațională este efectuată pe relații baze de date relaționale datele și rezultatele calculului lor reprezintă, de asemenea, relații.

Ideea principală a algebrei relaționale este că mijloacele de manipulare a relațiilor considerate ca un set se bazează pe operații multiple tradiționale completate de unele operații specifice bazei de date.

Să descriem versiunea de algebră care a fost propusă de CODD. Operațiunea constă din 8 operatori principali:

Preluare relație (operație unară)

Proiecția relației (operație unară)

· Fuziunea relațiilor

· Intersecția relațiilor (operație binară)

· Scăderea rapoartelor

Produsul relațiilor

· Relații de legătură

· Împărțirea relațiilor

Aceste operațiuni pot fi explicate după cum urmează:

· Rezultatul selectării unei relații bazate pe o anumită condiție este o relație care include doar acele tupluri ale relației originale care îndeplinesc această condiție.

· La proiectarea unei relații pe un set dat de atribute ale acesteia, se va obține o relație ale cărei tupluri sunt luate din tuplurile corespunzătoare primei relații.

· La efectuarea operației de îmbinare a două relații se va obține o relație care include toate tuplurile incluse în cel puțin una dintre relațiile care participă la operație.

· La efectuarea operației de intersecție a două relații se va obține o relație care include toate tuplurile incluse în ambele relații inițiale.

· La efectuarea operației de scădere a două relații se va obține o relație care include toate tuplurile incluse în prima relație, cu excepția celor care sunt incluse și în a doua relație.

· La efectuarea produsului direct al două relaţii se obţine o relaţie ale cărei tupluri sunt o combinaţie a tuplurilor primei şi celei de-a doua relaţii.

· Când două relații sunt conectate în funcție de o anumită condiție, se formează o relație rezultată de tupluri ale căror tupluri sunt o combinație de tupluri ale primei și celei de-a doua relații care îndeplinesc această condiție.

· Operația de împărțire relațională are doi operanzi – o relație binară (formată din două atribute) și o relație unară (formată dintr-un atribut). Rezultatul operației este o relație constând din tupluri, inclusiv relația primului atribut de tupluri din prima relație și astfel încât setul de valori al celui de-al doilea atribut să coincidă cu setul de valori al celui de-al doilea atribut. .

Pe lângă cele de mai sus, există o serie de operațiuni speciale specifice lucrului cu baze de date:

· Ca rezultat al operației de redenumire, o relație este un set de tupluri care coincide cu corpul relației originale, dar numele atributelor au fost schimbate.

Rezultă că rezultatul unei operații relaționale este o anumită relație este posibil să se formeze expresii relaționale în care, în loc de relația originală (operand), se va folosi o expresie relațională încorporată. Acest lucru se datorează faptului că operațiile algebrei relaționale sunt cu adevărat închise conceptului de relație. Să începem cu operația unificarea relaţiilor, cu toate acestea, aceasta este în in aceeasi masura se aplică și operațiilor de intersecție și combinare, adică în algebra relațională, rezultatul operației de unire este o relație. Dacă presupunem în algebra relaţională posibilitatea asociațiile arbitrare două relații cu seturi diferite de atribute, atunci rezultatul unei astfel de operații va fi o mulțime, dar un set de tupluri de diferite tipuri, adică, în general, nu o relație. Dacă pornim de la cerința ca algebra relațională să fie închisă în raport cu conceptul de relație, atunci o astfel de operație asociațiile este lipsit de sens. Aceasta duce la apariția conceptului compatibilitatea relațiilor De unificare: două relații sunt compatibile doar dacă au cu aceleași rubrici, adică are același set de nume de atribute, iar atributele cu același nume sunt definite în același domeniu.

Cu condiția ca două relații să fie compatibile în unirea lor, atunci când operația de unire, intersecție și scădere este efectuată în mod normal asupra lor, rezultatul operației este o relație cu un antet corect definit care se potrivește cu antetul fiecăruia dintre relațiile operandului. Dacă două relații nu sunt pe deplin compatibile cu îmbinarea, adică compatibile în toate, cu excepția numelor de atribute, atunci înainte de a efectua o operație de tip de îmbinare, aceste relații pot fi făcute compatibile pe deplin cu îmbinarea prin aplicarea unei operații de redenumire.

Funcționarea produsului direct al două relații ridică noi probleme. În teoria mulţimilor, produsul direct poate fi obţinut pentru orice mulţime. Elementele setului rezultat vor fi perechi formate din elemente ale primului și celui de-al doilea set. Deoarece relațiile sunt mulțimi, pentru oricare două relații este posibil să se obțină un produs direct. Cu toate acestea, rezultatul nu va fi o relație. Elementele rezultatului nu vor fi tupluri, ci perechi de tupluri. Prin urmare, în algebra relațională, se utilizează o formă specială a operației de luare a unui produs direct - produsul direct extins al relațiilor. Atunci când se ia produsul direct extins a două relații, elementul relației rezultate este un tuplu format prin fuzionarea unui tuplu din prima relație și un tuplu din a doua relație. Imediat apare o a doua problemă legată de obținerea unui antet corect format al relației rezultate, aceasta duce la necesitatea introducerii conceptului de compatibilitate relațională prin luarea unui produs direct extins.

Două relații sunt compatibile prin luarea unui produs direct numai dacă setul de nume de atribute ale acestor relații nu se intersectează. Orice două relații pot fi convertite într-o formă de produs direct compatibil, aplicând o operație de redenumire uneia dintre relații.

Operația de preluare necesită două relații: o relație inițială, operandul și o condiție simplă de constrângere. În urma operației de selecție, se produce o relație al cărei cap coincide cu antetul relației de operand, iar corpul include acele tuple ale relației de operand care satisfac valorile condiției de constrângere.

Să introducem un număr de operatori.

Fie unire să însemne operația de unire, intersectare – operația de intersecție, minus – operația de scădere. Pentru a desemna operația de eșantionare, vom folosi construcția A unde B, unde A este relația operandului și B este o condiție simplă de comparație. Fie C1 și C2 două condiții simple de eșantionare

A unde C1 ȘI C2 este identic (A unde C1) se intersectează (A unde C2)

A unde C1 SAU C2 este identică cu (A unde C1) uniunea (A unde C2)

A unde C1 nu C2 este identic cu (A unde C1) minus (A unde C2)

Folosind aceste definiții, este posibilă implementarea operațiunilor de eșantionare în care condiția de eșantionare este o expresie logică arbitrară compusă din condiții simple folosind conexiuni logice (și, sau, nu). Operația de preluare a proiecțiilor relației A pe lista de atribute a1, a2,…,an va fi o relație al cărei cap este mulțimea de atribute, a1,a2,…,an. Corpul rezultatului va fi format din tupluri pentru care în relația A există un tuplu, atributul a1 are valoarea b1, atributul a2 are valoarea b2< и так далее атрибут an – bn. По сути при выполнении операции проекции определяется «Вертикальная» вырезка отношения - операнда с удалением возникающих кортежей –дубликатов.

Operația de îmbinare, numită uneori îmbinare condiționată, necesită doi operanzi, relațiile fiind unite și un al treilea operand, condiția simplă. Fie conectate relația A și B Ca și în cazul operației de selecție, condiția de îmbinare C are forma, (a comp –op b) sau (a comp –op const) unde A și B sunt numele de. atribute ale relațiilor A și B, const este literalmente specificată constantă. Comp-op este o operațiune de comparație validă în acest context. Atunci, prin definiție, rezultatul operației de conectare este relația obținută prin efectuarea operației de restricție, conform condiției C, produsul direct al relației A și B.

Există un caz special important de legătură, legătura naturală. O operație de îmbinare se numește operație de îmbinare naturală dacă condițiile de îmbinare sunt de forma (a=b) unde a și b sunt atribute ale operanzilor de îmbinare diferiți. Acest caz este important deoarece este deosebit de comun în practică și există algoritmi de implementare eficienți pentru acesta într-un SGBD. Operația natural join se aplică unei perechi de relații A și B care au un atribut comun P, adică un atribut cu același nume și definit pe același domeniu. Fie ab să desemneze uniunea antetelor relațiilor A și B. Atunci o îmbinare naturală este rezultatul îmbinării lui A și B proiectate pe ab. Operațiile de îmbinare naturală nu sunt incluse direct în setul de operații algebrei relaționale. dar au o semnificație practică foarte importantă.

Operația de împărțire a relațiilor are nevoie de mai mult explicatie detaliata pentru că este greu de înțeles. Să fie date două relații A (a1,a2,..,an,b1,b2,…,bm)

B (b1,b2,…,bn) Presupunem că atributul b1 al relației A și atributul b1 al relației B sunt definite pe același domeniu. Să numim mulțimea de atribute (aj) un atribut compus a, iar mulțimea (bj) c un atribut compus b. După aceasta, vom vorbi despre împărțirea relațională a relației binare A (a,b) în relația unară B (b).

Rezultatul împărțirii lui A la B este o relație unară C (a), constând din tupluri v astfel încât în ​​relația A există tupluri care în setul de valori (w) includ setul de valori ale lui b în raport cu B.

Deoarece împărțirea este cea mai dificilă operațiune, să o explicăm cu un exemplu. Să existe două relații în baza de date a studenților: STUDENTI (NUME COMPLET, NUMĂR) și NUME (NUME COMPLET), iar relația unară NUME conține toate numele pe care le au studenții institutului. Apoi, după efectuarea operației de împărțire relațională a relației STUDENTI în relația NUME, se va obține o relație unară care să conțină numerele de carnete de studenți aparținând studenților cu toate prenumele posibile la acest institut.


Notație relațională

Să presupunem că există o bază de date cu structura STUDENTI (număr, nume, bursă, cod grup) și relația GRUPURI (gr_nom, gr_kol, gr vechi) Să presupunem că trebuie să aflați numele și numerele studenților. bilete pentru studenții care sunt prefecți ai grupelor cu mai mult de 25 de persoane În algebra relațională, trebuie să întreprindeți următoarele acțiuni pentru o astfel de solicitare:

1. Conectați relațiile STUDENTI și GRUPURI, conform condiției „număr_elev = stea_grup”;

2. Limitați raportul rezultat prin condiția gr_col>25.

3. Proiectați rezultatul operației anterioare pe atributul student_name, student_number.

Iată o formulare pas cu pas a secvenței de execuție a interogării în baza de date, fiecare dintre acestea corespunzând unei singure operații relaționale. dacă formulăm aceeași interogare folosind calculul relațional, atunci am obține o formulă care poate fi citită: Emite STUDY_NAME și STUDY_NUMBER pentru astfel de studenți, astfel încât un astfel de grup GR_STAR și valoarea GR_NUM>25 să coexiste. În a doua formulare am indicat doar caracteristicile relației rezultate, dar nu am spus nimic despre metoda de formare a acesteia. În acest caz, SGBD însuși trebuie să decidă ce fel de operațiuni și în ce ordine trebuie efectuate asupra relațiilor STUDENTI și GRUPURI. Ambele metode discutate în exemplu sunt de fapt echivalente și nu există conversii foarte complexe de la una la alta.

Conceptele de bază ale calculului relațional sunt conceptele unei variabile cu o anumită zonă a valorii sale și conceptele unei formule corect construite bazate pe variabile și funcții speciale. Funcții. Care este domeniul de definire al unei variabile diferă între calculul tuplu și calculul domeniului, adică de-a lungul sau de-a lungul. În calculul tuplurilor, domeniile definiției variabilelor sunt relația bazei de date, adică. valoare valabilă Fiecare variabilă este un tuplu al unei relații. În calculul domeniului, domeniile de definire a variabilei sunt domeniile pe care sunt definite atributele relațiilor de baze de date, adică valoarea validă a fiecărei variabile este valoarea fiecărei variabile.

octet Întreg Şir Char
M
N
K

Comanda RANGE este folosită pentru a defini tupluri. De exemplu, pentru a defini variabila STUDENT al cărei scop este STUDENTS, trebuie să utilizați construcția RANGE STUDENT IS STUDENTS. Din această definiţie rezultă că în orice moment al timpului variabila student reprezintă un anumit tuplu al relaţiei STUDENTI. Când utilizați variabile tuple în formule, puteți face referire la valorile atributelor variabilelor. De exemplu, pentru a face referire la valoarea atributului STUDENT_NAME al variabilei STUDENT, trebuie să utilizați construcția STUDENT.STUDENT_NAME.

Formulele construite corect sunt folosite pentru a exprima condițiile impuse variabilelor tuple. Astfel de formule se bazează pe comparații simple, care sunt operații de comparare a valorilor atributelor variabilelor și constantelor literale. De exemplu, construcția STUDENT.STUD_NOM=123456. Este o comparație simplă. Mai mult varianta dificila formulele compuse sunt formate folosind conexiuni logice ȘI, SAU, NU, DACĂ…Atunci. În cele din urmă, este posibil să se construiască formule bine formate folosind cuantificatori. Dacă F este o formulă bine formată care implică variabila var, atunci construcția EXIST (cuantificator de existență) ​​var (F) și FORALL (pentru toate tuplurile) var (F) sunt corecte.

Variabilele incluse în formulele corect construite pot fi libere sau legate. Toate variabilele incluse în componența lor în construcția cărora nu s-au folosit cuantificatori sunt libere. Aceasta înseamnă că dacă pentru un set de valori ale variabilelor tuple libere se obține valoarea „adevărată” la calcularea formulelor, atunci aceste valori pot fi incluse în relația rezultată. Dacă se folosește un cuantificator la construirea formulelor, atunci variabilele sunt legate. Când se calculează valoarea unei astfel de formule corect construite, nu se utilizează o singură valoare a variabilei asociate, ci întregul său domeniu de definire.

1)EXISTĂ STUD2 (STUD.1STUD_STIP> STUD2.STUD_STIP)

2) FORALL STUD2 (STUD.1STUD_STIP> STUD2.STUD_STIP)

Fie STUD1 și STUD2 două variabile tuplu definite pentru relația elevi, atunci formula pentru tuplu curent al variabilei STUD1 ia valoarea adevărată numai dacă în întreaga relație elevi există un astfel de tuplu asociat cu variabila STUD2 astfel încât valoarea atributului său STUD_STIP satisface condiția de comparație internă. Formula corect construită nr. 2 pentru tuplul construit STUDENT 1 ia valoarea adevărată dacă pentru toate tuplurile relația STUDENTS asociată variabilei STUDENT 2, valoarea atributului STUDENT.STIP satisface condiția internă.

Astfel, formulele bine formate oferă un mijloc de exprimare a condițiilor de eșantionare dintr-o relație de bază de date. Pentru a putea folosi calculul relațional pentru a lucra efectiv cu o bază de date, este necesară o altă componentă care determină setul și numele coloanelor relației rezultate. Această componentă se numește lista tinta.

Lista țintelor are forma:

· Var.attr – numele unei variabile libere, attr este numele atributului relației pe care este definită variabila var.

· Var care este echivalent cu relația din listă, Var.attr1, Var.attr1... Var.attr№ include numele tuturor atributelor relației definitorii.

· Nume_nou = var.attr; noul nume al atributului corespunzător relației rezultate.

Ultima opțiune este necesară în cazurile în care codul din formulă folosește mai multe variabile libere cu același domeniu. În calculul domeniului, domeniul de definire a domeniilor nu este relațiile, ci domeniile. În raport cu baza de date STUDENTS GROUP, putem vorbi despre variabilele de domeniu NUME (Valorile de domeniu sunt nume valide sau NOM STUD). (Valorile domeniului sunt numere de student valide).

Principala diferență dintre calculul de domeniu și calculul tuplu este prezența set suplimentar predicate care permit exprimarea așa-numitelor condiții de apartenență. Dacă R este o relație n-ară cu atribute (a1, a2, … an), atunci condiția de apartenență are forma R(ai1:Vi1,ai2:Vi2,...aim:Vim) unde (m<=n). Где в Vij это либо литерально заданная константа либо имя кортежной переменной. Условие членства принимает значение истина, только в том случае если в отношении R существует кортеж, содержащий следующие значения указанных атрибутов. Если от Vij константа то на атрибут aij накладывается жёсткое условие независящее от текущих доменных переменных. Если же Vij имя доменной переменной то условие членства может принимать различные значения при разных значениях этой переменной.

Un predicat este o funcție logică care returnează adevărat sau fals pentru un argument. O relație poate fi considerată ca un predicat cu argumente care sunt atribute ale relației în cauză. Dacă un anumit set specific de tupluri este prezent în relație, atunci predicatul va produce un rezultat adevărat, altfel va produce un rezultat fals.

În toate celelalte privințe, formulele și expresiile calculului de domeniu arată similar cu formulele și expresiile calculului tuplu. Evaluarea domeniului relațional este baza pentru majoritatea interogărilor de limbaj bazate pe formulare.


Informații conexe.


Toate bazele de date moderne folosesc CBO (Cost Based Optimization), optimizarea costurilor. Esența sa constă în faptul că pentru fiecare operațiune se determină „costul” acesteia, iar apoi costul total al cererii este redus prin utilizarea celor mai „ieftine” lanțuri de operațiuni.

Pentru a înțelege mai bine optimizarea costurilor, vom analiza trei moduri comune de a uni două tabele și vom vedea cum chiar și o simplă interogare de asociere se poate transforma în coșmarul unui optimizator. În discuția noastră, ne vom concentra pe complexitatea timpului, deși optimizatorul calculează „costul” în ceea ce privește resursele procesorului, memorie și operațiuni I/O. Doar că complexitatea timpului este un concept aproximativ și pentru a determina resursele necesare procesorului, trebuie să numărați toate operațiile, inclusiv adunarea, declarațiile if, înmulțirea, iterația etc.

In afara de asta:

  • Pentru a efectua fiecare operație de nivel înalt, procesorul efectuează un număr diferit de operații de nivel scăzut.
  • Costul operațiunilor procesorului (în termeni de cicluri) variază între diferitele tipuri de procesoare, adică depinde de arhitectura specifică a procesorului.
Prin urmare, ne va fi mai ușor să evaluăm sub formă de complexitate. Dar amintiți-vă că cel mai adesea performanța bazei de date este limitată de subsistemul discului și nu de resursele procesorului.

Am vorbit despre ei când ne-am uitat la B-trees. După cum vă amintiți, indecșii sunt deja sortați. Apropo, există și alte tipuri de indici, de exemplu, indexul bitmap. Dar ele nu oferă niciun beneficiu în ceea ce privește CPU, memorie și utilizarea discului în comparație cu indexurile B-tree. În plus, multe baze de date moderne pot crea în mod dinamic indecși temporari pentru interogările în curs, dacă acest lucru va ajuta la reducerea costurilor de execuție a planului.

4.4.2. Modalitati de recurs

Înainte de a putea utiliza operatorii sindicali, trebuie să obțineți mai întâi datele necesare. Puteți face acest lucru în următoarele moduri.

  • Scanare completă. Baza de date citește pur și simplu întregul tabel sau index. După cum înțelegeți, pentru subsistemul disc este mai ieftin să citiți un index decât un tabel.
  • Scanare de gamă. Folosit, de exemplu, atunci când folosiți predicate precum WHERE AGE > 20 AND AGE< 40. Конечно, для сканирования диапазона индекса вам нужно иметь индекс для поля AGE.

    În prima parte a articolului, am aflat deja că complexitatea temporală a unei interogări de interval este definită ca M + log(N), unde N este numărul de date din index și M este numărul estimat de rânduri din intervalul. Cunoaștem valorile ambelor variabile datorită statisticilor. O scanare interval citește doar o parte a indexului, astfel încât operațiunea costă mai puțin decât o scanare completă.

  • Scanați pentru valori unice. Folosit în cazurile în care trebuie să obțineți o singură valoare din index.
  • Acces prin ID de rând. Dacă baza de date folosește un index, atunci de cele mai multe ori va căuta rânduri asociate acestuia. De exemplu, facem următoarea cerere:

    SELECTAȚI NUMELE, PRENUMELE din PERSOANA LA CARE VARSTA = 28
    Dacă avem un index pe coloana de vârstă, optimizatorul va folosi indexul pentru a găsi toți tinerii de 28 de ani și apoi va interoga ID-urile rândurilor corespunzătoare din tabel, deoarece indexul conține doar informații despre vârstă.

    Să presupunem că avem o altă cerere:

    SELECTAȚI TYPE_PERSON.CATEGORY din PERSON, TYPE_PERSON WHERE PERSON.AGE = TYPE_PERSON.AGE
    Pentru a îmbina cu TYPE_PERSON, va fi folosit un index pe coloana PERSON. Dar, deoarece nu am solicitat informații din tabelul PERSON, nimeni nu le va accesa prin ID-uri de rând.

    Această abordare este bună doar pentru un număr mic de apeluri, deoarece este costisitoare în ceea ce privește I/O. Dacă aveți nevoie să vă accesați ID-ul frecvent, este mai bine să utilizați o scanare completă.

  • alte metode. Puteți citi despre ele în documentația Oracle. Diferite baze de date pot folosi nume diferite, dar principiile sunt aceleași peste tot.
4.4.3. Operațiuni sindicale

Deci, știm cum să obținem datele, este timpul să le combinăm. Dar mai întâi, să definim câțiva termeni noi: dependențe interne și dependențe externe. Dependența ar putea fi:

  • masa,
  • index,
  • rezultatul intermediar al unei operații anterioare (de exemplu, o îmbinare anterioară).
Când combinăm două dependențe, algoritmii de îmbinare le gestionează diferit. Să presupunem că A JOIN B este uniunea dintre A și B, unde A este o dependență externă și B este o dependență internă.

Cel mai adesea, costul A JOIN B nu este egal cu costul B JOIN A.

Să presupunem că dependența externă conține N elemente, iar dependența internă conține M. După cum vă amintiți, optimizatorul cunoaște aceste valori datorită statisticilor. N și M sunt numere de dependență cardinale.

  • Unirea folosind bucle imbricate. Acest cel mai simplu mod asociațiile.

    Funcționează astfel: pentru fiecare șir al unei dependențe externe, potrivirile sunt găsite în toate șirurile dependenței interne.

    Exemplu de pseudocod:

    Nested_loop_join(array outer, array inner) pentru fiecare rând a în exterior pentru fiecare rând b în inner if (match_join_condition(a,b)) write_result_in_output(a,b) end if end for end for
    Deoarece aceasta este o iterație dublă, complexitatea timpului este definită ca O(N*M).

    Pentru fiecare dintre N rânduri de dependență externă, trebuie să numărați M rânduri de dependență externă. Adică, acest algoritm necesită N + N*M citiri de pe disc. Dacă dependența internă este suficient de mică, atunci o puteți pune în întregime în memorie, iar apoi subsistemul discului va avea doar citiri M + N. Așa că se recomandă ca dependența internă să fie cât mai compactă pentru a o încadra în memorie.

    În ceea ce privește complexitatea timpului, nu există nicio diferență.

    De asemenea, puteți înlocui dependența internă cu un index, acest lucru va salva operațiunile I/O.
    Dacă dependența internă nu se încadrează în totalitate în memorie, puteți utiliza un alt algoritm care utilizează discul mai economic.

    • În loc să citească ambele dependențe rând cu linie, acestea sunt citite în grupuri de linii (bunch), cu câte un grup din fiecare dependență fiind stocat în memorie.
    • Șirurile din aceste grupuri sunt comparate între ele, iar potrivirile găsite sunt stocate separat.
    • Apoi grupuri noi sunt încărcate în memorie și, de asemenea, comparate între ele.
    Și tot așa până se epuizează grupurile.

    Exemplu de algoritm:

    // versiune îmbunătățită pentru a reduce I/O pe disc. nested_loop_join_v2(fișier exterior, fișier interior) pentru fiecare grup ba în exterior // ba este acum în memorie pentru fiecare grup bb în interior // bb este acum în memorie pentru fiecare rând a în ba pentru fiecare rând b în bb if (match_join_condition( a,b)) write_result_in_output(a,b) end if final for end for end for final for
    În acest caz, complexitatea timpului rămâne aceeași, dar numărul de accesări la disc scade: (număr de grupuri externe + număr de grupuri externe * număr de grupuri interne). Pe măsură ce dimensiunea grupului crește, numărul de accesări la disc scade și mai mult.

    Notă: în acest algoritm, fiecare acces este citit volum mai mare date, dar acest lucru nu contează, deoarece apelurile sunt secvențiale.

  • Hash join. Aceasta este o operațiune mai complexă, dar în multe cazuri costul ei este mai mic.

    Algoritmul este următorul:

    1. Toate elementele din dependența internă sunt citite.
    2. Un tabel hash este creat în memorie.
    3. Toate elementele din dependența externă sunt citite unul câte unul.
    4. Pentru fiecare element se calculează un hash (folosind funcția corespunzătoare din tabelul hash) astfel încât să poată fi găsit blocul corespunzător din dependența internă.
    5. Elementele din bloc sunt comparate cu elementele din dependența externă.
    Pentru a evalua acest algoritm din punct de vedere al complexității timpului, trebuie făcute câteva ipoteze:
    • Dependența internă conține X blocuri.
    • Funcția hash distribuie hashurile aproape în mod egal pentru ambele dependențe. Adică toate blocurile au aceeași dimensiune.
    • Costul găsirii unei potriviri între elementele unei dependențe externe și toate elementele din interiorul unui bloc este egal cu numărul de elemente din interiorul blocului.
    Atunci complexitatea timpului va fi egală cu:

    (M / X) * (N / X) + hash_table_creation_cost(M) + hash_function_cost * N

    Și dacă funcția hash creează blocuri suficient de mici, atunci complexitatea timpului va fi O(M + N).

    Există o altă metodă de îmbinare hash care este mai eficientă în memorie și nu necesită mai multe operațiuni I/O:

    1. Tabelele hash sunt calculate pentru ambele dependențe.
    2. Plasat pe disc.
    3. Și apoi sunt comparate pas cu pas între ele (un bloc este încărcat în memorie, iar al doilea este citit rând cu linie).
    Asociere prin fuziune. Aceasta este singura metodă de îmbinare care are ca rezultat date sortate. În acest articol, luăm în considerare un caz simplificat când dependențele nu sunt împărțite în externe și interne, deoarece se comportă la fel. Cu toate acestea, în viața reală, acestea pot diferi, să zicem, atunci când lucrați cu duplicate.

    Operația de fuziune poate fi împărțită în două etape:

    1. (Opțional) este efectuată mai întâi o îmbinare de sortare, unde ambele seturi de date de intrare sunt sortate după cheile de îmbinare.
    2. Apoi are loc fuziunea.
    Triere

    Algoritmul de sortare de îmbinare a fost deja discutat mai sus, în acest caz, este destul de justificat dacă salvarea memoriei este importantă pentru dvs.

    Dar se întâmplă ca seturile de date să ajungă deja sortate, de exemplu:

    • Dacă masa este organizată nativ.
    • Dacă dependența este un index cu o condiție de îmbinare prezentă.
    • Dacă unirea are loc cu un rezultat intermediar sortat.
    Consolidare prin fuziune

    Această operație este foarte asemănătoare cu operația de îmbinare în sortare de îmbinare. Dar în loc să selectăm toate elementele ambelor dependențe, selectăm doar elemente egale.

    1. Cele două elemente curente ale ambelor dependențe sunt comparate.
    2. Dacă sunt egale, atunci sunt introduse în tabelul rezultat și apoi sunt comparate următoarele două elemente, câte unul din fiecare dependență.
    3. Dacă nu sunt egale, atunci comparația se repetă, dar în loc de cel mai mic dintre cele două elemente, se ia elementul următor din aceeași dependență, deoarece probabilitatea de coincidență în acest caz este mai mare.
    4. Pașii 1-3 se repetă până se epuizează elementele uneia dintre dependențe.
    Dacă ambele dependențe sunt deja sortate, atunci complexitatea timpului este O(N + M).

    Dacă ambele dependențe mai trebuie sortate, atunci complexitatea timpului este O(N * Log(N) + M * Log(M)).

    Acest algoritm funcționează bine deoarece ambele dependențe sunt deja sortate și nu trebuie să mergem înainte și înapoi între ele. Cu toate acestea, există o oarecare simplificare aici: algoritmul nu gestionează situațiile în care aceleași date apar de mai multe ori, adică atunci când apar mai multe potriviri. În realitate, se utilizează o versiune mai complexă a algoritmului. De exemplu:

    MergeJoin(relatie a, relatie b) relatie iesire intreg a_key:=0; întreg b_key:=0; în timp ce (a!=null și b!=null) dacă (a< b) a_key++; else if (a >b) b_key++; else //Predicat alăturat satisfăcut write_result_in_output(a,b) //Trebuie să fim atenți când creștem pointerii întreg a_key_temp:=a_key; întreg b_key_temp:=b_key; if (a != b) b_key_temp:= b_key + 1; end if if (b != a) a_key_temp:= a_key + 1; end if if (b == a && b == a) a_key_temp:= a_key + 1; b_key_temp:= b_key + 1; end if a_key:= a_key_temp; b_key:= b_key_temp; sfârşitul dacă sfârşitul în timp ce

Ce algoritm să aleg?

Dacă ar exista cel mai bun mod de a combina, atunci toate aceste soiuri nu ar exista. Deci, răspunsul la această întrebare depinde de o mulțime de factori:

  • Cantitatea de memorie disponibilă. Dacă nu este suficient, uită de un hash join puternic. Cel puțin, execuția sa este în întregime în memorie.
  • Dimensiunea celor două seturi de date de intrare. Dacă aveți un tabel mare și celălalt foarte mic, atunci o îmbinare care utilizează bucle imbricate va funcționa cel mai rapid, deoarece o îmbinare hash implică o procedură costisitoare pentru crearea hashurilor. Dacă aveți două tabele foarte mari, atunci unirea folosind bucle imbricate va consuma toate resursele CPU.
  • Disponibilitatea indicilor. Dacă aveți doi indici B-tree, este mai bine să utilizați o îmbinare de îmbinare.
  • Trebuie să sortez rezultatele? Poate doriți să utilizați o îmbinare de îmbinare costisitoare (cu sortare) dacă lucrați cu seturi de date nesortate. Apoi, la ieșire, veți primi date sortate, ceea ce este mai convenabil de combinat cu rezultatele unei alte uniuni. Sau pentru că interogarea se așteaptă implicit sau explicit să primească date sortate după operatorii ORDER BY/GROUP BY/DISTINCT.
  • Dependențele de ieșire sunt sortate?. În acest caz, este mai bine să utilizați o îmbinare de îmbinare.
  • Ce tipuri de dependențe folosești?. Unire prin echivalență (tableA.column1 = tableB.column2)? Dependențe interne, dependențe externe, produs cartezian sau auto-unire? ÎN situatii diferite Unele metode de îmbinare nu funcționează.
  • Distribuția datelor. Dacă datele sunt respinse de condiția de alăturare (de exemplu, vă alăturați persoanelor după nume de familie, dar există adesea nume), atunci în niciun caz nu ar trebui să utilizați o alăturare hash. În caz contrar, funcția hash va crea găleți cu distribuție internă foarte slabă.
  • Este necesar să fuzionați în mai multe procese/file?
Cei dornici de cunoștințe se pot adânci în documentația pentru DB2, ORACLE și SQL Server.

4.4.4. Exemple simplificate

Să presupunem că trebuie să ne unim cinci mese pentru a obține o imagine completă a anumitor persoane. Fiecare persoană poate avea:

  • Mai multe numere de telefon mobil.
  • Adrese de e-mail multiple.
  • Adrese fizice multiple.
  • Mai multe numere de cont bancar.
Adică, trebuie să răspundeți rapid la această solicitare:

SELECTAȚI * din PERSON, MOBILE, MAILS, ADRESSES, BANK_ACCOUNTS WHERE PERSON.PERSON_ID = MOBILES.PERSON_ID AND PERSON.PERSON_ID = MAILS.PERSON_ID AND PERSON.PERSON_ID = ADRESSES.PERSON_ID AND PERSON.PERSON_ID = BANK_IDS.
Optimizatorul trebuie să găsească cea mai buna cale procesarea datelor. Dar sunt două probleme:

  1. Ce metodă de alăturare ar trebui să folosesc? Există trei opțiuni (hash join, merge join, imbricat loop join), cu opțiunea de a folosi 0, 1 sau 2 indici. Ca să nu mai vorbim că indicii pot fi și diferiți.
  2. În ce ordine ar trebui efectuată fuziunea?
De exemplu, mai jos sunt posibile planuri pentru trei îmbinări a patru tabele:

Pe baza celor descrise, care sunt opțiunile dvs.?

  1. Utilizați o abordare cu forță brută. Folosind statistici, calculați costul fiecăruia dintre posibilele planuri de execuție a interogărilor și selectați-l pe cel mai ieftin. Dar există destul de multe opțiuni. Pentru fiecare comandă de alăturare, pot fi folosite trei căi diferite sindicate, în total 34=81 posibile planuri de execuție. În cazul unui arbore binar, problema alegerii ordinii de îmbinare devine o problemă de permutare, iar numărul de opțiuni este (2 * 4)! / (4 + 1)!... Ca rezultat, în acest exemplu foarte simplificat, numărul total de planuri posibile de execuție a interogării este de 34 * (2 * 4)! / (4 + 1)! = 27.216 Dacă la aceasta adăugăm opțiunile în care o îmbinare de îmbinare utilizează 0, 1 sau 2 indici B-tree, numărul de planuri posibile crește la 210.000. Am menționat că aceasta este o interogare FOARTE SIMPĂ?
  2. Plange si renunta. Foarte tentant, dar neproductiv și ai nevoie de bani.
  3. Încercați mai multe planuri și alegeți-l pe cel mai ieftin. Deoarece este imposibil să calculați costul tuturor opțiunilor posibile, puteți lua un set de date de testare arbitrar și puteți rula toate tipurile de planuri pe acesta pentru a estima costul acestora și a selecta cel mai bun.
  4. Aplicați reguli inteligente pentru a reduce numărul de planuri posibile.
    Există două tipuri de reguli:
    1. Cele „logice”, cu ajutorul cărora puteți elimina opțiunile inutile. Dar ele nu sunt întotdeauna aplicabile. De exemplu, „Când vă conectați folosind bucle imbricate, dependența interioară trebuie să fie cel mai mic set de date.”
    2. Nu trebuie să cauți cea mai profitabilă soluție și să aplici reguli mai stricte pentru a reduce numărul de planuri posibile. Spuneți: „dacă dependența este mică, utilizați îmbinări în buclă imbricate, dar niciodată îmbinare îmbinare sau îmbinare hash”.
Chiar și un exemplu atât de simplu ne confruntă selecție uriașă. Și în interogările reale pot exista și alți operatori relaționali: OUTER JOIN, CROSS JOIN, GROUP BY, ORDER BY, PROJECTION, UNION, INTERSECT, DISTINCT etc. Adică, numărul posibilelor planuri de execuție va fi și mai mare.

Deci, cum alege baza de date?

4.4.5. Programare dinamică, algoritm lacom și euristică

O bază de date relațională utilizează diferite abordări, care au fost menționate mai sus. Iar sarcina optimizatorului este să găsească o soluție adecvată într-un timp limitat. În cele mai multe cazuri, optimizatorul nu caută cea mai bună soluție, ci pur și simplu o soluție bună.

Forța brută poate fi potrivită pentru cereri mici. Și cu modalități de a elimina calculele inutile, chiar și interogările de dimensiuni moderate pot folosi forța brută. Aceasta se numește programare dinamică.

Esența este că multe planuri de execuție sunt foarte asemănătoare.

În această ilustrație, toate cele patru planuri folosesc subarborele A JOIN B. În loc să calculăm costul său pentru fiecare plan, îl putem calcula o singură dată și apoi folosim acele date atât timp cât este necesar. Cu alte cuvinte, folosind memorarea rezolvăm problema suprapunerii, adică evităm calculele inutile.

Datorită acestei abordări, în loc de complexitate temporală (2*N)!/(N+1)! obținem „doar” 3 N. În exemplul anterior cu patru îmbinări, aceasta înseamnă reducerea numărului de cazuri de la 336 la 81. Dacă luăm o interogare cu 8 îmbinări (o interogare mică), atunci reducerea complexității va fi de la 57.657.600 la 6.561.

Dacă sunteți deja familiarizat cu programarea dinamică sau algoritmizarea, vă puteți juca cu acest algoritm:

Procedura findbestplan(S) if (bestplan[S].cost infinit) return bestplan[S] // altfel bestplan[S] nu a fost calculat mai devreme, calculează-l acum dacă (S conține doar 1 relație) set bestplan[S]. plan și bestplan[S].cost bazat pe cea mai bună modalitate de a accesa S /* Folosind selecții pe S și indici pe S */ altfel pentru fiecare submulțime nevid S1 din S astfel încât S1 != S P1= findbestplan(S1) P2= findbestplan(S - S1) A = cel mai bun algoritm pentru unirea rezultatelor P1 și P2 cost = P1.cost + P2.cost + costul lui A dacă cost< bestplan[S].cost bestplan[S].cost = cost bestplan[S].plan = “execute P1.plan; execute P2.plan; join results of P1 and P2 using A” return bestplan[S]
Programarea dinamică poate fi utilizată pentru interogări mai mari, dar vor trebui introduse reguli suplimentare (euristice) pentru a reduce numărul de planuri posibile:


Algoritmi lacomi

Dar dacă cererea este foarte mare sau dacă trebuie să obținem un răspuns extrem de rapid, se folosește o altă clasă de algoritmi - algoritmi greedy.

În acest caz, planul de execuție a interogării este construit pas cu pas folosind o anumită regulă (euristica). Datorită acesteia, algoritmul lacom caută cea mai bună soluție pentru fiecare etapă separat. Planul începe cu o instrucțiune JOIN și apoi la fiecare pas se adaugă un nou JOIN conform regulii.

Să ne uităm la un exemplu simplu. Să luăm o interogare cu 4 îmbinări a 5 tabele (A, B, C, D și E). Să simplificăm oarecum problema și să ne imaginăm că singura opțiune este să combinam folosind algoritmi imbricați. Vom folosi regula „folosește unirea cu cel mai mic cost”.

  • Începem cu unul dintre tabele, de exemplu, A.
  • Calculăm costul fiecărei uniuni cu A (va fi atât o dependență externă, cât și una internă).
  • Constatăm că A JOIN B ne va costa cel mai ieftin.
  • Apoi calculăm costul fiecărei îmbinări cu rezultatul A JOIN B (o considerăm și în două roluri).
  • Constatăm că cel mai profitabil ar fi (A JOIN B) JOIN C.
  • Din nou evaluăm opțiunile posibile.
  • La sfârșit obținem următorul plan de execuție a interogării: (((A JOIN B) JOIN C) JOIN D) JOIN E)/
Același algoritm poate fi aplicat pentru a evalua opțiunile începând cu tabelul B, apoi C și așa mai departe. Drept urmare, obținem cinci planuri, dintre care alegem cel mai ieftin.

Acest algoritm este numit „algoritmul celui mai apropiat vecin”.

Nu vom intra în detalii, dar cu o bună simulare a complexității sortării N*log(N) această problemă Pot fi . Complexitatea temporală a algoritmului este O(N*log(N)) în loc de O(3 N) pentru versiunea completa cu programare dinamică. Dacă aveți o interogare mare cu 20 de alinări, atunci aceasta ar fi 26 față de 3.486.784.401, nu?

Dar există o nuanță. Presupunem că, dacă găsim cea mai bună modalitate de a uni două tabele, vom obține cel mai mic cost atunci când unim rezultatul îmbinărilor anterioare cu următoarele tabele. Totuși, chiar dacă A JOIN B este cea mai ieftină opțiune, atunci (A JOIN C) JOIN B poate avea un cost mai mic decât (A JOIN B) JOIN C.

Deci, dacă aveți nevoie disperată să găsiți cel mai mult plan ieftin din toate timpurile și popoarele, atunci este recomandabil să rulați în mod repetat algoritmi lacomi folosind reguli diferite.

Alti algoritmi

Dacă te-ai săturat deja de toți acești algoritmi, poți sări peste acest capitol. Nu este necesar să stăpânești restul materialului.

Mulți cercetători lucrează la problema găsirii celui mai bun plan de execuție a interogărilor. Ei încearcă adesea să găsească soluții pentru probleme și modele specifice. De exemplu, pentru îmbinări cu stele, execuție de interogare paralelă etc.

Se caută opțiuni pentru a înlocui programarea dinamică pentru executarea de interogări mari. Aceiași algoritmi lacomi sunt un subset de algoritmi euristici. Ei acționează conform regulii, își amintesc rezultatul unei etape și îl folosesc pentru a găsi cea mai bună opțiune pentru etapa următoare. Iar algoritmii care nu folosesc întotdeauna soluția găsită pentru etapa anterioară se numesc euristici.

Un exemplu sunt algoritmii genetici:

  • Fiecare soluție reprezintă un plan pentru executarea completă a cererii.
  • În loc de o soluție (plan), algoritmul generează X soluții la fiecare etapă.
  • În primul rând, sunt create planuri X, acest lucru se face aleatoriu.
  • Dintre acestea, sunt salvate doar acele planuri a căror valoare satisface un anumit criteriu.
  • Aceste planuri sunt apoi amestecate pentru a crea X planuri noi.
  • Unele dintre noile planuri sunt modificate aleatoriu.
  • Cei trei pași anteriori se repetă de Y ori.
  • Din planurile ultimului ciclu îl obținem pe cel mai bun.
Cu cât mai multe cicluri, cu atât planul poate fi calculat mai ieftin. Selecția naturală, consolidarea trăsăturilor, asta-i tot.
Apropo, algoritmii genetici sunt integrați în PostgreSQL.

Baza de date folosește, de asemenea, algoritmi euristici, cum ar fi Recoacerea simulată, Îmbunătățirea iterativă și Optimizarea în două faze. Dar nu este un fapt că sunt folosite în sistemele corporative, poate că destinul lor este produsele de cercetare.

4.4.6. Adevărați optimizatori

De asemenea, un capitol opțional, îl puteți sări peste el.

Să ne îndepărtăm de teoretizare și să ne uităm la exemple reale. De exemplu, cum funcționează optimizatorul SQLite. Aceasta este o bază de date „ușoară” care utilizează o optimizare simplă bazată pe un algoritm lacom cu reguli suplimentare:

  • SQLite nu modifică niciodată ordinea tabelelor într-o operație CROSS JOIN.
  • Se folosește unirea folosind bucle imbricate.
  • Îmbinările externe sunt întotdeauna evaluate în ordinea în care au fost efectuate.
  • Până la versiunea 3.8.0, algoritmul cel mai apropiat Nearest Neighbor este folosit pentru a găsi cel mai bun plan de execuție a interogărilor. Și din versiunea 3.8.0, este folosit „N cei mai apropiati vecini” (N3, N Nearest Neighbors).
Iată un alt exemplu. Dacă citim documentația IBM DB2, aflăm că optimizatorul său este folosit 7 diferite niveluri optimizări:
  • Algoritmi greedy:
    • 0 - optimizare minimă. Utilizează scanarea indexului, îmbinări în bucle imbricate și evită rescrierea unor interogări.
    • 1 - optimizare scăzută
    • 2 - optimizare completă
  • Programare dinamica:
    • 3 - optimizare medie și aproximare grosieră
    • 5 - optimizare completă, se folosesc toate tehnicile euristice
    • 7 - același lucru, dar fără euristică
    • 9 - optimizare maximă cu orice preț, indiferent de efortul depus. Toată lumea este evaluată moduri posibile sindicate, inclusiv produse carteziene.
Nivelul implicit este 5. Acesta include:
  • Colectarea tuturor statisticilor posibile, inclusiv distribuțiile de frecvență și cuantile.
  • Aplicarea tuturor regulilor de rescriere a interogărilor, inclusiv crearea unei rute de tabel pentru interogările materializate). Excepție fac regulile care necesită calcule intensive și sunt utilizate pentru un număr foarte limitat de cazuri.
  • Când încercați opțiunile de alăturare folosind programarea dinamică:
    • Există o utilizare limitată a dependenței interne compuse.
    • Pentru circuitele stelare cu tabele de căutare, produsele carteziene sunt utilizate într-o măsură limitată.
  • Sunt acoperite o gamă largă de metode de acces, inclusiv preluarea listei (mai multe despre aceasta mai jos), AND specială a indicilor și rutarea tabelelor pentru interogări materializate.
Desigur, dezvoltatorii nu împărtășesc detalii despre euristica utilizată în produsul lor, deoarece optimizatorul este poate cel mai o parte importantă DB. Cu toate acestea, știm că implicit pentru determinarea ordinii de alăturare este programare dinamică, limitat de euristică.

Alte condiții (GROUP BY, DISTINCT etc.) sunt procesate prin reguli simple.

4.4.7. Cache-ul planului de interogări

Deoarece construirea unui plan necesită timp, majoritatea bazelor de date stochează planul într-un cache al planului de interogare. Acest lucru ajută la evitarea calculelor inutile ale acelorași pași. Baza de date trebuie să știe exact când trebuie să actualizeze planurile învechite. Pentru aceasta, este stabilit un anumit prag, iar dacă modificările statisticilor îl depășesc, atunci planul aferent acestui tabel este eliminat din cache.

Cerere Executor

În această etapă, planul nostru a fost deja optimizat. Este recompilat în cod executabil și, dacă există suficiente resurse, este executat. Operatorii cuprinsi in plan (JOIN, SORT BY etc.) pot fi procesati fie secvential, fie in paralel decizia este luata de executant. Interacționează cu managerul de date pentru a primi și scrie date.

5. Manager de date


Managerul de interogări execută interogarea și are nevoie de date din tabele și indecși. Le solicită managerului de date, dar există două dificultăți:

  • Bazele de date relaționale folosesc un model tranzacțional. Este imposibil să obțineți orice date dorite la un moment dat, deoarece în acest moment pot fi folosite/modificate de cineva.
  • Preluarea datelor este cea mai lentă operațiune dintr-o bază de date. Prin urmare, managerul de date trebuie să poată prezice activitatea sa pentru a umple memoria tampon în timp util.

5.1. Manager cache

După cum s-a spus de mai multe ori, blocajul din baza de date este subsistemul disc. Prin urmare, un manager de cache este utilizat pentru a îmbunătăți performanța.

În loc să primească date direct de la Sistemul de fișiere, executorul solicitării contactează managerul de cache pentru ele. Utilizează un pool de buffer conținut în memorie, care poate crește radical performanța bazei de date. Este greu să pui un număr pentru asta, deoarece multe depind de ceea ce ai nevoie:

  • Acces secvenţial (scanare completă) sau aleatoriu (acces prin ID de rând).
  • Citiți sau scrieți.
De asemenea mare importanță are tipul de unități folosite în sistemul de discuri: „hard disk” cu la viteze diferite rotație ax, SSD, RAID în diferite configurații. Dar putem spune că utilizarea memoriei este de 100-100.000 de ori mai rapidă decât utilizarea discului.

Totuși, aici ne confruntăm cu o altă problemă. Managerul de cache trebuie să pună datele în memorie ÎNAINTE ca executantul de interogări să aibă nevoie de ele. În caz contrar, va trebui să aștepte ca acestea să fie primite de pe discul lent.

5.1.1. Preempțiune

Interogatorul știe de ce date va avea nevoie, deoarece știe întregul plan, ce date sunt pe disc și statistici.

Când executorul procesează prima bucată de date, acesta cere managerului de cache să preîncarce următoarea bucată. Și când procedează la procesarea acestuia, îi cere DC să încarce a treia și confirmă că prima porțiune poate fi ștearsă din cache.

Managerul de cache stochează aceste date într-un pool de buffer. De asemenea, le adaugă informații de serviciu (declanșare, blocare) pentru a ști dacă mai sunt necesare în buffer.

Uneori executantul nu știe de ce date va avea nevoie, sau unele baze de date nu au o astfel de funcționalitate. Apoi se folosește preîncărcarea speculativă (de exemplu, dacă executantul solicită datele 1, 3, 5, atunci probabil va solicita 7, 9, 11 în viitor) sau preîncărcarea secvențială (în acest caz, DC-ul încarcă pur și simplu următorul de la comanda discului o bucată de date.

Nu trebuie să uităm că buffer-ul este limitat de cantitatea de memorie disponibilă. Adică pentru a încărca unele date trebuie să le ștergem periodic pe altele. Completarea și ștergerea memoriei cache consumă o parte din subsistemul de disc și resursele de rețea. Dacă aveți o interogare care rulează frecvent, ar fi contraproductiv să încărcați și să curățați datele pe care le utilizează de fiecare dată. Pentru a rezolva această problemă, bazele de date moderne folosesc o strategie de înlocuire a tamponului.

5.1.2. Strategii de înlocuire a tamponului

Majoritatea bazelor de date (cel puțin SQL Server, MySQL, Oracle și DB2) folosesc algoritmul LRU (Least Recently Used) pentru aceasta. Este conceput pentru a menține datele în memoria cache care au fost utilizate recent, ceea ce înseamnă că există o probabilitate mare ca acestea să fie necesare din nou.

Pentru a face mai ușor de înțeles cum funcționează algoritmul, vom presupune că datele din buffer nu sunt blocate de declanșatoare (latch) și, prin urmare, pot fi șterse. În exemplul nostru, tamponul poate stoca trei date:

  1. Managerul de cache folosește datele 1 și le pune într-un buffer gol.
  2. Apoi folosește datele 4 și le trimite și în buffer.
  3. La fel se procedează cu datele 3.
  4. În continuare, sunt preluate datele 9, dar tamponul este deja plin. Prin urmare, datele 1 sunt eliminate din acesta, deoarece au fost neutilizate pentru cel mai mult timp. După aceasta, datele 9 sunt plasate în tampon.
  5. Managerul de cache folosește din nou datele 4. Este deja în buffer, deci este marcat ca fiind ultimul utilizat.
  6. Datele 1 devin din nou solicitate Pentru a le plasa în buffer, datele 3 sunt șterse din el, deoarece nu au fost folosite de cel mai mult timp.
Acesta este un algoritm bun, dar are unele limitări. Ce se întâmplă dacă facem o scanare completă a unui tabel mare? Ce se întâmplă dacă dimensiunea tabelului/indexului depășește dimensiunea tamponului? În acest caz, algoritmul va elimina tot conținutul său din cache, astfel încât datele complete de scanare vor fi utilizate cel mai probabil o singură dată.

Îmbunătățiri ale algoritmului

Pentru a preveni acest lucru, unele baze de date folosesc reguli speciale. Conform documentației Oracle:

„Pentru foarte mese mari De obicei se folosește accesul direct, adică blocurile de date sunt citite direct pentru a evita depășirea memoriei cache. Pentru tabelele de dimensiuni medii, pot fi utilizate atât accesul direct, cât și citirile din cache. Dacă sistemul decide să folosească memoria cache, baza de date plasează blocurile de date la sfârșitul listei LRU pentru a preveni ștergerea buffer-ului.”

De asemenea, este utilizată o versiune îmbunătățită a LRU, LRU-K. SQL Server folosește LRU-K cu K = 2. Esența acestui algoritm este că atunci când se evaluează situația, ia în considerare mai multe informatii despre tranzacțiile anterioare și nu numai că își amintește ultimele date utilizate. Litera K din nume înseamnă că algoritmul ia în considerare ce date au fost folosite ultimele K ori. Li se atribuie o anumită pondere. Când date noi sunt încărcate în cache, datele vechi, dar utilizate frecvent, nu sunt șterse, deoarece greutatea lor este mai mare. Desigur, dacă datele nu mai sunt folosite, acestea vor fi totuși șterse. Și cu cât datele rămân mai mult nerevendicate, cu atât greutatea lor scade în timp.

Calcularea greutății este destul de costisitoare, așa că SQL Server folosește LRU-K cu K egal cu doar 2. Pe măsură ce valoarea lui K crește ușor, eficiența algoritmului se îmbunătățește. Îl poți cunoaște mai bine datorită.

Alti algoritmi

Desigur, LRU-K nu este singura soluție. Există, de asemenea, 2Q și CLOCK (ambele similare cu LRU-K), MRU (Most Recently Used, care utilizează logica LRU, dar aplică o regulă diferită, LRFU (Least Recently and Frequently Used), etc. În unele baze de date puteți alege, ce se va folosi algoritmul.

5.1.3. Scrieți tampon

Am vorbit doar despre buffer-ul de citire, dar bazele de date folosesc și buffer-uri de scriere, care acumulează date și le scot pe disc pe porțiuni, în loc de scriere secvențială. Acest lucru salvează operațiunile I/O.
Amintiți-vă că stocarea tampon pagini(unități indivizibile de date), mai degrabă decât rânduri din tabele. Se spune că o pagină din pool-ul de buffer este murdară dacă este modificată, dar nu este scrisă pe disc. Există mulți algoritmi diferiți care sunt utilizați pentru a determina când sunt scrise pagini murdare. Dar are foarte mult de-a face cu conceptul de tranzacții.

5.2. Manager de tranzacții

Responsabilitatea lui este să se asigure că fiecare cerere este executată folosind propria sa tranzacție. Dar înainte de a vorbi despre dispecer, să clarificăm conceptul de tranzacții ACID.

5.2.1. „Pe acid” (joaca de cuvinte, dacă cineva nu a înțeles)

O tranzacție ACID (atomicitate, izolare, durabilitate, consistență) este o operație elementară, o unitate de lucru care îndeplinește 4 condiții:

  • Atomicitatea. Nu există nimic „mai mic” decât o tranzacție, nici o operațiune mai mică. Chiar dacă tranzacția durează 10 ore. Dacă o tranzacție eșuează, sistemul revine la starea „înainte”, adică tranzacția este anulată.
  • Izolare. Dacă două tranzacții A și B sunt executate în același timp, atunci rezultatul lor nu ar trebui să depindă dacă una dintre ele a fost finalizată înainte, în timpul sau după executarea celeilalte.
  • Durabilitate. Atunci când o tranzacție este comisă, adică finalizată cu succes, datele pe care le-a folosit rămân în baza de date, indiferent de eventualele incidente (erori, blocări).
  • Consecvență.În baza de date sunt înregistrate doar date valide (din punct de vedere al conexiunilor relaționale și funcționale). Consistența depinde de atomicitate și izolare.

În timpul executării oricărei tranzacții, puteți executa diverse interogări SQL pentru a citi, crea, actualiza și șterge date. Problemele încep atunci când două tranzacții folosesc aceleași date. Un exemplu clasic este transferul de bani din contul A în contul B. Să presupunem că avem două tranzacții:

  • T1 ia 100 USD din contul A și îi trimite în contul B.
  • T2 ia 50 USD din contul A și îi trimite, de asemenea, în contul B.
Acum să ne uităm la această situație din punctul de vedere al proprietăților ACID:
  • Atomicitatea vă permite să fiți sigur că indiferent de ce eveniment are loc în timpul T1 (crash server, defecțiune de rețea), nu se poate întâmpla ca 100 USD să fie debitați de la A, dar să nu ajungă la B (altfel se vorbește despre o „stare inconsecventă”).
  • Izolare spune că, chiar dacă T1 și T2 sunt efectuate simultan, ca rezultat 100 USD vor fi debitați de la A și aceeași sumă va merge la B. În toate celelalte cazuri, ei vorbesc din nou despre o stare inconsistentă.
  • Fiabilitate vă permite să nu vă faceți griji cu privire la dispariția T1 dacă baza de date se blochează imediat după comiterea T1.
  • Consecvență previne posibilitatea ca banii să fie creați sau distruși în sistem.
Nu trebuie să citiți mai jos, nu mai este important pentru înțelegerea restului materialului.

Multe baze de date nu oferă implicit izolarea completă, deoarece aceasta impune o suprasarcină uriașă de performanță. SQL folosește 4 niveluri de izolare:

  • Tranzacții serializabile. Cel mai inalt nivel izolare. Implicit în SQLite. Fiecare tranzacție este executată într-un mediu propriu, complet izolat.
  • Lectură repetabilă. Implicit în MySQL. Fiecare tranzacție are propriul mediu, cu excepția unei situații: dacă tranzacția adaugă date noiși se finalizează cu succes, acestea vor fi vizibile pentru alte tranzacții încă în curs. Dar dacă tranzacția modifică dateleși se finalizează cu succes, aceste modificări nu vor fi vizibile pentru tranzacțiile încă în curs. Adică, pentru datele noi, principiul izolării este încălcat.

    De exemplu, tranzacția A se execută

    SELECT count(1) din TABLE_X
    Apoi tranzacția B adaugă tabelul X și comite date noi. Și dacă după această tranzacție A efectuează din nou count(1), atunci rezultatul va fi diferit.

    Aceasta se numește citire fantomă.

  • Citiți datele angajate. Folosit implicit în Oracle, PostgreSQL și SQL Server. Aceasta este la fel ca citirea repetabilă, dar cu avantajul suplimentar de a întrerupe izolarea. Să presupunem că tranzacția A citește date; sunt apoi modificate sau șterse de tranzacția B, care comite aceste acțiuni. Dacă A citește din nou aceste date, ea va vedea modificările (sau faptul ștergerii) făcute de B.

    Aceasta se numește citire nerepetabilă.

  • Citiți datele necommitate. Cel mai scăzut nivel de izolare. La citirea datelor comise se adaugă o nouă încălcare a izolării. Să presupunem că tranzacția A citește date; apoi sunt modificate de tranzacția B (modificările nu sunt comise, B încă se execută). Dacă A citește din nou datele, va vedea modificările făcute. Dacă B este derulat înapoi, atunci când este citit din nou, A nu va vedea nicio modificare, ca și cum nimic nu s-ar fi întâmplat.

    Aceasta se numește citire murdară.

Majoritatea bazelor de date adaugă propriile niveluri de izolare (de exemplu, bazate pe instantanee, ca în PostgreSQL, Oracle și SQL Server). De asemenea, multe baze de date nu implementează toate cele patru niveluri descrise mai sus, în special citirea datelor necommitate.

Utilizatorul sau dezvoltatorul poate suprascrie nivelul de izolare implicit imediat după stabilirea conexiunii. Tot ce trebuie să faceți este să adăugați o linie de cod foarte simplă.

5.2.2. Controlul concurenței

Principalul lucru pentru care avem nevoie de izolare, consistență și atomicitate este capacitatea de a efectua operații de scriere pe aceleași date (adăugați, actualizați și ștergeți).

Dacă toate tranzacțiile citesc doar date, acestea pot funcționa simultan fără a afecta alte tranzacții.
Dacă cel puțin o tranzacție modifică datele citite de alte tranzacții, atunci baza de date trebuie să găsească o modalitate de a ascunde aceste modificări de acestea. De asemenea, trebuie să vă asigurați că modificările efectuate nu vor fi șterse de alte tranzacții care nu văd datele modificate.

Acest lucru se numește control al concurenței.

Cel mai simplu mod este să efectuați pur și simplu tranzacțiile una câte una. Dar această abordare este de obicei ineficientă (se folosește doar un nucleu al unui procesor), iar capacitatea de scalare este, de asemenea, pierdută.

Modul ideal de a rezolva problema arată astfel (de fiecare dată când o tranzacție este creată sau anulată):

  • Monitorizați toate operațiunile fiecărei tranzacții.
  • Dacă două sau mai multe tranzacții sunt în conflict din cauza citirii/modificării acelorași date, atunci modificați ordinea operațiunilor în cadrul părților în conflict pentru a minimiza numărul de motive.
  • Execută părți conflictuale ale tranzacțiilor într-o anumită ordine. Tranzacțiile neconflictuale sunt executate în paralel în acest moment.
  • Vă rugăm să rețineți că tranzacțiile pot fi anulate.
Dacă abordăm problema mai formal, atunci aceasta este o problemă de programare a conflictelor. Rezolvarea acesteia este foarte dificilă, iar optimizarea necesită resurse mari de procesor. Bazele de date corporative nu își pot permite să petreacă ore întregi căutând cel mai bun program pentru fiecare noua tranzactie. Prin urmare, se folosesc abordări mai puțin sofisticate, în care se alocă mai mult timp conflictelor.

5.2.3. Manager de blocare

Pentru a rezolva problema descrisă mai sus, multe baze de date folosesc blocări și/sau versiunea datelor.
Dacă o tranzacție are nevoie de anumite date, o blochează. Dacă le-a cerut și o altă tranzacție, atunci va trebui să aștepte până când prima tranzacție eliberează blocarea.

Aceasta se numește blocare exclusivă.

Dar este prea risipitor să folosești încuietori exclusive în cazurile în care tranzacțiile trebuie doar să citească date. De ce să interferați cu citirea datelor? În astfel de cazuri, se folosesc încuietori partajate. Dacă o tranzacție trebuie să citească date, aceasta îi aplică o blocare partajată și o citește. Acest lucru nu împiedică și alte tranzacții să partajeze încuietori și să citească datele. Dacă unul dintre ei trebuie să schimbe datele, atunci va trebui să aștepte până când toate încuietorile comune sunt eliberate. Abia atunci va putea aplica o blocare exclusivă. Și apoi toate celelalte tranzacții vor trebui să aștepte ca acesta să fie retras pentru a citi aceste date.

Un manager de blocare este un proces care aplică și eliberează încuietori. Ele sunt stocate într-un tabel hash (cheile sunt datele care sunt blocate). Managerul știe pentru toate datele ce tranzacții au aplicat blocări sau așteaptă să fie eliberate.

Impas

Utilizarea blocărilor poate duce la o situație în care două tranzacții așteaptă la nesfârșit eliberarea blocărilor:

Aici, tranzacția A a blocat exclusiv datele 1 și așteaptă eliberarea datelor 2. În același timp, tranzacția B a blocat exclusiv datele 2 și așteaptă ca datele 1 să fie eliberate.

Într-un impas, dispecerul alege ce tranzacție să anuleze (revenire). Și decizia nu este atât de ușor de luat:

  • Ar fi mai bine să omorâți tranzacția care a modificat ultimul set de date (și, prin urmare, rollback-ul ar fi cel mai puțin dureros)?
  • Ar fi mai bine să omorâm cea mai tânără tranzacție, deoarece utilizatorii altor tranzacții au așteptat mai mult?
  • Ar fi mai bine să omorâți o tranzacție care durează mai puțin timp pentru finalizare?
  • Câte alte tranzacții vor fi afectate de rollback?
Dar înainte de a lua o decizie, dispecerul trebuie să verifice dacă a avut loc într-adevăr un impas.

Să ne imaginăm un tabel hash sub forma unei diagrame, ca în ilustrația de mai sus. Dacă există o relație ciclică în diagramă, atunci blocajul este confirmat. Dar, deoarece verificarea ciclurilor este destul de costisitoare (la urma urmei, diagrama care arată toate blocajele va fi destul de mare), este adesea folosită o abordare mai simplă: utilizarea timeout-urilor. Dacă blocarea nu este eliberată într-un anumit timp, atunci tranzacția a intrat într-o stare de blocaj.

Înainte de a aplica o blocare, dispecerul poate verifica și pentru a vedea dacă va cauza un impas. Dar pentru a răspunde la aceasta fără ambiguitate, va trebui să cheltuiți și bani pe calcule. Prin urmare, astfel de verificări prealabile sunt adesea prezentate ca un set de reguli de bază.

Blocare în două faze

Cel mai simplu mod de a obține o izolare completă este atunci când o blocare este aplicată la început și eliberată la sfârșitul tranzacției. Aceasta înseamnă că o tranzacție trebuie să aștepte până când toate blocările sunt eliberate înainte de a începe, iar toate blocările pe care le-a aplicat sunt eliberate numai după finalizare. Această abordare poate fi folosită, dar apoi se pierde mult timp în așteptarea ca toate încuietorile să fie eliberate.

DB2 și SQL Server utilizează un protocol de blocare în două faze, care împarte o tranzacție în două faze:

  • Faza de crestere, când o tranzacție poate aplica doar blocări, dar nu le poate elibera.
  • Faza de micsorare, când o tranzacție poate elibera numai blocări (pe date care au fost deja procesate și nu vor fi procesate din nou), dar nu poate aplica altele noi.
Un conflict comun care apare în absența blocării în două faze este:

Înainte de tranzacția A, X = 1 și Y = 1. Procesează datele Y = 1, care au fost modificate de tranzacția B după începerea tranzacției A Datorită principiului izolării, tranzacția A trebuie să proceseze Y = 2.

Obiectivele atinse folosind aceste două reguli simple:

  • Eliberați blocările care nu mai sunt necesare pentru a reduce timpii de așteptare pentru alte tranzacții.
  • Preveniți cazurile în care o tranzacție primește date modificate de o tranzacție rulată anterior. Astfel de date nu se potrivesc cu datele solicitate.
Acest protocol funcționează excelent, cu excepția situației în care tranzacția a modificat datele și a scos blocarea din ele, iar apoi a fost anulată. În acest caz, o altă tranzacție poate citi și modifica datele, care vor fi apoi anulate. Pentru a evita această situație, toate blocajele exclusive trebuie eliberate la finalizarea tranzacției.

Desigur, bazele de date reale folosesc mai mult sisteme complexe, mai multe tipuri se blochează și cu o granularitate mai mare (blocare rânduri, pagini, partiții, tabele, spații de tabele), dar esența este aceeași.

Versiune de date

O altă modalitate de a rezolva problema conflictului de tranzacție este utilizarea versiunilor de date.

  • Toate tranzacțiile pot modifica aceleași date în același timp.
  • Fiecare tranzacție funcționează cu propria copie (versiune) a datelor.
  • Dacă două tranzacții modifică aceleași date, atunci doar una dintre modificări va fi acceptată, cealaltă va fi respinsă, iar tranzacția care a făcut-o va fi anulată (și eventual repornită).
Acest lucru permite creșterea productivității deoarece:
  • Tranzacțiile de citire nu blochează tranzacțiile de scriere și invers.
  • Managerul de blocare greoi nu are niciun impact.
În general, orice va fi mai bun decât încuietori, cu excepția cazului în care două tranzacții scriu aceleași date. În plus, acest lucru poate duce la o risipă uriașă de spațiu pe disc.

Ambele abordări - blocarea și versiunea - au argumente pro și contra, mult depinde de situația în care sunt utilizate (mai multe lecturi sau mai multe intrări). Puteți studia o prezentare foarte bună despre implementarea controlului concurenței multiversiune în PostgreSQL.

Unele baze de date (DB2 înainte de versiunea 9.7, SQL Server) folosesc numai blocări. Alții, precum PostgreSQL, MySQL și Oracle, folosesc abordări combinate.

Notă: versiunea are un efect interesant asupra indexurilor. Uneori există duplicate într-un index unic, indexul poate conține mai multe înregistrări decât rânduri din tabel etc.

Dacă o parte din date este citită la un nivel de izolare și apoi crește, atunci numărul de blocări crește, ceea ce înseamnă că se pierde mai mult timp în așteptarea tranzacțiilor. Prin urmare, majoritatea bazelor de date nu utilizează implicit nivelul maxim de izolare.

Ca de obicei, pentru mai mult informatii detaliate consultați documentația: MySQL, PostgreSQL, Oracle.

5.2.4. Manager de jurnal

După cum știm deja, pentru a crește performanța, baza de date stochează o parte din date în memoria tampon. Dar dacă serverul se blochează în timpul unei tranzacții, datele din memorie se vor pierde. Și acest lucru încalcă principiul fiabilității tranzacțiilor.

Desigur, puteți scrie totul pe disc, dar dacă se blochează, veți rămâne cu date nescrise, iar aceasta este o încălcare a principiului atomicității.

Orice modificare scrisă de tranzacție trebuie să fie anulată sau finalizată.

Acest lucru se face în două moduri:

  • Copii umbră/pagini. Fiecare tranzacție își creează propria copie a bazei de date (sau o parte a acesteia) și funcționează cu această copie. Dacă apare o eroare, copia este ștearsă. Dacă totul a mers bine, baza de date trece instantaneu la datele din copie folosind un truc la nivel de sistem de fișiere și apoi șterge datele „vechi”.
  • Jurnal de tranzacții. Aceasta este o unitate specială de depozitare. Înainte de fiecare scriere pe disc, baza de date scrie informații în jurnalul de tranzacții. Deci, în caz de eșec, baza de date va ști cum să ștergă sau să finalizeze tranzacția în așteptare.
WAL

În bazele de date mari cu numeroase tranzacții, copiile umbră/paginile ocupă o cantitate incredibil de mare de spațiu în subsistem de disc. Prin urmare, bazele de date moderne folosesc un jurnal de tranzacții. Trebuie plasat într-un depozit sigur.

Majoritatea produselor (în special, Oracle, SQL Server, DB2, PostgreSQL, MySQL și SQLite) funcționează cu jurnalele de tranzacții prin protocolul WAL (Write-Ahead Logging). Acest protocol conține trei reguli:

  1. Fiecare modificare a bazei de date trebuie să fie însoțită de o intrare în jurnal și trebuie făcută ÎNAINTE ca datele să fie scrise pe disc.
  2. Înregistrările din jurnal trebuie aranjate în conformitate cu ordinea evenimentelor relevante.
  3. Când o tranzacție este efectuată, o înregistrare a acesteia trebuie să fie scrisă în jurnal ÎNAINTE ca tranzacția să fie finalizată cu succes.

Managerul de jurnal monitorizează implementarea acestor reguli. Este situat în mod logic între managerul de cache și managerul de acces la date. Managerul de jurnal înregistrează fiecare operațiune efectuată de tranzacții până când este scrisă pe disc. Pare corect?

GRESIT! După tot ceea ce am trecut în acest articol, este timpul să ne amintim că tot ceea ce are legătură cu baza de date este supus blestemului „efectului bază de date”. Serios, problema este că trebuie să găsiți o modalitate de a scrie în jurnal, menținând în același timp o performanță bună. La urma urmei, dacă jurnalul de tranzacții este lent, atunci încetinește toate celelalte procese.

BERBEC

În 1992, cercetătorii de la IBM au creat o versiune extinsă a WAL, pe care au numit-o ARIES. Într-o formă sau alta, ARIES este folosit de majoritatea bazelor de date moderne. Dacă doriți să studiați acest protocol mai în profunzime, puteți studia lucrarea corespunzătoare.

Deci, BERBEC înseamnă A algoritmi pentru R ecovery şi eu solare E xploiting S mantici. Această tehnologie are două sarcini:

  1. Oferiți performanțe bune la scrierea jurnalelor.
  2. Asigurați o recuperare rapidă și fiabilă.
Există mai multe motive pentru care o bază de date trebuie să anuleze o tranzacție:
  1. Utilizatorul a anulat-o.
  2. Eroare de server sau de rețea.
  3. Tranzacția a încălcat integritatea bazei de date. De exemplu, ați aplicat condiția UNIQUE unei coloane, iar tranzacția a adăugat un duplicat.
  4. Prezența blocajelor.
Dar uneori baza de date poate restabili și o tranzacție, de exemplu, în cazul unei erori de rețea.

Cum este posibil acest lucru? Pentru a răspunde la aceasta, mai întâi trebuie să înțelegeți ce informații sunt stocate în jurnal.

Bușteni
Fiecare operațiune (adăugare/ștergere/modificare) în timpul executării unei tranzacții duce la apariția unei înregistrări în jurnal. Intrarea conține:

  • LSN (Număr de secvență de jurnal). Acesta este un număr unic a cărui semnificație este determinată de ordine cronologică. Adică, dacă operația A a avut loc înainte de operația B, LSN-ul pentru A va fi mai mic decât LSN-ul pentru B. În realitate, metoda de generare a unui LSN este mai complicată, deoarece este legată și de modul în care este stocat jurnalul.
  • TransID. ID-ul tranzacției care a efectuat operația.
  • PageID. Locația de pe disc în care se află datele modificate.
  • PrevLSN. Un link către o intrare anterioară de jurnal creată de aceeași tranzacție.
  • ANULA. O metodă de a derula înapoi o operație.

    De exemplu, dacă a fost efectuată o operație de actualizare, atunci valoarea/starea anterioară a elementului modificat (UNDO fizic) sau operația inversă care vă permite să reveniți la starea anterioară (UNDO logică) este scrisă în UNDO. BERBECUL folosește doar cele logice, lucrul cu cele fizice este foarte dificil.

  • A REFACE. Metoda de repetare a operației.
În plus, fiecare pagină de pe disc (pentru stocarea datelor, nu a jurnalelor) conține LSN-ul ultimei operațiuni care a modificat datele conținute acolo.

Din câte știm, UNDO nu este folosit doar în PostgreSQL. În schimb, un colector de gunoi este folosit pentru a curăța versiunile vechi ale datelor. Acest lucru se datorează implementării versiunilor de date în acest SGBD.

Pentru a vă face mai ușor să vă imaginați compoziția unei intrări de jurnal, iată un exemplu simplificat vizual în care Solicitare UPDATE DE LA PERSOANĂ SETĂ VÂRSTA = 18;. Să fie executat în tranzacția numărul 18:

Fiecare jurnal are un LSN unic. Jurnalele legate se referă la aceeași tranzacție și sunt legate în ordine cronologică (ultimul jurnal din listă se referă la ultima operațiune).

Buffer de jurnal
Pentru a preveni logarea să devină un blocaj al sistemului, se utilizează un buffer de jurnal.

Când interogatorul solicită date modificate:

  1. Managerul de cache le stochează într-un buffer.
  2. Managerul de jurnal stochează jurnalul corespunzător în propriul buffer.
  3. Interogatorul determină dacă operația s-a încheiat și, prin urmare, dacă datele modificate pot fi solicitate.
  4. Managerul de jurnal salvează informatie necesara la jurnalul de tranzacții. Momentul efectuării acestei intrări este determinat de algoritm.
  5. Managerul de cache scrie modificările pe disc. Momentul înregistrării este stabilit și de algoritm.
Când se commite o tranzacție, înseamnă că toți pașii de la 1 la 5 au fost finalizați. În același timp, scrierea datelor pe disc este o procedură mai complexă, ținând cont de faptul că datele trebuie ulterior citite rapid.

Politici STEAL și FORCE

Pentru a îmbunătăți performanța, pasul numărul 5 ar trebui făcut după comitere, deoarece în caz de eșec este încă posibilă restabilirea tranzacției folosind REDO. Aceasta se numește politica NO-FORCE.

Dar baza de date poate alege și politica FORCE pentru a reduce încărcarea în timpul recuperării. Apoi, pasul numărul 5 este executat înainte de comitere.

Baza de date alege, de asemenea, dacă să scrie datele pe disc în mod incremental (politica STEAL) sau, dacă managerul buffer-ului trebuie să aștepte un commit, să le scrie pe toate odată (NO-STEAL). Alegerea depinde de ceea ce aveți nevoie: înregistrare rapidă recuperare lungă sau recuperare rapidă?

Cum afectează politicile menționate procesul de recuperare:

  • STEAL/NO-FORCE necesită UNDO și REDO. Performanța este cea mai mare, dar structura jurnalelor și proceselor de recuperare (cum ar fi ARES) este mai complexă. Majoritatea bazelor de date folosesc această combinație de politici.
  • Pentru STEAL/FORCE ai nevoie doar de UNDO.
  • Pentru NO-STEAL/NO-FORCE - doar REDO.
  • Pentru NO-STEAL/FORCE nu ai nevoie de nimic. Performanța în acest caz este cea mai scăzută și este necesară o cantitate mare de memorie.
Recuperare

Deci, cum putem folosi jurnalele noastre uimitoare? Să presupunem că un nou angajat a distrus baza de date (regula #1: este întotdeauna vina începătorului!). Îl reporniți și începe procesul de recuperare.
BERBEC restaurează în trei etape:

  1. Analiză. Întregul jurnal de tranzacții este citit astfel încât să poată fi restaurată cronologia evenimentelor care au avut loc în timpul căderii bazei de date. Acest lucru ajută la determinarea tranzacției care trebuie anulată. Toate tranzacțiile fără un ordin de comitere sunt anulate. De asemenea, sistemul decide ce date ar fi trebuit scrise pe disc în timpul defecțiunii.
  2. Repeta. REDO este folosit pentru a actualiza baza de date la starea de dinaintea accidentului. Jurnalele sale sunt procesate în ordine cronologică. Pentru fiecare jurnal, se citește LSN-ul paginii de pe disc care conține datele care trebuie modificate.

    Dacă LSN(pages_on_disk)>=LSN(entries_in_log), atunci datele au fost deja scrise pe disc înainte de eroare. Dar valoarea a fost suprascrisă de o operațiune care a fost efectuată după înregistrare și înainte de eșec. Deci nu s-a făcut nimic, într-adevăr.

    Dacă LSN(pages_pe_disk)

    Reluarea este efectuată chiar și pentru tranzacțiile care vor fi anulate, deoarece simplifică procesul de recuperare. Dar bazele de date moderne probabil nu fac asta.

  3. Anulare.În această etapă, toate tranzacțiile care nu au fost finalizate în momentul eșecului sunt anulate. Procesul începe cu cele mai recente jurnale ale fiecărei tranzacții și procesează UNDO-urile în ordine cronologică inversă folosind PrevLSN.
În timpul procesului de recuperare, jurnalul de tranzacții trebuie să fie conștient de acțiunile efectuate în timpul recuperării. Acest lucru este necesar pentru a sincroniza datele salvate pe disc cu cele înregistrate în jurnalul de tranzacții. Este posibil să ștergeți înregistrările tranzacțiilor care sunt anulate, dar acest lucru este foarte dificil de făcut. În schimb, ARIES face înregistrări compensatorii în jurnalul de tranzacții care invalidează în mod logic intrările tranzacțiilor anulate.

Dacă tranzacția este anulată „manual”, sau de către un manager de blocare sau din cauza unei defecțiuni în rețea, atunci pasul de analiză nu este necesar. La urma urmei, informațiile pentru REDO și UNDO sunt conținute în două tabele aflate în memorie:

  • În tabelul de tranzacții (aici sunt stocate stările tuturor tranzacțiilor curente).
  • Tabelul paginilor murdare (acesta conține informații despre ce date trebuie scrise pe disc).
De îndată ce apare o nouă tranzacție, aceste tabele sunt actualizate de managerul de cache și managerul de tranzacții. Și din moment ce tabelele sunt stocate în memorie, dacă baza de date se blochează, acestea dispar.

Etapa de analiză este necesară doar pentru a restaura ambele tabele folosind informații din jurnalul de tranzacții. Pentru a accelera această fază, ARIES folosește puncte de control. Conținutul ambelor tabele, precum și cel mai recent LSN la momentul scrierii, sunt scrise pe disc din când în când. Deci, în timpul recuperării, sunt analizate doar jurnalele care urmează acestui LSN.

6. Concluzie

Ca o privire de ansamblu suplimentară citind despre baze de date, vă putem recomanda articolul Arhitectura unui sistem de baze de date. Aceasta este o introducere bună la subiect, scrisă într-un limbaj destul de clar.

Dacă ați citit cu atenție tot materialul de mai sus, probabil că v-ați făcut o idee despre cât de mari sunt capabilitățile bazelor de date. Cu toate acestea, acest articol nu abordează alte probleme importante:

  • Cum să gestionați bazele de date grupate și tranzacțiile globale.
  • Cum să obțineți un instantaneu dacă baza de date funcționează.
  • Cum să stocați și să comprimați eficient datele.
  • Cum să gestionezi memoria.
Deci, gândiți-vă de două ori înainte de a alege între un NoSQL cu erori și o bază de date relațională solidă. Nu mă înțelege greșit, unele baze de date NoSQL sunt foarte bune. Dar ele sunt încă departe de a fi perfecte și pot ajuta doar la rezolvarea unor probleme specifice asociate cu anumite aplicații.

Deci, dacă cineva vă întreabă cum funcționează bazele de date, atunci în loc să renunțați și să plecați, puteți răspunde:

Etichete: Adăugați etichete

Funcții DBMS.

Funcțiile DBMS sunt de nivel înalt și scăzut.

Funcții de nivel înalt:

1. Definirea datelor – folosind această funcție, se determină ce informații vor fi stocate în baza de date (tipul, proprietățile datelor și modul în care acestea vor fi legate între ele).

2. Procesarea datelor. Informațiile pot fi prelucrate în diferite moduri: eșantionare, filtrare, sortare, combinarea unei informații cu alta, calcularea totalurilor.

3. Management de date. Folosind această funcție, specificați cine are permisiunea de a vizualiza datele, de a le corecta sau de a adăuga informații noi și, de asemenea, definiți regulile pentru accesul colectiv.

Funcții de nivel scăzut:

1. Gestionarea datelor din memoria externă;

2. Gestionarea bufferelor RAM;

3. Managementul tranzacțiilor;

4. Introducerea unui jurnal de modificări în baza de date;

5. Asigurarea integritatii si securitatii bazei de date.

Tranzacţie este o secvență indivizibilă de operații care este monitorizată de SGBD de la început până la finalizare și în care, dacă o operație nu este finalizată, întreaga secvență este anulată.

Jurnal DBMS – o bază de date specială sau o parte din baza de date principală, inaccesibilă utilizatorului și utilizată pentru a înregistra informații despre toate modificările aduse bazei de date.

Introducere în jurnalul DBMS este conceput pentru a asigura o stocare fiabilă în baza de date în prezența defecțiunilor și defecțiunilor hardware, precum și a erorilor în software.

Integritatea bazei de date – aceasta este o proprietate a unei baze de date, ceea ce înseamnă că conține informații complete, consecvente și care reflectă în mod adecvat despre domeniul subiectului.

Clasificarea SGBD.

SGBD-urile pot fi clasificate:

1. După tipul de program:

A. Servere de baze de date (de exemplu, MS SQL Server, InterBase (Borland)) – sunt destinate organizării centrelor de prelucrare a datelor în rețele de calculatoare și implementării funcțiilor de gestionare a bazelor de date solicitate de programele client folosind instrucțiuni SQL (adică programe care răspund solicitărilor);

b. Clienți baze de date – programe care solicită date. PFDBMS, foile de calcul, procesoarele de text și programele de e-mail pot fi utilizate ca programe client;

c. Baze de date complet funcționale (MS Access, MS Fox Pro) – un program care are o interfață dezvoltată care vă permite să creați și să modificați tabele, să introduceți date, să creați și să formatați interogări, să dezvoltați rapoarte și să le imprimați.

2. Conform modelului de date DBMS (precum și baza de date):

A. Ierarhic – bazată pe o structură arborescentă pentru stocarea informațiilor și care amintește de un sistem de fișiere computerizat; principalul dezavantaj este incapacitatea de a implementa o relație multi-la-mulți;

b. Reţea – care le-a înlocuit pe cele ierarhice și nu a durat mult deoarece principalul dezavantaj a fost dificultatea dezvoltării aplicațiilor serioase. Principala diferență dintre o rețea și una ierarhică este că într-o structură ierarhică „descendentul-record” are un singur strămoș, dar într-un descendent de rețea poate avea orice număr de strămoși;

c. Relațional – ale căror date sunt plasate în tabele, între care există anumite legături;

d. Orientat pe obiecte – stochează date sub formă de obiecte iar principalul avantaj atunci când se lucrează cu ele este că li se poate aplica o abordare orientată pe obiecte;

e. Hibrid, adică obiect-relațional – combina capacitățile bazelor de date relaționale și orientate pe obiecte. Un exemplu de astfel de bază de date este Oracle (anterior era relațională).

3. În funcție de locația părților individuale ale SGBD, acestea se disting:

A. local – ale căror toate părțile sunt situate pe un singur computer;

b. reţea.

Rețelele includ:

- cu organizare file-server;

Cu această organizare, toate datele sunt localizate pe un singur computer, care se numește server de fișiere și care este conectat la rețea. Când se găsesc informațiile necesare, se transferă întregul fișier, inclusiv o mulțime de informații redundante. Și numai atunci când se creează o copie locală este găsită înregistrarea necesară.

- cu o organizatie client-server;

Serverul bazei de date primește o solicitare de la client, găsește înregistrarea necesară în date și o transmite clientului. O cerere către server este formată în limbajul de interogare structurat SQL, motiv pentru care serverele de baze de date sunt numite servere SQL.

- SGBD distribuit conțin câteva zeci și sute de servere situate pe o suprafață mare.

Prevederi de bază ale modelului bazei de date relaționale.

Baza de date relațională este o bază de date în care toate datele sunt organizate sub formă de tabele, iar toate operațiunile asupra acestor date sunt reduse la operațiuni pe tabele.

Caracteristicile bazelor de date relaționale:

1. Datele sunt stocate în tabele formate din coloane și rânduri;

2. La intersecția fiecărei coloane și rând există o singură valoare;

3. Fiecare coloană - câmp are propriul nume, care servește ca nume - atribut, iar toate valorile dintr-o coloană au același tip;

4. Coloanele sunt aranjate într-o anumită ordine, care este specificată la crearea tabelului, spre deosebire de rândurile, care sunt aranjate în ordine aleatorie. Tabelul poate să nu aibă un singur rând, dar trebuie să aibă cel puțin o coloană.

Terminologia bazelor de date relaționale:

Element de bază de date relaționale Formular de prezentare
1. Baza de date Set de mese
2. Schema bazei de date Set de anteturi de tabel
3. Atitudine Masa
4. Diagrama relațiilor Rând antet coloană tabel
5. Esența Descrierea proprietăților obiectului
6. Atribut Antetul coloanei
7. Domeniul Set de valori de atribute valide
8. Cheie primară Un identificator unic care identifică în mod unic fiecare înregistrare din tabel
9. Tipul de date Tipul valorilor elementului din tabel
10. Cortege șir (înregistrare)
11. Cardinalitatea Numărul de rânduri din tabel
12. Gradul de relație Numărul de câmpuri
13. Corpul relației Set de tupluri de relație

La proiectarea unei baze de date relaționale, datele sunt plasate în mai multe tabele. Relațiile se stabilesc între tabele folosind chei. La conectarea tabelelor, se disting un tabel principal și unul suplimentar (subordonat).

Există următoarele tipuri de relații între tabele:

1. Relație 1:1 (unu la unu) înseamnă că fiecare înregistrare din tabelul principal corespunde unei înregistrări din tabelul suplimentar și, invers, fiecare înregistrare din tabelul suplimentar corespunde unei înregistrări din tabelul principal.

2. Tipul de comunicare 1:M (unu la mai mulți) înseamnă că fiecare înregistrare din tabelul principal corespunde mai multor înregistrări din tabelul suplimentar și, invers, fiecare înregistrare din tabelul suplimentar corespunde unei singure înregistrări din tabelul principal.

3. Tipul de relație M:1 (mai multe la unul) înseamnă că una sau mai multe înregistrări din tabelul principal corespund unei singure înregistrări din tabelul secundar.

4. Relația M:M (mulți la mulți) – acesta este atunci când mai multe înregistrări ale tabelului principal corespund mai multor înregistrări ale tabelului suplimentar și invers.

5. Componentele de bază ale MS Access.

Principalele componente (obiecte) ale MS Access sunt:

1. Tabele;

3. Formulare;

4. Rapoarte;

5. Macrocomenzi:

Module

Masa este un obiect conceput pentru a stoca date sub formă de înregistrări (rânduri) și câmpuri (coloane). Fiecare câmp conține o parte diferită a unei înregistrări și fiecare tabel este utilizat pentru a stoca informații despre o problemă specifică.

Cerere – o întrebare despre datele stocate în tabele sau instrucțiuni pentru selectarea înregistrărilor care urmează să fie modificate.

Formă este un obiect în care puteți plasa controale destinate introducerii, afișarii și modificării datelor în câmpurile tabelului.

Raport este un obiect care vă permite să prezentați informații definite de utilizator într-o anumită formă, să le vizualizați și să le imprimați.

Macro – una sau mai multe macrocomenzi care pot fi folosite pentru a automatiza o anumită sarcină. O macrocomandă este elementul de bază al unei macrocomenzi; o instrucțiune de sine stătătoare care poate fi combinată cu alte instrucțiuni macro pentru a automatiza finalizarea unei sarcini.

Modul – un set de descrieri, instrucțiuni și proceduri stocate sub un singur nume. MS Access are trei tipuri de module: modul formular, modul raport și modul general. Modulele formulare și rapoarte conțin program local pentru formulare și rapoarte.

6. Tabele în MS Access.

MS Access are următoarele metode pentru a crea tabele:

1. Modul de masă;

2. Constructor;

3. Expert tabel;

4. Import tabele;

5. Comunicarea cu tabelele.

ÎN modul de masă Datele sunt introduse într-un tabel gol. Pentru introducerea datelor este furnizat un tabel cu 30 de câmpuri. După ce îl salvează, MS Access însuși decide ce tip de date să atribuie fiecărui câmp.

Constructor oferă posibilitatea de a crea în mod independent câmpuri, de a selecta tipuri de date pentru câmpuri, de dimensiunile câmpurilor și de a seta proprietățile câmpului.

Pentru a defini un câmp în mod Constructor sunt intrebati:

1. Numele domeniului , care în fiecare tabel trebuie să aibă un nume unic, care este o combinație de litere, cifre, spații și caractere speciale, cu excepția " .!” “ " Lungimea maximă a numelui este de 64 de caractere.

2. Tip de date definește tipul și intervalul de valori valide, precum și cantitatea de memorie alocată pentru acest câmp.

Tipuri de date MS Access

Tip de date Descriere
Text Text și numere, cum ar fi nume și adrese, numere de telefon, coduri poștale (până la 255 de caractere).
Câmp de memorare Text lung și numere, cum ar fi comentarii și explicații (până la 64.000 de caractere).
Numeric Un tip de date general pentru date numerice care permite calcule matematice, excluzând calculele monetare.
Data Ora Valori date și ore. Utilizatorul poate alege formulare standard sau poate crea un format personalizat.
Monetar Valori monetare. Pentru calculele monetare, nu se recomandă utilizarea unor tipuri de date numerice, deoarece pot fi rotunjite în calcule. Valorile valutare sunt întotdeauna afișate cu numărul specificat de zecimale.
Tejghea Numere secvențiale atribuite automat. Numerotarea începe de la 1. Câmpul contor este convenabil pentru crearea unei chei. Acest câmp este compatibil cu un câmp numeric a cărui proprietate Size este setată la Long Integer.
Logic Valori „Da/Nu”, „Adevărat/Fals”, „Pornit/Oprit”, una dintre cele două valori posibile.
Câmp obiect OLE Obiecte create în alte programe care acceptă protocolul OLE.

3. Cele mai importante proprietăți ale câmpului:

- Dimensiunea campului specifică dimensiunea maximă a datelor stocate în câmp.

- Format câmp este un format pentru afișarea unui anumit tip de date și stabilește regulile de prezentare a datelor atunci când le afișează pe ecran sau le imprimă.

- Semnătura câmpului setează textul care este afișat în tabele, formulare și rapoarte.

- Condiție de valoare vă permite să controlați intrarea, stabilește restricții asupra valorilor introduse, dacă sunt încălcate condițiile, interzice introducerea și afișează textul specificat de proprietatea Mesaj de eroare;

- Mesaj de eroare setează textul mesajului afișat pe ecran atunci când sunt încălcate restricțiile specificate de Condiția de valoare.

Tip control– o proprietate care este setată în fila Înlocuire din fereastra de proiectare a tabelului. Această proprietate determină dacă câmpul va fi afișat în tabel și sub ce formă - ca câmp sau casetă combinată.

Cheie unică (primară). tabelele pot fi simple sau complexe, incluzând mai multe câmpuri.

Pentru a defini o cheie, selectați câmpurile care compun cheia și faceți clic pe butonul din bara de instrumente câmp cheie sau comanda este executată Câmp de editare/cheie.


©2015-2019 site
Toate drepturile aparțin autorilor lor. Acest site nu pretinde autor, dar oferă o utilizare gratuită.
Data creării paginii: 2016-02-16

Baze de date relaționale vă permit să stocați informații în mai multe tabele „plate” (bidimensionale), interconectate prin câmpuri de date partajate numite chei. Bazele de date relaționale oferă acces mai ușor la rapoartele din mers (de obicei prin SQL) și oferă o fiabilitate și integritate sporită a datelor prin eliminarea informațiilor redundante.

Toată lumea știe ce este o bază de date simplă: directoarele telefonice, cataloagele de produse și dicționarele sunt toate baze de date. Ele pot fi structurate sau organizate în alt mod: ca fișiere plate, ca structuri ierarhice sau de rețea sau ca tabele relaționale. Cel mai adesea, organizațiile folosesc baze de date relaționale pentru a stoca informații.

O bază de date este o colecție de tabele formate din coloane și rânduri, similare unei foi de calcul. Fiecare linie conține o intrare; fiecare coloană conține toate cazurile unei anumite date din toate rândurile. De exemplu, un agendă telefonică tipică constă din coloane care conțin numere de telefon, numele apelantului și adresele apelantului. Fiecare linie conține un număr, un nume și o adresă. Acest formular simplu se numește fișier plat datorită naturii sale bidimensionale și faptului că toate datele sunt stocate într-un singur fișier.

În mod ideal, fiecare bază de date are cel puțin o coloană cu un identificator unic sau cheie. Luați în considerare agenda telefonică. Pot exista mai multe intrări pentru apelantul John Smith, dar niciunul dintre numerele de telefon nu se repetă. Numărul de telefon servește drept cheie.

În realitate, totul nu este atât de simplu. Două sau mai multe persoane care utilizează același număr de telefon pot fi listate separat în agenda telefonică, ceea ce face ca numărul de telefon să apară în două sau mai multe locuri, astfel încât să existe mai multe șiruri de taste care nu sunt unice.

Datele creează probleme

În cele mai simple baze de date, fiecare înregistrare ocupă un rând, cu alte cuvinte, compania de telefonie trebuie să creeze o coloană separată pentru fiecare informație contabilă. Adică unul pentru al doilea abonat al telefonului „împerecheat”, altul pentru al treilea etc., în funcție de câți abonați suplimentari sunt necesari.

Aceasta înseamnă că fiecare înregistrare din baza de date trebuie să aibă toate aceste coloane suplimentare, chiar dacă nu sunt folosite în altă parte. Aceasta înseamnă și că baza de date trebuie reorganizată ori de câte ori o companie oferă un nou serviciu. Este introdus serviciul de apelare pe ton - iar structura bazei de date se modifică, pe măsură ce se adaugă o nouă coloană. Este introdus suportul pentru ID apelant, apel în așteptare etc. - iar baza de date este reconstruită din nou și din nou.

În anii 1960, doar cele mai mari companii își puteau permite să achiziționeze computere pentru a-și gestiona datele. Mai mult, bazele de date construite cu modele de date statice și limbaje de programare procedurală, cum ar fi Cobol, pot fi costisitoare de întreținut și nu întotdeauna fiabile. Limbile procedurale definesc o secvență de evenimente prin care trebuie să treacă un computer pentru a finaliza o sarcină. Programarea unor astfel de secvențe a fost dificilă, mai ales dacă trebuia să modificați structura bazei de date sau să creați un nou tip de raport.

Conexiuni puternice

Edgar Codd, cercetător la Laboratorul de Cercetare din San Jose al IBM, a creat și descris în esență conceptul de baze de date relaționale în lucrarea sa fundamentală, A Relational Model of Data for Large Shared Data Banks of the ACM, iunie 1970).

Codd a propus un model care permite dezvoltatorilor să-și parționeze bazele de date în tabele separate, dar înrudite, ceea ce îmbunătățește performanța, păstrând în același timp același aspect ca baza de date originală. De atunci, Codd a fost considerat părintele fondator al industriei bazelor de date relaționale.

Acest model funcționează după cum urmează. Compania de telefonie ar putea crea un tabel principal folosind numărul de telefon ca cheie primară și îl poate stoca împreună cu alte informații de bază despre clienți. O companie poate defini un tabel separat cu coloane pentru această cheie primară și pentru servicii suplimentare, cum ar fi suport pentru identificarea apelantului și apel în așteptare. Ea poate crea, de asemenea, un alt tabel pentru a controla facturile de apel, unde fiecare intrare constă dintr-un număr de telefon și date de taxare a apelurilor.

Utilizatorii finali pot obține cu ușurință informațiile pe care le doresc, așa cum le doresc, chiar dacă datele sunt stocate în tabele diferite. Prin urmare, un reprezentant al serviciului clienți al unei companii de telefonie poate afișa informații despre facturarea unui abonat, precum și starea serviciilor speciale sau când a fost primită ultima plată, pe același ecran.

Codd a formulat 12 reguli pentru bazele de date relaționale, dintre care majoritatea se referă la integritatea datelor, actualizarea și accesul. Primele două sunt destul de clare chiar și pentru utilizatorii netehnici.

Regula 1, regula informațiilor, specifică că toate informațiile dintr-o bază de date relațională sunt reprezentate ca un set de valori stocate în tabele.

Regula 2, Regula de garantare a accesului, specifică că fiecare element de date dintr-o bază de date relațională poate fi accesat folosind un nume de tabel, o cheie primară și un nume de coloană. Cu alte cuvinte, toate datele sunt stocate în tabele și, dacă cunoașteți numele tabelului, cheia primară și coloana în care se află elementul de date necesar, acestea pot fi oricând preluate.

Esența muncii lui Codd a fost că s-a propus să se utilizeze limbaje de programare declarative, mai degrabă decât procedurale, cu baze de date relaționale. Limbajele declarative, cum ar fi SQL (Structured Query Language) oferă utilizatorilor posibilitatea de a spune în esență computerului: „Vreau să recuperez următorii biți de date din toate înregistrările care îndeplinesc un anumit set de criterii”. Computerul însuși va „înțelege” ce pași trebuie luați pentru a obține aceste informații din baza de date.

Pentru a lucra cu un număr mare de baze de date utilizate în mod activ, sunt utilizate sisteme software de gestionare a bazelor de date relaționale, create de producători de renume precum Oracle, Sybase, IBM, Informix și Microsoft.

Deși majoritatea implementărilor SQL pot fi numite interoperabile doar într-o anumită aproximare, acest mecanism, aprobat ca standard internațional, permite crearea unor sisteme complexe bazate pe baze de date. O interfață ușor de programat între site-urile Web și bazele de date relaționale oferă utilizatorilor finali posibilitatea de a adăuga înregistrări noi, de a le actualiza pe cele existente și de a genera rapoarte pentru o varietate de servicii, cum ar fi tranzacționarea online și accesul la cataloagele bibliotecii online.

Model relațional

O bază de date relațională folosește un set de tabele legate între ele printr-o cheie specifică (în acest caz, câmpul PhoneNumber)

Sisteme de management al bazelor de date și sisteme expert. Concepte de bază ale bazelor de date relaționale. Lucrul cu cereri. Forme. Rapoarte. Crearea bazei de date.

Sisteme de management al bazelor de date și funcțiile acestora

În tehnologia modernă a bazelor de date, software specializat - sisteme de gestionare a bazelor de date - este utilizat pentru a crea baze de date, a le susține și a le întreține. Un SGBD este un set de instrumente software și lingvistice necesare pentru crearea și operarea bazelor de date.

În stadiul dezvoltării bazei de date, SGBD este folosit pentru a descrie structura bazei de date: definirea tabelelor; determinarea numărului de câmpuri; tipul de date afișate în acestea; dimensiunile câmpurilor; definirea relaţiilor dintre tabele. Pe lângă tabele, majoritatea SGBD-urilor prevăd crearea de instrumente speciale pentru lucrul cu date - formulare, interogări.

În timpul funcționării bazelor de date, SGBD asigură editarea structurii bazei de date, completarea acesteia cu date, căutarea, sortarea, selectarea datelor conform criteriilor specificate și generarea de rapoarte.

În sistemele informaționale care rulează pe computere personale compatibile cu IBM, așa-numitele sisteme de gestionare a bazelor de date asemănătoare dBASE, de exemplu, dBASE, FoxPro și Clipper, au devenit larg răspândite. Ceea ce este semnificativ pentru utilizatori este că, deși diferă în limbajele de comandă și formatele de fișiere index, toate aceste SGBD folosesc aceleași fișiere de bază de date cu extensia .DBF, al cărei format a devenit de ceva timp un fel de standard de bază de date.

În bazele de date asemănătoare dBASE, se utilizează de fapt o abordare relațională a organizării datelor, adică Fiecare fișier .DBF este un tabel bidimensional care constă dintr-un număr fix de coloane și un număr variabil de rânduri (înregistrări). În termenii acceptați în documentația tehnică, fiecare coloană corespunde unui câmp de unul din cinci tipuri (N - numeric, C - simbolic, D - dată, L - logic, M - notă), iar fiecare linie corespunde unei înregistrări cu lungime fixă. constând dintr-un câmp cu număr fix. Folosind limbajele de comandă ale acestor SGBD, sunt create și corectate machetele de fișiere .DBF (descrieri de tabel), sunt create fișiere index, sunt descrise procedurile de lucru cu bazele de date (citire, căutare, modificare a datelor, raportare și multe altele). O trăsătură caracteristică a fișierului .DBF este simplitatea și claritatea acestuia: reprezentarea fizică a datelor de pe disc corespunde exact cu prezentarea tabelului pe hârtie. Cu toate acestea, în general, sistemele construite pe fișiere .DBF ar trebui să fie considerate învechite.



Alte SGBD-uri (cu un alt format de fișier) sunt, de asemenea, foarte populare - Paradox, Clarion etc. Trebuie subliniat faptul că sistemele enumerate își au originea în MS-DOS, dar acum aproape toate au fost îmbunătățite și au versiuni pentru Windows.

Dintre sistemele relaționale moderne, cel mai popular SGBD pentru Windows este Access de la Microsoft, Approach de la Lotus, Paradox de la Borland. Multe dintre aceste sisteme suportă tehnologia OLE și pot manipula nu numai informații numerice și textuale, ci și imagini grafice (desene, fotografii) și chiar fragmente de sunet și clipuri video.

SGBD-urile enumerate sunt adesea numite desktop, adică cantitatea relativ mică de date deservită de aceste sisteme. Cu toate acestea, nu numai utilizatorii individuali, ci și echipe întregi (în special în rețelele locale de calculatoare) lucrează adesea cu aceștia.

În același timp, SGBD-urile relaționale mai puternice, cu așa-numitul acces SQL, trec treptat în centrul tehnologiei informaționale moderne. Aceste SGBD-uri se bazează pe tehnologia client-server. Printre principalii producători de astfel de sisteme se numără Oracle, Centura (Gupta), Sybase, Informix, Microsoft și alții.

Tipuri de date în baze de date

Sistemele informaționale funcționează cu următoarele tipuri principale de date.

Date text. Valoarea fiecărei date text (caracter) este reprezentată de un set de caractere alfanumerice arbitrare, a căror lungime de cele mai multe ori nu depășește 255 (de exemplu, 5, 10, 140). Datele text reprezintă numele și pozițiile persoanelor, numele companiilor, produse, dispozitive etc. în IS. Într-un caz particular, valoarea unei date text poate fi numele unui fișier care conține informații nestructurate de lungime arbitrară (de exemplu, o biografie sau o fotografie a unui obiect). De fapt, acesta este un link structurat care vă permite să extindeți în mod dramatic conținutul de informații din tabelul dvs.

Date numerice. Datele de acest tip sunt de obicei folosite pentru a reprezenta atribute ale căror valori trebuie folosite pentru operații aritmetice (greutăți, prețuri, coeficienți etc.). O dată numerică, de regulă, are caracteristici suplimentare, de exemplu: un număr întreg de 2 octeți, un număr în virgulă mobilă (4 octeți) într-un format fix etc. Separatorul dintre părțile întregi și fracționale este de obicei un punct.

Date de tip dată și/sau oră. Datele tip dată sunt specificate într-un format cunoscut de mașină, de exemplu, ZZ.LL.AA (zi, lună, an). La prima vedere, acesta este un caz special de date text. Cu toate acestea, utilizarea unui tip de dată special într-un IC are următoarele avantaje. În primul rând, sistemul are posibilitatea de a menține un control strict (de exemplu, valoarea lunii poate fi doar discretă în intervalul 01-12). În al doilea rând, devine posibil să se reprezinte automat formatul de dată în funcție de tradițiile unei anumite țări (de exemplu, formatul MM-DD-GT este adoptat în SUA). În al treilea rând, la programare, operațiile aritmetice cu date sunt mult simplificate (încercați, de exemplu, să calculați manual o dată la 57 de zile după o dată dată). Folosirea acestui tip de timp are aceleași avantaje.

Date logice. O dată de acest tip (uneori numită boolean) poate lua doar una dintre cele două valori care se exclud reciproc - Adevărat sau Fals (condițional: 1 sau 0). Este de fapt un comutator a cărui valoare poate fi interpretată ca „Da” și „Nu” sau ca „Adevărat” și „Fals”. Tipul boolean este convenabil de utilizat pentru acele atribute care pot lua una dintre cele două valori care se exclud reciproc, de exemplu, a avea un permis de conducere (da sau nu), serviciul militar (da sau nu), etc.

Câmpuri obiect OLE. Valoarea unor astfel de date poate fi orice obiect OLE care este disponibil pe computer (grafică, sunet, video). În special, lista de studenți poate include nu numai o fotografie statică a elevului, ci și vocea acestuia.

Tipuri personalizate. În multe sisteme, utilizatorilor li se oferă posibilitatea de a-și crea propriile tipuri de date, de exemplu: „Ziua săptămânii” (luni, marți etc.), „Adresă” (cod poștal - oraș - ...), etc.

Într-un caz particular, valoarea unei date text poate fi o colecție de spații, iar valoarea unei date numerice poate fi zero. Dacă nu este introdusă nicio informație în tabel, valoarea va fi goală (Null). Nulul nu trebuie confundat cu zero sau spații. În multe sisteme, este important ca utilizatorul să înregistreze absența datelor pentru unele instanțe ale unui obiect (de exemplu, absența unei adrese, „Adresa este nulă”). Dacă introduceți accidental un spațiu într-un astfel de rând de tabel, sistemul va considera că adresa a fost specificată, iar această instanță nu va fi inclusă în lista de obiecte cu adrese lipsă.

Baze de date relaționale

Cea mai convenabilă modalitate atât pentru utilizator, cât și pentru computer este de a prezenta datele sub forma unui tabel bidimensional - majoritatea sistemelor informatice moderne funcționează doar cu astfel de tabele. Sunt numite baze de date care constau din tabele bidimensionale relaționale , (în engleză „relație” - relație). Ideea principală a abordării relaționale este de a reprezenta o structură de date arbitrară sub forma unui tabel bidimensional simplu.

Un exemplu de implementare a unui model de date relaționale ar putea fi un tabel cu informații despre elevi.

După cum se poate vedea din exemplul de mai sus, un tabel relațional are următoarele proprietăți:

· fiecare rând al tabelului este un element de date (informații despre un student);

· toate coloanele din tabel sunt omogene, i.e. Toate articolele dintr-o coloană sunt de același tip și lungime (de exemplu, coloana Nume afișează nume de elevi de tip caracter de până la 17 caractere);

· fiecare coloană are un nume unic (de exemplu, nu există două coloane Nume în tabel);

· nu sunt permise rânduri identice în tabel (se face o singură intrare pentru fiecare elev);

· ordinea rândurilor și coloanelor din tabel poate fi arbitrară (o înregistrare despre elev în tabel se face la admiterea la școală, iar ordinea coloanelor nu contează).

Elemente structurale ale unei baze de date relaționale

Folosind un tabel relațional ca exemplu, să ne uităm la principalele elemente structurale ale unei baze de date.

1. În bazele de date relaționale, orice colecție de date este prezentată sub formă de tabele (relații) bidimensionale, similare listei de elevi descrise mai sus. Mai mult, fiecare tabel constă dintr-un număr fix de coloane și un anumit număr (variabil) de rânduri. Descrierea coloanelor se numește de obicei aspectul tabelului.

2. Fiecare coloană a tabelului reprezintă un câmp - o unitate elementară de organizare logică a datelor, care corespunde unei unități indivizibile de informații - detaliile unui obiect de date (de exemplu, numele de familie al elevului, adresa).

Următoarele caracteristici sunt utilizate pentru a descrie domeniul:

· numele câmpului (de exemplu, Nr. dosar personal, Nume);

· tipul câmpului (de exemplu, caracter, dată);

· caracteristici suplimentare (lungimea câmpului, format, precizie).

De exemplu, câmp Data nașterii poate fi de tipul „data” și lungimea 8 (6 cifre și 2 puncte care separă ziua, luna și anul în înregistrarea datei).

3. Fiecare rând al unui tabel se numește înregistrare. Înregistrarea combină în mod logic toate câmpurile care descriu un obiect de date, de exemplu, toate câmpurile din primul rând al tabelului de mai sus descriu date despre studentul Ivan Vasilyevich Petrov, născut la 12 martie 1989, care locuiește la adresa st. Gorki, 12-34 ani, învață la clasa 4A, număr dosar personal - P-69. Sistemul numerotează înregistrările în ordine: 1,2, ..., n, unde n este numărul total de înregistrări (rânduri) din tabel în acest moment. Spre deosebire de numărul de câmpuri (coloane) dintr-un tabel, numărul de înregistrări în timpul funcționării bazei de date poate varia după cum se dorește (de la zero la milioane). Numărul de câmpuri, numele și tipurile acestora pot fi, de asemenea, modificate, dar aceasta este o operațiune specială numită modificarea aspectului mesei .

4. Structura de înregistrare a fișierului specifică câmpuri ale căror valori sunt o cheie simplă care identifică instanța de înregistrare. Un exemplu de cheie atât de simplă în tabelul Studenți este câmpul numărul de fișier personal, a cărui valoare identifică în mod unic un obiect din tabel - un student, deoarece nu există doi studenți în tabel cu același număr de fișier personal.

5. Fiecare câmp poate fi inclus în mai multe tabele (de exemplu, un câmp Nume de familie pot fi incluse în tabelul Lista elevilor din grupa de teatru).