Metodyka porównywania wydajności operacji SQL Insert w wybranych RDBMS

Poniżej polska wersja artykułu opublikowanego w PIMR,
oryginalna wersja dostępna tutaj

Wprowadzenie
Kluczową kwestią nabierającą coraz większego znaczenia, braną pod uwagę na etapie projektowania, wytwarzania i eksploatowania bazodanowych systemów informatycznych jest problem wydajności i skalowalności aplikacji[1]. W procesie wieloetapowego projektowania danych generalnie nasza uwaga skupiona jest na ich poprawnym odwzorowaniu zgodnie z rozpoznanymi wymaganiami i z przyjętym architektonicznym modelem danych. Zagadnienie wydajności samo w sobie jest zagadnieniem złożonym albowiem możemy go rozpatrywać w kontekście różnych operacji dokonywanych na bazie produkcyjnej lub też w kontekście procesów tworzenia na jej podstawie baz analitycznych[1][7][8]. Z tego obszaru, dość szerokiego, nakreślonego powyżej autorów zainteresował wpływ istnienia klucza podstawowego oaz sposób jego generowania na wydajność zapisu danych w RDBMS. W podejściu badawczym przyjęto perspektywę, interesującą użytkowników gotowego produktu, jaki jest RDBMS, w związku z tym świadomie pominięto zagadnienia związane z mechanizmami fizycznego rozmieszczenia danych na dysku.
Metodyka

Próba odpowiedzi na pytanie na ile obecność klucza podstawowego oraz sposób jego tworzenia wpływa na zapis danych w relacyjnych wymagało opracowania metodyki i wytworzenia niezbędnych narzędzi programistycznych.
Na etapie początkowym przyjęto szereg założeń, których zachowanie powinno eliminować wpływ czynników zakłócających pomiar. Między innymi zdecydowano się, iż aplikacja powinna działać całkowicie po stronie serwera bazodanowego. Tym samym wyeliminowano by wpływ interfejsów programistycznych dostępu do danych typu ADO, ADO.NET itp. na czas zapisu rekordów. Konsekwencją tej decyzji było zwrócenie naszej uwagi tylko na te RDBMS, których wewnętrzny język jest językiem proceduralnym.
Wytworzona procedura, względnie procedury stanowiące podstawowe narzędzie badawcze, powinny tworzyć strukturę tabeli, generować rekordy, a następnie je zapisywać. Równocześnie należałoby rejestrować czas rozpoczęcia i zakończenia zapisu danych z jednoczesnym odnotowywaniem liczby rekordów osadzonych w bazie. Powyższa druga porcja informacji, potrzebna do analiz, gromadzona byłaby w oddzielnej tabeli.
Skoro podstawowym celem autorów było uzyskanie odpowiedzi na pytanie na ile obecność klucza głównego i sposób jego generowania ma wpływ na szybkość zapisu zdecydowano się na utworzenie szeregu niezależnych procedur, osobno dla każdego przewidywanego wariantu. Wspólnym elementem byłby zapis wyników eksperymentu do tej samej tabeli. Przyjęto następujące przypadki, które wiązały się rodzajem informacjami zapisywanych w bazie:
• dane bez klucza podstawowego,
• dane z kluczem głównym, którego wartości generowane są przez RDBMS,
• dane z kluczem głównym, gdzie wartości są generowane na podstawie algorytmu użytkownika.
Procedury to realizujące powinny być zaimplementowane w co najmniej w dwóch RDBMS. Podjęto decyzję, iż będzie to SQL Server 2008, Oracle XE i MySQL. Podstawą wspomnianej decyzji była popularność wykorzystania tych narzędzi informatycznych. I tak dla przykładu na polskim rynku darmowa wersja MSSQL jest wykorzystywana między innymi w znanych programach: Płatnik, MicroSubiekt. Z kolei jego większy brat (płatny) stosowany jest między innymi w jednym z najpopularniejszych programów typu ERP na naszym rynku tj. CDN XL. Baza Mysql skolei dominuje na rynku aplikacji interneotwych, większość skryptów obsługujących fora to tandem Apache, PHP wraz z MySQL. Oprogramowanie bazodanowe dostarczane przez Oracle ma jedną z najlepszych opinii w środowisku IT, dlatego też darmowa wersja (XE) została poddana analogicznym testom jak MSSQL i MySQL.
W prezentowanej metodyce przyjęto jeszcze jedno założenie, z którym w praktyce bazodanowej bardzo często mamy do czynienia, polegające na tym, iż klucz podstawowy jest jedno elementowy, przyjmujący wartości typu int.
Mimo, że zaproponowana metodyka całościowo nie pokrywa się z operacjami przebiegającymi w rzeczywistości, to zdaniem autorów jest dobrym narzędziem do realizacji badań porównawczych. Świadomie zrezygnowano w rozważaniach i badaniach z specjalistycznych narzędzi służących do ładowania danych (typu ETL) wykorzystywanych w tworzeniu hurtowni danych, skupiając się głównie na rozwiązaniach bazodanowych OLTP.

Narzędzie badawcze – procedury

Sygnalizowane powyżej procedury, stanowiące narzędzie badawcze, wytworzono wpierw w języku T-SQL, który jest językiem wbudowanym w SQL Server 2008R2. Pozwala on nie tylko na manipulowanie danymi (składowe języka DML – Data modyfication Language) ale również na definiowanie struktury (składowe języka DDL – Data definition Language). W zaprezentowanej poniżej procedurze, dotyczące przypadku zapisu danych w tabeli bez zdefiniowanego klucza podstawowego, wykorzystano obie wspomniane możliwości języka T-SQL. Podjęto również decyzję o zapisie wyników cząstkowych eksperymentu w dodatkowej tabeli. Do utworzenia agregatów, które tworzą wyniki cząstkowe, odnotowane w tabeli wykorzystano pytanie grupujące wraz z funkcją DateDiff. Grupę tworzą rekordy, które zostały zapisane do bazy w tym samym przedziale czasowym wynoszącym jedna sekunda. Ten sposób grupowania jest możliwy, albowiem jedno z pól tabeli podstawowej (simple_insert_table) zawiera datę i czas systemowy zwróconą przez funkcję GetDate.

CREATE PROCEDURE [dbo].[simple_insert]
@numerow int=1000;
@numtries int= 100;
AS
BEGIN
SET NOCOUNT ON;
declare @testb datetime;
declare @tests datetime;

create table simple_insert_table (
a int, b varchar(10), c datetime );

declare @numtries1 int=@numtries;
declare @numerow1 int=@numerow;

begin transaction;
set @testb = GETDATE();
while @numtries >0
begin
set @numerow = @numerow1;
while @numerow >0
begin
insert into simple_insert_table values (1,’1234567890’,GETDATE());
set @numerow = @numerow -1;
end;
set @numtries = @numtries -1;
end;
set @tests=GETDATE();

insert into test_results (test_name,start_d,stop_d,param1,param2)
values (‘simple insert test’,@testb,@tests,@numerow1,@numtries1);

set @numerow = @@IDENTITY;
insert into test_subresult (test_id, ins_num, time_agr)
select @numerow,count (DATEDIFF(S, ‘19700101’, c)) e, DATEDIFF(S, ‘19700101’, c) from
simple_insert_table
group by DATEDIFF(S, ‘19700101’, c);
insert into test_results (test_name,param1,param2,param3,param4,param5)
select ‘statistic for simple insert: ‘+ cast(@numerow as varchar),exec_per,max_ins,avg_ins,min_ins,stddev_ins from dbo.simple_insert_stat;
drop table simple_insert_table;
commit transaction;
END

Niewielkie zmiany w prezentowanym kodzie pozwoliły na zbudowanie nowych procedur, które stanowiły narzędzie testujące dla dwóch kolejnych przypadków. W pierwszym wariancie klucz był generowany przez algorytm zawarty w procedurze. Zmienna wykorzystywana do przekazywania wartości generowanego klucza do zapytania, stanowiła równocześnie składową warunku, decydującego o liczbie wykonanych pętli. W drugim przypadku do generowania klucza wykorzystano odpowiednie narzędzia serwera bazodanowego. W przypadku SQL Server 2008R2 wykorzystano mechanizm identity, natomiast jego odpowiednikiem na poziomie MySQL był autoincrement. Z kolei w RDBMS Oracle wykorzystano mechanizm sekwencji. Ingerencja w wspomniane narzędzia dotyczyła tylko ustawień początkowych, obejmujących wartość startową oraz skok, które we wszystkich przypadkach były identyczne. Celem zapewnienia możliwości dokonania uogólnień omawiany algorytm został zaimplementowany w języku PL/SQL oraz w proceduralnym rozszerzeniu języka SQL dla bazy MySQL 5.5.8, co pozwoliło na przeprowadzenie testów z wykorzystaniem innych RDBMS.
W trakcie podjętych przez autorów badań pojawiła się, co prawda nowa wersja SQL Server 2011 wyposażona tym razem w dwa mechanizmy, pozwalające na automatyczne tworzenie klucza podstawowego, lecz nie jest to wersja ostateczna, w związku z powyższym nie stała się ona przedmiotem eksperymentów. Tym dodatkowym narzędziem umożliwiającym automatyczne generowanie klucza na poziomie wspomnianego RDBMS jest mechanizm sekwencji [8].
Badania i wyniki

Badania przeprowadzono w wirtualnym środowisku, opartym o system operacyjny Windows XP Home Edition wraz z najnowszymi aktualizacjami. Instalacja miała charakter standardowy podobnie, jak późniejsza instalacja RDBMS (zaaprobowano wszystkie ustawienia kreatora). Po zakończeniu testów danego RDBMS następowała reinstalacja środowiska badawczego. Każdy z testów został także wykonany na maszynie serwerowej podpiętej do macierzy w środowisku Windows Server 2008 ( z wyłączeniem testów bazy Oracle). Procedury dla bazy Oracle zostały przetestowane na serwerze z systemem operacyjnym Ubuntu Server 11 także podpiętym do wydajnej macierzy. Wyniki z środowisk serwerowych były analogiczne do maszyny badawczej (relacje wyników testów dla danego RDBMS).
Powszechnie uważa się iż wyłączenie ograniczeń (np. Klucza podstawowego) podczas wstawiania dużej ilości danych pozwala zwiększyć wydajność zapisu. Opisywany eksperyment pozwala ocenić czy wskazana operacja jest wstanie przynieść realne zyski.
W celu przeprowadzenia testów potrzebne było utworzenie w każdym badanym RDBMS pustej bazy danych, również zgodnie z ustawieniami sugerowanymi przez kreatora. Dało to podstawy do osadzenia w niej procedur testujących z jednoczesnym utworzeniem struktury relacyjnej do gromadzenia wyników badań.
Test przeprowadzono dla każdego z RDBMS dla wyszczególnianych poniżej wariantów, podczas których wprowadzono do bazy 106 rekordów:
• wstawiano dane bez klucza głównego,
• wstawiano dane tworzące klucz główny z poziomu procedury
• wstawiono dane zawierające klucz główny utworzony przy użyciu mechanizmów RDBMS (autoincrement, identity, sequence).

Efekty przeprowadzonych badań zaprezentowano w formie tabelarycznej tab. 1, 2, 3 i 4. Zawierają one wielkości względne, a punktem ich odniesienia są wyniki uzyskane dla pierwszego wariantu badań. Powyższy sposób postępowania zastosowano do rezultatów uzyskiwanych dla każdego z badanych RDBMS. W przypadku MySQL 5.5.8 badania przeprowadzono dla dwóch różnych silników INNODB oraz MyISAM, dostępnych dla tego RDBMS. Natomiast niecelowym, zdaniem autorów było umieszczenie względnych wyników badań uzyskanych dla przypadku zapisu rekordów pozbawionych klucza podstawowego.

Omówienie wyników

Zaprezentowane wyniki badań zapisu danych zawierających i niezawierających klucz podstawowy niewiele się różnią się między sobą w przypadku SQL Server 2008 R2. Dotyczy to zarówno sytuacji, gdy klucz jest tworzony przez RDBMS, jak i przez algorytm zaszyty w procedurze testującej. Opóźnienie zapisu danych wyposażonych w klucz podstawowy, przy przyjęciu prędkości zapisu 5000 wierszy na sekundę oraz liczbie rekordów 106, wynosi 10 sekund. Ważnym odnotowania jest również fakt, iż w trakcie badań nie zaobserwowano spadku prędkości zapisu wierszy wraz ze wzrostem liczby rekordów zawartych w tabeli. Zbliżoną prawidłowość zauważono w przypadku MySQL 5.5.8 wyposażonego w silnik InnoDB z tym, że okazał się on bardziej wrażliwy na sposób generowania klucza podstawowego. Drugą dość zaskakującą zależnością, wynikającą z otrzymanych wyników dla tego RDBMS jest wzrost względnej prędkości zapisu danych, zawierających klucz podstawowy. Dotyczy to zarówno sytuacji gdy klucz główny jest generowany przez system bazodanowy, jak i procedurę. Równoległym faktem, wymagającym wyjaśnienia są zerowe wartości prędkości minimalnej uzyskiwane w trakcie badań MySQL 5.5.8[5]. Skutkowało to znacznym wzrostem odchylenia standardowego oraz tym, że minimalna prędkość względna przyjmowała wartości nieokreślone.
Tego rodzaju prawidłowości nie stwierdzono przy użyciu wcześniejszego silnika MyISAM MySQL 5.5.8 [4]. Odnotowane w tym przypadku tendencje, będę konsekwencjami pomiarów są zgodne z rezultatami uzyskanymi dla Oracle XE, które potwierdzają dotychczasowe przekonanie, że wprowadzenie klucza spowalnia zapis nowych wierszy do tabeli. Należy jednak przypomnieć o istotnych wadach silnika MyISAM, jakim jest brak możliwość tworzenia transakcji i definiowania więzów integralności referencyjnej [6].
Podsumowanie

Współczesne RDBMS bardzo się różnią pod względem implementacji modelu relacyjnego, co utrudniania formułowanie uogólnień i reguł dotyczących wydajności tych systemów informatycznych. W pewnych wypadkach rozwiązania intuicyjne, czy będące efektem dotychczasowych doświadczeń z RDBMS mogą się okazać nieefektywne przy pracy z nowymi systemami bazodanowymi, dlatego autorzy zalecają testowanie proponowanych rozwiązań zwłaszcza przed rozpoczęciem prac rozwojowych tworzonego oprogramowania (zwłaszcza w przypadku tworzenia struktur OLAP). Przeprowadzone badania wraz z dokonaną analizą wyników, z użyciem trzech różnych RDBMS skłoniły autorów do sformułowania następujących uwag i wniosków:
• Wyposażenie danych w klucz podstawowy ogranicza z reguły wydajność zapisu rekordów w każdym badanym RDBMS z wyłączaniem MySQL 5.5 zawierającego silnik InnoDB. Spadek tej wydajności jest zróżnicowany lecz z perspektywy SQL Server 2008R2 jest on mało znaczący.
• Mechanizm generowania klucza podstawowego wbudowany w RDBMS z perspektywy wydajności zapisu nowych wierszy jest generalnie rozwiązaniem lepszym od własnych rozwiązań programistycznych zaszytych w procedurach.
• Wskazanym wydaje się podjęcie dalszych wysiłków poznawczych, zmierzających do wyjaśnienia nietypowego zachowania się MySQL 5.5.8 z silnikiem InnoDB z perspektywy prędkości zapisu danych pozbawianych i wyposażonych w klucz podstawowy.
• Uzyskane całkowite czasy zapisy danych w analizowanych wariantach i w różnych RDBMS i przy zaproponowanej metodyce badań wskazują, że z perspektywy aplikacji OLTP korzyści wydajnościowe, wynikające z niestosowania jednoelementowego klucza podstawowego są mało znaczące.
Bibliografia

[1] Beynon-Davies – Database Systems 2003
[2] Joe Celko – SQL for Smarties, Advanced SQL Programming, 3 Edition 2005
[3] MySQL Reference Manual – http://dev.mysql.com/doc/refman/5.5/en/mysql-nutshell.html 2011
[4] MySQL MyISAM Storage Engine Manual – http://dev.mysql.com/doc/refman/5.0/en/myisam-storage-engine.html
[5] MySQL InnoDB – http://dev.mysql.com/doc/refman/5.5/en/innodb-storage-engine.html
[6] MySQL refman – http://dev.mysql.com/doc/refman/5.0/en/ansi-diff-foreign-keys.html
[7] Paulraj Ponniah – Data Warehousing Fundamentals for IT Professionals 2010
[8] SQL Server perfomance – http://www.sql-server-performance.com/articles/dev/sequence_sql_server_2011_p1.aspx 2011
[9] Chris Todman – Designing a data warehouse: supporting customer relationship management 2003

Przestrzeń Tabel Oracle

Przestrzeń Tabel Oracle (TableSpace) jest logiczną jednostką w Systemach bazodanowych firmy Oracle. Przestrzeń tabel zawiera przynajmniej jeden plik (datafile). Każdy obiekt przechowywany w bazie danych Oracle jest przypisany do konkretnej przestrzeni tabel. Można powiedzieć że przestrzeń tabel jest pewnego rodzaju mostem pomiędzy systemem plików a RDBMS.

Wiersz, krotka, rekord w bazach danych

Wiersz/Krotka/Rekord w bazie danych jest konstrukcją analogiczną do rekordu w języku programowania. Posiada strukturę wewnętrzną tj. podział na pola o określonym typie. Rekordem może być wiersz pliku tekstowego, a pola mogą być określone poprzez pozycję w wierszu lub oddzielane separatorami. W relacyjnych bazach danych rekord to jeden wiersz w tabeli, czyli jedna krotka w relacji. Podczas przetwarzania wyników zapytań do bazy danych, które mogą zawierać połączone dane z kilku tabel, pojedynczy wiersz również jest nazywany rekordem. W bazach analitycznych w przypadku kostek OLAP można spotkać się określeniem krotki jako komórki zwracanej w wyniku zapytania (normalnie krotka odpowiada wierszowi/rekordowi).

widok – perspektywa

Widok (perspektywa) to logiczny byt (obiekt), osadzony na serwerze baz danych. Umożliwia dostęp do podzbioru kolumn i wierszy tabel lub tabeli na podstawie zapytania w języku SQL, które stanowi część definicji tego obiektu. Przy korzystaniu z widoku jako źródła danych należy odwoływać się identycznie jak do tabeli. Operacje wstawiania, modyfikowania oraz usuwania rekordów nie zawsze są możliwe ( np. w sytuacji gdy widok udostępnia część kolumn dwóch tabel tb_A oraz tb_B bez kolumny z kluczem głównym tabeli tb_B ). W niektórych SZBD widok służy tylko i wyłącznie do pobierania wyników i ograniczania dostępu do danych.

Encja

Encja (ang. entity) w bazach danych to reprezentacja obiektu (grupy obiektów) Formalnie jest to pojęcie niedefiniowalne, a podstawową cechą encji jest to, że jest rozróżnialna od innych encji (założeniem modelu relacyjnego jest unikalność encji).
Przykłady encji (i atrybuty w encji):
• Osoba (imię, nazwisko, PESEL)
• Pojazd (wysokość, szerokość, długość, sposób poruszania się)
Charakterystyczną cechą encji jest to, że włącza ona do swojego obszaru znaczeniowego obok obiektów fizycznych również obiekty niematerialne. Encja może stanowić pojęcie, fakt, wydarzenie (np. konto bankowe, którego atrybuty to np. numer, posiadacz, dopuszczalny debet itp.; konferencja, której atrybuty to np. temat, data, organizator itp.; wypożyczenie książki, z atrybutami np. imię i nazwisko wypożyczającego, numer karty bibliotecznej, data wypożyczenia itp.).
W pewnych kontekstach encja ma znaczenie bliższe tabeli przechowującej dane, a czasem jest utożsamiana z wystąpieniem danego obiektu w tabeli(instancja obiektu).

Na podstawie polskiej wiki, z moimi drobnymi zmianami.

Instancja bazy danych

Instancja bazy danych to byt nadrzędny utożsamiony z oprogramowaniem zarządzającym przetwarzanymi danymi. W przypadku Oracle instancja utożsamiana jest z jedną logiczną bazą danych. Instancja bazy danych Oracle składa się ze struktur pamięciowych, do których dostęp mają wszystkie procesy ją obsługujące oraz ze struktur prywatnych, dostępnych tylko dla procesów, które te struktury za-alokowały.
Można powiedzieć że Instancja Oracle składa się z struktur pamięciowych i procesów systemu operacyjnego obsługujących bazę danych. W przypadku SQL Server Instancja może obsługiwać wiele logicznych baz danych. Podobnie jak w SQL Server również MySQL pozwala na przechowywanie wielu logicznych baz danych. Konsekwencją takiego podejścia wspomnianych RDBMS jest możliwość zarządzania uprawnieniami i polityką kopii bezpieczeństwa na nieco innym poziomie (logiki danych) niż w przypadku Oracle.
W kontekście zbiorów danych instancją obiektu możemy nazwać jego wystąpienie. W przypadku baz danych dość częstym przypadkiem(niekoniecznie prawidłowym) jest fakt zapisu tego samego obiektu w różnych stanach(instancjach) mimo iż poprawność logiczna danych jest zachowana na poziomie jednostkowym może ona później zaburzać procesy analityczne.

Rodzaje baz danych – podział ze względu na model danych

Istnieje wiele różnych rodzajów baz danych i klasyfikacji ich podziału, jednakże najistotniejszym wydaje się rozróżnienie ze względu na model danych. Poniżej zostały opisane najważniejsze z nich [Beynon-Davies 2003].

Relacyjny model danych
Niezwykłość relacyjnego modelu danych polega na tym, że swoje powstanie zawdzięcza głównie jednej osobie – E.F. Coddowi. W 1970 r. Codd opublikował fundamenty dla najbardziej popularnego ze współczesnych modeli danych. Od 1968 do 1988 r. Codd opublikował ponad 40 prac na temat relacyjnego modelu danych. Codd traktuje swoje prace wydane przed 1979 r. jako pierwszą wersję relacyjnego modelu danych [Codd, 1990]. Na początku 1979 r. na konferencji Australian Computer Society Codd przedstawił pracę pod tytułem Extending the Relational Database Model to Capture More Meaning. Rozszerzoną wersję relacyjnego modelu danych, którą sformułował w jednej z swojej prac, Codd nazwał RM/T (T od Tasmania). Na początku 1990 r. Codd opublikował książkę pod tytułem The Relational Model for Database Management: Version 2. Jednym z powodów opublikowania książki, na który zwraca uwagę Codd, jest fakt, iż uważa on, ze wielu producentów produktów bazodanowych powołujących się na relacyjny model danych nie rozumie implikacji zawartych nie tylko w modelu RM/T, ale również w pierwszej wersji relacyjnego modelu danych [Beynon-Davies 2003].
Relacyjny model zakłada, iż jest potrzebna tylko jedna struktura danych – relacja.
W związku z tym, że pojęcie relacji jest matematyczną konstrukcją, relacja jest tabelą, dla której jest spełniony następujący zbiór zasad
1. Każda relacja w bazie danych ma jednoznaczną nazwę.
2. Każda kolumna w relacji ma jednoznaczną nazwę w ramach jednej relacji.
3. Wszystkie wartości w kolumnie muszą być tego samego typu. Mówimy, że są one zdefiniowane na tej samej dziedzinie.
4. Porządek kolumn w relacji nie jest istotny.
5. Każdy wiersz w relacji musi być różny. Innymi słowy, powtórzenia wierszy nie są dozwolone w relacji.
6. Porządek wierszy nie jest istotny.
7. Każde pole leżące na przecięciu kolumna/wiersz w relacji powinno zawierać wartość atomową. To znaczy, że zbiór wartości nie jest dozwolony na jednym polu relacji.

Każda relacja musi mieć klucz główny. Dzięki temu możemy zapewnić, niepowtarzalność wierszy w relacji. Klucz główny to jedna lub więcej kolumn tabeli, w której wartości jednoznacznie identyfikują każdy wiersz w tabeli [Beynon-Davies 2003].
W każdej relacji może istnieć wiele kluczy kandydujących, czyli kolumna lub zbiór kolumn, które mogą występować jako jednoznaczny identyfikator wierszy w tabeli. Klucz główny jest wybierany ze zbioru kluczy kandydujących [Beynon-Davies 2003].
Każdy klucz kandydujący, a więc także klucz główny, musi mieć dwie właściwości.
Po pierwsze być jednoznaczny i nie może mieć wartości „null” – specjalnego znaku wskazującego na brakujące lub niepełne dane. Następnie, z definicji każdy klucz kandydujący musi być jednoznacznym identyfikatorem. Stąd też, nie może być żadnych powtarzających się układów wartości w kolumnach kluczy kandydującego lub głównego. Po wtóre, wartość klucza głównego musi być określona dla każdego wiersza w tabeli. Innymi słowy,
w kolumnie lub kolumnach klucza głównego nie może wystąpić wartość „null” (oznaczająca brak wartości) [Beynon-Davies 2003].
Podstawową jednostką danych w relacyjnym modelu danych jest element, na przykład numer pracownika (244), nazwisko wykładowcy (S. Kowalski) lub data urodzenia studenta (1/7/1984). Mówimy, że takie elementy są nierozkładalne lub atomowe. Zbiór takich elementów danych tego samego typu nazywamy dziedziną. Na przykład dziedziną numerów pracowników jest zbiór wszystkich możliwości numerów pracowników. Dziedzinami są więc zbiory wartości, z których pochodzą elementy pojawiające się w kolumnach tabeli
[Beynon-Davies 2003].
Klucze obce łączą dane przechowywane w różnych tabelach. Klucz obcy jest kolumną lub grupą kolumn z jednej tabeli, która czerpie swoje wartości z tej samej dziedziny co klucz główny tabeli powiązanej z nią w bazie danych. W systemach relacyjnych wprowadzamy specjalną wartość, aby wskazać niepełną lub nieznaną informację – wartość „null”.
Ta wartość, różna od zera i spacji, jest szczególnie użyteczna przy powiązaniu kluczy głównego i obcego [Beynon-Davies 2003].
Pojęcie wartości null nie jest jednak do końca akceptowalne. Codd utrzymuje, że wprowadzenie wartości null do systemu relacyjnego zmienia logikę dwuwartościową (prawda, fałsz) na trójwartościową (prawda, fałsz, nieznane). W logice dwuwartościowej, jeżeli zdanie jeden jest prawdziwe i zdanie dwa jest prawdziwe, to ich połączenie spójnikiem „i” jest również prawdziwe. W logice trójwartościowej, jeżeli zdanie 1 jest prawdziwe,
a zdanie 2 ma wartość nieznaną, to ich połączenie spójnikiem „i” ma wartość nieznaną. Wprowadza to dodatkowe komplikacje przy przetwarzaniu zapytań. Niektórzy komentatorzy (np. Chris Date) twierdzą, że jest to zbędne [Beynon-Davies 2003]. Moim zdaniem dobrze zaprojektowana baza danych minimalizuje wystąpienia wartości nieokreślonej lub nawet ją wyklucza. Ewentualnie obsługa null jest przemyślana w sposób całkowicie zgodny
z implementacją dostawcy systemu bazodanowego obsługującego projektowaną bazę co
z kolei sprowadza się do wyboru dostawcy na wczesnym etapie projektowania bazy.
W przeciwnym wypadku baza jest narażona na utratę spójności właśnie przez następstwa logiki trójwartościowej. Może dojść także do sytuacji iż mimo spójności danych w bazie wyniki zapytań do bazy będą niespójne.
Kiedy Codd na początku zaproponował relacyjny model danych, najwięcej uwagi poświęcał wyszukiwaniu danych, które jest wykonywane przy pomocy operatorów znanych jako algebra relacyjna [Beynon-Davies 2003].
Algebra relacyjna jest zbiorem ośmiu operatorów. Każdy operator bierze jedną lub więcej relacji jako argument i produkuje jedną relację jako wynik. Trzema głównymi operatorami algebry relacyjnej są: restrykcja, rzut i złączenie. Dzięki tym trzem operatorom możemy wykonać większość operacji na danych wymaganych od systemu relacyjnego.
Dodatkowe operatory – iloczyn, suma, przecięcie, różnica i iloraz – opierają się na tradycyjnych operatorach teorii zbiorów. W relacyjnym modelu danych istnieją dwa rodzaje wewnętrznych reguł integralności: integralność encji i integralność referencyjna. Są one wewnętrzne, ponieważ każda relacyjna baza danych musi wykazywać oba aspekty integralności [Beynon-Davies 2003].
Integralność encji dotyczy kluczy głównych. Jest ona również regułą integralności, która mówi, że każda tabela musi mieć klucz główny oraz że kolumna lub kolumny wybrane jako klucz główny powinny być jednoznaczne i nie zawierać wartości null. Bezpośrednią konsekwencją reguły integralności encji jest fakt, że w tabeli są zabronione powtórzenia wierszy. Jeżeli każda wartość klucza głównego musi być różna, to w tabeli nie może się pojawić żaden powtarzający się wiersz. Integralność encji jest definiowana przez dodanie do definicji schematu klauzuli klucza głównego [Beynon-Davies 2003].
Integralność referencyjna dotyczy kluczy obcych. Reguła integralności referencyjnej mówi, że każda wartość klucza obcego może się znajdować tylko w jednym z dwóch stanów. Normalnie wartość klucza obcego odwołuje się do wartości klucza głównego w tabeli w bazie danych. Czasami wartość klucza obcego może być null i fakt ten zależy od zasad związanych z przedsięwzięciem. W tym wypadku jawnie stwierdzamy, że nie ma związku
z reprezentowanymi obiektami w bazie danych albo że ten związek jest nieznany
[Beynon-Davies 2003]. Jednakże dzisiejesze implementacje modeli relacyjnych jawnie dopuszczają sytuację, w której wartość klucza będzie spoza zbioru wartości klucza głównego. Jest to sytuacja niebezpieczna i moim zdaniem powinna być eliminowana. Wyobraźmy sobie sytuację, w której definiujemy informacje np. o studentach. Wówczas kluczem obcym
w tabeli studentów niech będzie informacja z identyfikatorem miasta, z którego pochodzi student. W sytuacji gdy projektant bazy zezwoli na wykroczenie klucza obcego ze zbioru klucza głównego np. poprzez usunięcie danej miejscowości z bazy, otrzymamy bazę w stanie niespójnym, mało tego zezwolimy aby ta niespójność została usunięta i wprowadzi ona bazę w stan, w którym jawnie i w świetle prawa baza zwróci informację fałszywą jako prawdziwą. Wystarczy tylko wprowadzić inne miasto, które otrzyma taki sam identyfikator jak to usunięte. W ten o to sposób student urodzony w Krakowie w naszej bazie mógł zmienić miejsce swoich narodzin. Niespójność taka jest bardzo trudna do wykrycia i może powodować kaskodową eskalację problemu. Problemem w takiej sytuacji jest także przywrócenie systemu do stanu poprawnego. W momencie gdy zostanie wprowadzone nowe miasto np. Poznań i otrzyma ono identyfikator Krakowa, po dodaniu nowych studentów urodzonych w Poznaniu powstanie problem odróżnienia ich od tych, którzy zostali urodzeni w Krakowie.
Utrzymanie integralności referencyjnej nie ogranicza się do określenia, czy klucz obcy może mieć wartość null, czy nie. Obejmuje ono również określenie więzów propagacji, które określają, co powinno się stać z powiązaną tabelą, gdy modyfikujemy wiersz lub wiersze
w docelowej tabeli [Beynon-Davies 2003].
Dla każdego związku między tabelami w naszej bazie danych powinniśmy określić, jak mamy postępować z usuwaniem docelowych i powiązanych kartotek. Na przykład, jeżeli usuniemy wiersz z tabeli w bazie danych, to musimy zdecydować, co powinno się stać
z powiązanymi wierszami w tabeli korzystającej z klucza obcego wskazującego na tabele,
w której usuwamy wiersz.
Są trzy (a właściwie cztery) możliwości:
1. Ograniczone usuwanie (ang. restricted delete). Jest to ostrożne podejście. Oznacza to, że zabraniamy usunąć wiersz np. z danymi wykładowcy dopóty, dopóki nie będą usunięte wszystkie wiersze informacji o zajęciach prowadzonych przez tego wykładowcę.
2. Kaskadowe usuwanie (ang. cascades delete). Jest to ufne podejście. Jeżeli usuwamy wiersz np. nagłówka dokumentu, to są jednocześnie usuwane wszystkie powiązane
z nim pozycje tego dokumentu.
3. Wstaw null przy usuwaniu (ang. nullifies delete). Jest to wyważone podejście. Jeżeli usuwamy wiersz wykładowcy, to numery pracowników w powiązanych wierszach przedmiotów ustawiamy na null [Beynon-Davies 2003].
4. Istnieje także możliwość wymuszenia braku akcji (ang. no action). Jest to podejście wysoce nie rozważne, co uargumentowałem we wstępie do integralności referencyjnej. Jeżeli usuniemy wiersz klucza głównego (wykładowcy) to wartości klucza obcego
(np. prowadzonych przez niego przedmiotów nie ulegną zmianie).

Za pomocą wewnętrznej integralności nie możemy wyrazić wszystkich aspektów integralności należących do konkretnej aplikacji. Oznacza to, że są wymagane inne mechanizmy, aby wyrazić inne postacie integralności Do schematu relacji możemy dodać aspekty dodatkowej integralności przez dołączenie ciągu definicji więzów. Takie definicje mogą być zapisane w postaci wyrażeń algebry relacyjnej lub rachunku relacyjnego. Na przykład, chociaż możemy zapewnić, aby każdy wykładany przedmiot miał przypisanego do niego wykładowcę (przez umieszczenie przy kluczu obcym identyfikatora wykładowcy klauzuli not null), nie możemy za pomocą więzów wewnętrznych wyrazić faktu, że każdy wykładowca ma obowiązek prowadzenia przynajmniej jednego przedmiotu
[Beynon-Davies 2003].

Hierarchiczny model danych
Hierarchiczny model danych nie ma takiej samej jednolitości oraz teoretycznej podstawy jak model relacyjny. Można powiedzieć, że ten model danych został opracowany
w wyniku analizy istniejącej implementacji. Prawdopodobnie najbardziej wyróżniającym się DBMS, odpowiadającym hierarchicznemu podejściu, jest IMS (ang. Information Management System) firmy IBM [Beynon-Davies 2003].
Hierarchiczny model danych używa dwóch struktur, którymi są: typy rekordów
i związek a właściwie relacja nadrzędny-podrzędny. Typ rekordu jest określoną strukturą danych, złożoną ze zbiorów nazwanych pól, np. ID_Student i Nazwisko_Studenta. Każde pole jest używane do przechowywania prostego atrybutu i jest mu przyporządkowany typ danych. Powiązanie nadrzędny-podrzędny jest związkiem jeden do wielu między dwoma typami rekordów. Typ rekordu po stronie ‘jeden’ związku jest nadrzędnym typem rekordu, takim jak kierunek studiów; rekord po stronie ‘wiele’ jest podrzędnym typem rekordu, takim jak przedmiot. Schemat hierarchiczny jest złożony z wielu typów rekordów, powiązanych ze sobą za pomocą związków nadrzędny-podrzędny [Beynon-Davies 2003].
Istnieje wiele wewnętrznych więzów integralności w modelu hierarchicznym, które są obecne zawsze, gdy tworzony jest schemat hierarchiczny. Najważniejsze z nich to:
1. Nie mogą istnieć żadne wystąpienia rekordów, z wyjątkiem rekordu korzenia (najwyższego w hierarchii), bez powiązania z odpowiednim wystąpieniem rekordu nadrzędnego. Dlatego też nie można wstawić rekordu podrzędnego dopóty, dopóki nie zostanie powiązany
z rekordem nadrzędnym, oraz że usunięcie rekordu nadrzędnego powoduje automatyczne usunięcie wszystkich powiązanych z nim rekordów podrzędnych.
2. Jeżeli podrzędny typ rekordu ma związane dwa lub więcej nadrzędnych typów rekordów, to rekord podrzędy musi zostać powielony dla każdego rekordu podrzędnego
[Beynon-Davies 2003].
Sieciowy model danych
Pod względem hierarchicznym sieciowy model danych jest używany przez wiele osób za następcę hierarchicznego modelu danych. W latach siedemdziesiątych większość komercyjnych DBMS przeszła, aczkolwiek bez zachowania pełnej zgodności, na sieciowy model danych. Ostatnim istotnym zdarzeniem dotyczącym sieciowego modelu danych było zarekomendowanie w 1986 r. przez organizację ANSI języka definicji sieciowych
(ang. Network Definition Language; NDL) [Beynon-Davies 2003].
Integralność w modelu sieciowym dotyczy głównie określenia członkostwa w kolekcji i trybu wstawiania. Członkostwo w kolekcji musi być oznaczone, jako wymagane lub opcjonalne. Jeśli status jest ustawiony na wymagane, to system spowoduje, że każde wystąpienie rekordu członka będzie wystąpieniem danej kolekcji. Dla członków kolekcji jest predefiniowany tryb wstawiania. Jeśli tryb wstawiania jest ustawiony na ręczny, to programy użytkowe muszą wstawiać rekordy członków do określonego wcześniej wystąpienia konkretnej kolekcji. Jeśli tryb wstawiania jest automatyczny, to, gdy jest tworzony rekord członka, jest on automatycznie wstawiany do bieżącego wystąpienia danej kolekcji
[Beynon-Davies 2003].

Baza danych – definicja, informacje teoretyczne

Baza danych jest pewnym modelem wycinka rzeczywistości w danej organizacji
(np. firmie, uczelni). Tę rzeczywistość nazywamy obszarem analizy (ang. Uniwerse Of Discourse, UOD) [Beynon-Davies 2003].
Bazę danych możemy uważać za zbiór danych (faktów), których zadaniem jest reprezentowanie określonego UOD. Jednostka danych, jest symbolem, którego używamy, aby reprezentować jakąś rzecz. Chcąc by fakty były użyteczne, muszą być one zinterpretowane. Dane zinterpretowane to informacje. Natomiast informacje to dane w otoczeniu (kontekście) nadającym im znaczenie. Zbiór faktów lub predykatów na temat obszaru analizy tworzą bazę danych. Zazwyczaj fakty negatywne, np. które przedmioty nie są zaliczane przez studenta, nie są przechowywane [Beynon-Davies 2003].
W ściśle określonej chwili baza danych znajduje się w pewnym stanie. Stan oznacza zbiór faktów, które są prawdziwe w danej chwili. Dlatego też bazę danych uważamy za bazę faktów, która zmienia się w czasie [Beynon-Davies 2003].
Baza danych składa się z części intensjonalnej oraz ekstensjonalnej. Część intensjonalna bazy danych jest zbiorem definicji, które opisują strukturę danych. Z kolei część ekstensjonalna jest łącznym zbiorem danych w bazie danych. Intensjonalną stronę bazy danych nazywamy schematem bazy danych. Tworzenie schematu systemu bazy danych jest
w istocie procesem projektowania bazy danych. Baza danych musi być zaprojektowana. Natomiast proces projektowania bazy danych jest czynnością polegającą na reprezentowaniu klas, atrybutów i związków w bazie danych [Beynon-Davies 2003].

Charakterystyka baz danych

Dane w bazie danych traktowane są, jako trwałe. Przez trwałość rozumiemy, że dane są przechowywane przez pewien przedział czasowy. Ten przedział nie musi być bardzo duży. Termin „trwałość” jest używany do rozróżnienia bardziej trwałych danych od informacji, które są tymczasowe. Dlatego dane dotyczące pacjentów, pracowników czy studentów są zwykle uważane za przykłady danych trwałych. Dane wprowadzone przy terminalu, przeznaczone do przetwarzania w programie lub drukowane w postaci raportu, nie są uznane za trwałe, ponieważ po jednym użyciu nie są już dłużej potrzebne [Beynon-Davies 2003].
Chcąc uznać, iż baza danych ma właściwość integralności, musi zawierać dokładne odbicie obszaru analizy. Proces zapewnienia integralności jest jednym z podstawowych zadań systemu zarządzania danymi. Integralność oznacza zapewnienie, że baza danych daje poprawne odpowiedzi na zadane pytania. Jest ważną sprawą, ponieważ większość baz danych jest projektowana z myślą o zmianach zachodzących w trakcie ich używania. Innymi słowy, dane w bazie danych ulegają zmianie w czasie [Beynon-Davies 2003].
W zbiorze możliwych, przyszłych stanów bazy danych niektóre są poprawne,
a niektóre nie. Każdy poprawny stan stanowi zawartość bazy danych w konkretnym momencie. Integralność jest procesem zapewniającym, że baza danych zmienia się
w przestrzeni, określonej przez stany poprawne. Integralność jest związana z określeniem, czy przejście do kolejnego stanu jest poprawne [Beynon-Davies 2003].
Integralność bazy danych jest zapewniana przez więzy integralności, czyli reguły, które określają, w jaki sposób baza danych ma pozostać dokładnym odbiciem swojego obszaru analizy. Więzy (integralności) dzielimy na dwa główne typy: więzy statyczne i więzy przejść.
Więzy statyczne, czyli „niezmiennik stanu”, używamy do sprawdzania, czy wykonywana transakcja nie zmienia stanu bazy danych w stan niepoprawny. Więzy statyczne to ograniczenie określone na stanie bazy danych. Zapewniają np. unikalność wartości bądź zawieranie wartości w określonym zbiorze [Beynon-Davies 2003].
Więzy przejść są to reguły, które wiążą ze sobą stany bazy danych. Przejście jest zmianą stanu i dlatego może być reprezentowane przez parę stanów. Także są ograniczeniem nałożonym na przejście poprzez zablokowanie możliwości zakończenia transakcji przy próbie wprowadzenia faktów niezgodnych z modelem [Beynon-Davies 2003].
Bazy danych są projektowane tak, aby zminimalizować powtarzanie się danych.
W bazie danych chcemy przechowywać tylko jeden element danych na temat obiektów lub związków między obiektami z naszego obszaru analizy. Idealna baza danych powinna być zbiorem niepowtarzających się faktów. Niestety ze względu na zmiany zachodzące w czasie, w celu zachowania integralności danych (zgodności z obszarem analizy) niektóre informacje muszą zostać zapisane więcej niż jeden raz. Przykładem takiego powielania informacji
w bazie jest nagłówek dokumentu. Należy na nim zapisać identyfikator kontrahenta oraz wszelkie wymagane dane dla danego typu dokumentu. Mimo iż logika tworzenia baz danych sugerowałaby zapisanie samego identyfikatora, to w sytuacji, gdy kontrahent zmieni jakąś składową nagłówka (np. zmieni adres) baza może przejść w stan niespójny. W takiej sytuacji dopuszczamy sytuacje, w której dokument zapisany w bazie danych może być różny od jego wydrukowanej wersji, co jest z kolei niedozwolone. Tak, więc idealna baza danych to nie tylko zbiór niepowtarzających się faktów, ale również zbiór faktów nastawiony na minimalizację powtórzeń pozostający w spójności z obszarem analizy w okresie czasu.
Zdarzenia, które powodują zmianę stanu, są w terminologii baz danych nazywane transakcjami. Transakcja zmienia bazę danych z jednego stanu w kolejny (nowy). Nowy stan jest wprowadzany przez stwierdzenie faktów, które stają się prawdziwe oraz przez zaprzeczenie faktów, które przestają być prawdziwe [Beynon-Davies 2003].
Większość danych jest przechowywana w bazie danych po to, aby spełnić pewne potrzeby związane z organizacją jakiejś struktury. Do wykonywania takiej operacji na bazie danych są potrzebne dwa rodzaje funkcji: aktualizujące i zapytań. Funkcje aktualizujące dokonują zmian danych (przeprowadzają transakcje). Funkcje zapytań wydobywają dane
z bazy danych niedokonując żadnych zmian w strukturze danych. Akcja danej funkcji aktualizującej może spowodować, że warunki innej funkcji aktualizującej staną się prawdziwe. W tym przypadku mówimy, że pierwsza funkcja aktualizująca „wyzwoliła” zmianę stanu. W ten sposób z transakcji „zewnętrznej” możemy uruchomić kaskadowo transakcje „wewnętrzne”.
Drugim podstawowym typem funkcji bazy danych jest funkcja zapytania. Nie modyfikuje ona w żaden sposób bazy danych, ale jest używana głównie do sprawdzania, czy pewien fakt lub grupa faktów jest spełniona w danym stanie bazy danych
[Beynon-Davies 2003].
Każdy system bazy danych musi używać jakiegoś formalizmu reprezentacji. Patrick Henry Winston zdefiniował formalizm reprezentacji, jako zbiór składniowych
i semantycznych konwencji, które umożliwiają opisywanie rzeczy. Składnia reprezentacji określa reguły łączenia symboli w celu kreowania wyrażeń w formalizmie reprezentacji. Semantyka reprezentacji określa, w jaki sposób takie wyrażenia mają być rozumiane, innymi słowy, w jaki sposób wprowadza się ich znaczenie. W terminologii baz danych idea formalizmu reprezentacji odpowiada pojęciu modelu danych. Model danych dostarcza twórcom baz danych zbioru reguł, za pomocą, których mogą skonstruować system bazy danych. Istnieje wiele różnych modeli danych. Najbardziej powszechny jest relacyjny model danych, który oferuje bardzo elastyczny sposób reprezentowania faktów, ale nie dostarcza łatwego sposobu reprezentowania zawiłości funkcji aktualizujących w systemach baz danych. Obiektowe (post-relacyjne) bazy danych oferują dobrą notację reprezentowania funkcji aktualizujących w systemach baz danych, ale ich dużą wadą jest brak jednolitości dostępnych implementacji [Beynon-Davies 2003]. Należy także zauważyć, iż najpopularniejszy (relacyjny) model danych ze względu na drobne różnice w implementacji u konkretnych dostawców oprogramowania bazodanowego napotyka podobne trudności, co modele post-relacyjne. Skutkuje to dużymi trudnościami przy przenoszeniu logiki bazodanowej pomiędzy dostawcami, a czasem nawet pomiędzy różnymi wersjami oprogramowania tego samego dostawcy.
Baza danych może być używana tylko przez jedną osobę lub jeden system użytkowy. Jednakże w większości przedsiębiorstw wiele baz danych jest używanych przez wielu użytkowników. Korzystanie z wspólnych danych stanowi główną cechę większości systemów baz danych.
Z definicji w bazie danych z wieloma użytkownikami musi istnieć metoda obsługi przypadku, gdy kilka osób lub systemów użytkowych chce uzyskać dostęp do tych samych danych w tym samym czasie. Problem ten nosi nazwę współbieżności
[Beynon-Davies 2003].
Weźmy pod uwagę sytuację, gdy jeden użytkownik rejestruje np. studenta na określonym kierunku studiów. W tej samej chwili inny użytkownik usuwa ze zbioru aktualnie oferowanych kierunków, kierunek na który właśnie jest rejestrowany student. Jest oczywiste, że w tej chwili, gdy pierwszy użytkownik wprowadza fakt rejestracji, drugi użytkownik mógłby zanegować fakt istnienia tego faktu. Baza danych zostałaby w stanie niespójnym.
W takim systemie bazy danych muszą istnieć sposoby radzenia sobie z tego typu sytuacjami
[Beynon-Davies 2003]. Moim zdaniem należy też zwrócić uwagę, iż mechanizmy panowania nad problemem współbieżności implementowane są przez każdego dostawcę inaczej. Dlatego też już na etapie projektowania bazy należy wybrać dostawcę systemu bazodanowego
i uwzględnić dany mechanizm. Nawet subtelne różnice mogą okazać się przeszkodą sprawiającą, że dany system stanie się bezużyteczny dla końcowego użytkownika.