Pułapki języka SQL • O czym będę mówił: – – – – – Co to jest SQL? Historia SQL Dlaczego mówię o SQL a nie o OQL? Standardy SQL Dane numeryczne w SQL • Numeryczne typy danych i ich konwersja (zaokrąglanie i obcinanie) • Konwersja typów znakowych • Czterofunkcyjna matematyka – Brakujące dane w SQL • Wartości NULL zawsze oznaczają kłopoty – Optymalizacja zapytań • Optymalizacja sprzętowa • Optymalizacja programowa . Pułapki języka SQL - Maciej Kuske - Styczeń 2 Pułapki języka SQL • Nie będę mówił o: – projektowaniu baz danych • DDL Database Definition Language – podstawach matematycznych modelu relacyjnego – normalizacji – szczegółach • nie jest to kurs programowania • chciałbym aby ten wykład zasygnalizował pewne problemy które możemy napotkać w SQL • chciałbym podać niektóre przykłady ich rozwiązywania . Pułapki języka SQL - Maciej Kuske - Styczeń 3 Co to jest SQL ? • Structured Query Language: – Strukturalny Język Zapytań – Język zarządzania relacyjną bazą danych • Sposób działania: – Jest opisem przedmiotu naszych żądań - system samodzielnie rozpracowuje sposób ich spełnienia – Nie posiada instrukcji wejścia i wyjścia – Nie jest językiem proceduralnym (operacje na danych) . Pułapki języka SQL - Maciej Kuske - Styczeń 4 Język proceduralny • Język proceduralny jest szczegółowym opisem sposobu realizowania zadania i jednorazowo operuje na jednym rekordzie lub jednej jednostce danych. Tego rodzaju języki posiadają również nazwę 3GL (3-rd generation languages). Są to znane języki programowania, do których należą Fortran, Cobol, BASIC, ADA oraz Pascal. Kiedy te języki operują na danych, wykorzystują pliki o następujących właściwościach: – 1. Dane są przechowywane w plikach wierszy danych. Aby można było wykorzystać plik, programista musi znać jego lokalizację fizyczną, lokalizację logiczną oraz strukturę. – 2. Program jest wyposażony w informacje potrzebne do odczytu pliku i uzyskuje jednorazowo dostęp do jednego wiersza danych. – 3. Struktura wierszy danych jest zdefiniowana w obrębie każdego programu. – 4. Kolejność wierszy danych w obrębie pliku ma istotne znaczenie. – 5. Istotne znaczenie posiada kolejność danych w obrębie wiersza. – 6. Wiersze mogą być złożonymi strukturami danych. . Pułapki języka SQL - Maciej Kuske - Styczeń 5 Język nieproceduralny • Jest opisem przedmiotu naszych żądań; system samodzielnie rozpracowuje sposób ich spełnienia. Nie jest uważany za język przeznaczony dla użytkownika końcowego; nie posiada instrukcji wejścia i wyjścia, zatem musi być wykorzystywany za pomocą języka nadrzędnego, który obsługuje te funkcje. Operując na danych, SQL modeluje rzeczywistość za pomocą tabel, posiadających następujące właściwości. – 1. Dane są przechowywane w bazie danych utworzonej z tabel; tabele te mogą być tabelami rzeczywistymi lub wirtualnymi. Użytkownicy są połączeni z całą bazą danych, a nie z poszczególnymi tabelami. – 2. Program żąda od SQL-a zwrócenia danych, nie zajmując się wcale fizyczną strukturą ani lokalizacją danych. – 3. Struktury tabel są zdefiniowane w obrębie tej bazy danych, a nie w obrębie każdego programu. – 4. Nie ma znaczenia kolejność tabel w bazie danych. Są one identyfikowane przez nazwy. – 5. Kolejność kolumn w tabeli nie jest istotna. Są one identyfikowane przez nazwy. – 6. Kolejność wierszy w obrębie tabeli nie ma znaczenia. Są one identyfikowane przez wartości w obrębie ich kolumn (klucze). – 7. Dane są zawsze przedstawiane użytkownikowi jako tabele, niezależnie od wewnętrznej struktury stosowanej przez konkretną bazę danych. . Pułapki języka SQL - Maciej Kuske - Styczeń 6 Historia SQL-a • Powstał z języka Sequel w laboratoriach firmy IBM na początku lat siedemdziesiątych • Pierwszy SZBD to „System R” (IBM) -1973r. • Publikacje IBM-a 1973-1979r. • Pierwsze komercyjne zastosowanie 1977r. - Oracle • Standardy SQL-a: – – – – 1987r. - pierszy standard ISO 1989r. - drugi standard ISO (SQL-89) 1992r. - trzeci standard ISO (SQL2) ……. - SQL3 z uwzględnieniem cech obiektowych • Dla porównania wersja 1.1 ODMG-93 wersja 1.1 (grudzień 1993) . Pułapki języka SQL - Maciej Kuske - Styczeń 7 Dlaczego mówię o SQL a nie o OQL? • Dlaczego używamy relacyjnych baz danych: – bardzo duża popularność i pozornie prosta budowa języka SQL – istniejące implementacje systemów informatycznych realizowanych w oparciu o technologie relacyjnych baz danych – łatwa przenaszalność kodu SQL, niezależność od platform, szeroka gama sterowników ODBC, JDBC i inne. • Dlaczego nie chcemy używać obiektowych baz danych: – brak jednolitego standardu dla obiektowych baz danych • SQL3 • ODMG, CORBA – wysokie koszty implemetacji systemów obiektowych baz danych – brak wiązań do języków programowania . Pułapki języka SQL - Maciej Kuske - Styczeń 8 Standardy SQL-a • Obecnie obowiązują dwie normy ANSI/ISO: SOL-89, SQL-92 • SQL-92 to trzy poziomy zgodności: wstępny, pośredni i pełny • Istniejące ciała normalizacyjne: – ANSI (American National Standard Institute) • W szczególności Komisja ANSI X3H2 ds. standardów baz danych – ISO (International Standard Organization) – NIST (Notional Institute Standards and Technology) • Opracował: FIST (Federalne Standardy Przetwarzania Informacji) – SQL/Access Group • Przyłączalność różnych systemów baz danych – X/Open • Przenaszalność kodu pomiędzy różnymi bazami danych . Pułapki języka SQL - Maciej Kuske - Styczeń 9 Dane numeryczne Numeryczne typy danych: – Bardzo obszerny zakres numerycznych typów danych – Idea zapewnienia każdemu językowi nadrzędnemu (bazowemu) numerycznego typu danych SQL-a, który odpowiadałby jednemu z jego własnych typów danych – Pośród tych typów danych można znaleźć kilka typów stanowiących rozszerzenia producenta oprogramowania. • Np.: MONEY jako rozszeżenie DECIMAL lub NUMERIC – Dzielą się na dokładne (NUMERIC, DECIMAL, INTEGER) i przybliżone (FLOAT(P), REAL, DOUBLE PRECISION) . Pułapki języka SQL - Maciej Kuske - Styczeń 10 Konwersja numerycznych typów danych • Kiedy ma miejsce ? • Metody konwersji (niestety, zależne od implementacji): – zaokrąglanie (na podstawie usuwanej liczby): • Metoda naukowa - jeśli ta cyfra jest równa 0, l, 2, 3 lub 4, zostaje usunięta, a cyfra wyższego rzędu po jej lewej stronie pozostaje bez zmiany. Gdy ta cyfra jest równa 5, 6, 7, 8 lub 9, zostaje usunięta, a sąsiednia cyfra po lewej stronie ulega zwiększeniu o jeden. • Metoda handlowa - jak wyżej ale w przypadku, gdy cyfra równa 5, możemy zechcieć zastosować jakąś regułę, dzięki której nastąpi zaokrąglenie w górę w połowie przypadków. Jedna z takich reguł polega na analizie najbliższej sąsiedniej cyfry po lewej stronie. Jeśli cyfra jest nieparzysta, pozostanie niezmieniona. Gdy jest parzysta, nastąpi jej zwiększenie. – obcinanie • zdefiniowane jako obcinanie w kierunku zera; tzn. wartość 1,5 -> 1, a -1,5-> -1. • Nie jest to prawdą w przypadku wszystkich języków programowania; wszystkie są zgodne jedynie w kwestii obcinania liczb dodatnich w kierunku do zera, ale może się okazać niespodziewanie, że liczba -1,5 zostanie obcięta do wartości -2. . Pułapki języka SQL - Maciej Kuske - Styczeń 11 Konwesja znakowych typów danych • Kiedy ma miejsce ? – Ma miejsce przy operacjach poównania, zapisywania w bazie danych, aktualizacji danych - wtedy gdy np.: porównywane łańcuchy znakowe są różnych typów. • W jaki sposób jest realizowana ? – Jeżeli porównujemy wartość typu CHAR(4) np.: „ABCD” z CHAR(8) np.: „ABCDEFG” to pierwsza wartość zostanie uzupełniona znakami pustymi z prawej strony (do 8 znaków). • Niespodzianki – W przypadku porównania łańcuchy 'Smith' oraz 'Smith końcowymi) są równe. ' (z trzema spacjami – W przypadku predykatu LIKE nie następuje uzupełnianie i rezultatem będzie FALSE. . Pułapki języka SQL - Maciej Kuske - Styczeń 12 Czerofunkcyjna matematyka • SQL posiada możliwości rachunkowe słabsze od kieszonkowego kalkulatora. Dwuargumentowe operatory +, -, * oraz / reprezentują odpowiednio dodawanie, odejmowanie, mnożenie i dzielenie. • Operatory mnożenia i dzielenia posiadają równy priorytet i są wykonywane przed dwuargumentowymi operatorami plus i minus. Dopuszczalne jest stosowanie jednoargumentowych operatorów plus i minus. Możemy ich używać, umieszczając je w dowolnej liczbie przed numeryczną wartością zmiennych. Jednak trzeba uważać ponieważ w SQL-u stosuje się także komentarze w stylu języka Ada, gdzie wiersz komentarza wstawia się pomiędzy dwie kreski i znak nowego wiersza. Optymalizacja wyrażeń matematycznych :-) • • – Rozważmy na przykład takie działanie złożone (duża liczba + duża liczba - duża liczba), gdzie duża liczba jest maksymalną wartością, jaką można przedstawić za pomocą jej numerycznego typu danych. Jeśli pogrupujemy wyrażenie w kierunku od lewej strony do prawej, otrzymamy ((duża liczba + duża liczba) - duża liczba) = błąd przepełnienia! Jeśli jednak grupowanie zostanie przeprowadzone od prawej strony ku lewej, otrzymujemy (duża liczba + (duża liczba - duża liczba)) = duża liczba. . Pułapki języka SQL - Maciej Kuske - Styczeń 13 Brakujące dane w SQL • Co to jest NULL ? – Zwyczajny opis wartości NULL mówi, że reprezentuje ona obecnie nieznaną wartość, która w przyszłości może być zastąpiona wartością rzeczywistą, kiedy zdobędziemy brakujące informacje. – W przypadku SQL-a wartość NULL jest jedynym sposobem obsługi brakujących wartości. – NULL jest tworem globalnym, który nie przynależy do żadnego z typów danych, ale jest w stanie zastępować dowolne ich wartości. – W raporcie Interim Report 75-02-08 to the ANSI X3 (SPARC Study Group 1975) przedstawiono 14 różnych rodzajów niepełnych danych, jakie mogą wystąpić w roli wyników działań lub wartości atrybutów. Grupa ta obejmuje takie przypadki, jak arytmetyczny niedomiar i przepełnienie, dzielenie przez zero, obcięcie łańcucha znakowego, podniesienie wartości zero do potęgi zero oraz inne błędy rachunkowe, a także wartości brakujące lub nieznane. – Regułą dla matematyki z udziałem wartości NULL jest to, że wartości te rozprzestrzeniają się. . Pułapki języka SQL - Maciej Kuske - Styczeń 14 Brakujące dane w SQL • Wykonajmy zapytanie zapisane poniżej: SELECT test / 0 FROM Wypelniona_wartosciami_NULL; SELECT test / 0 FROM Wypelniona_Jedynkami; SELECT test / 0 FROM Wypelniona_Zerami; • Przewidywany rezultat to w matematyce błąd ! • Jednak okazuje się, że operacja arytmetyczna z wartością NULL zwraca wartość NULL wyniku. W dodatku wyrażenie (NULL / 0) nie jest spójne dla różnych implementacji SQL-a. • . Pułapki języka SQL - Maciej Kuske - Styczeń 15 Brakujące dane w SQL Produkt NULL/0 Jeden/zero Zero/zero Błąd operacji zmiennoprzecinkowej, brak da-nych Błąd dzielenia przez 0, brak danych Błąd operacji zmiennoprzecinkowej, brak da-nych Błąd dzielenia przez 0, brak danych NULL Błąd dzielenia przez 0, brak danych Ingres 6.4/03 NULL Oracle 6.0/8.0 NULL Progress 6.2 NULL R:BASE 4.0a NULL NULL Błąd dzielenia przez 0, brak danych błąd obcinania podczas wykonania programu wskutek dzielenia przez 0 błąd obcinania podczas wykonania programu wskutek dzielenia przez 0 błąd obcinania podczas wykonania programu wskutek dzielenia przez 0 SQL Server 4.2/7.0 NULL NULL oraz błąd NULL oraz błąd SQL Base 5.1 NULL Plus nieskończoność Plus nieskończoność Sybase 4.9 NULL NULL oraz błąd NULL oraz błąd WATCOM SQL NULL XDB 2.41 NULL NULL Błąd dzielenia przez 0, brak danych NULL Błąd dzielenia przez 0, brak danych RDB . Pułapki języka SQL - Maciej Kuske - Styczeń 16 Brakujące dane w SQL Porównywanie wartości NULL • wartości NULL nie można porównywać z innymi wartościami NULL za pomocą czegoś, co programiści nazywają operatorem porównania (równe, nierówne, mniejsze niż, większe niż itd.) • Jeżeli wykonujemy: SELECT * FROM Jakaś_Tabela WHERE Pewna_Kolumna=2; i następnie wykonujemy: SELECT * FROM Jakaś_Tabela WHERE Pewna_Kolumna<>2; spodziewamy się otrzymać w rezultacie wszystkie wiersze z Jakaś_Tabela. Jednakże oprócz powyższych, należałoby wykonać dodatkowo zapytanie: SELECT * FROM Jakaś_Tabela WHERE Pewna_Kolumna IS NULL; aby uzyskać spodziewany wynik. . Pułapki języka SQL - Maciej Kuske - Styczeń 17 Brakujące dane w SQL • Funkcje agregujące – Funkcja COUNT • Zwraca liczbę wierszy w tabeli. Funkcja zajmuje się wierszami a nie wartościami kolumn więc liczone są także wartości NULL. – Operacje sumowania SUM: • brakujące dane są usuwane przed zliczaniem. – Funkcja AVG: • Jest mniej więcej tym samym co (SUM(x)/COUNT(*)) - różnica polega na tym, że SUM odrzuca puste wartości a COUNT nie ! – Funkcje MIN i MAX • Wartości NULL nie są brane pod uwagę • Zbiór pusty zwraca wartość NULL . Pułapki języka SQL - Maciej Kuske - Styczeń 18 Jak pozbyć się brakujących danych • Odpowiednio skonstruowany schemat bazy danych. Brakujące dane powinny być przesunięte do innych tabel powiązanych z główną. • Dobrym zwyczajem byłoby deklarowanie wszystkich tabel bazowych z ograniczeniami NOT NULL na wszystkich kolumnach, kiedy tylko to możliwe. • Gdy istnieje potrzeba przedstawiania brakujących wartości, należy zaprojektować dla nich schematy kodowania ze stosownymi wartościami. Na przykład, istnieją następujące kody płci ISO: 0 = nieznana, l = męska, 2 = żeńska, 9 = nie dotyczy. • Można stosować łańcuch znakowy typu '9999-99-99 23:59:59.999999’ dla wartości typu 'wieczność' albo 'kres czasu'. (Uwaga na procedury statystyczne!) . Pułapki języka SQL - Maciej Kuske - Styczeń 19 Optymalizacja zapytań • Rodzaje optymalizatorów: – Optymalizator pracujący w oparciu o reguły językowe przegląda składnię zapytania i planuje sposób jego wykonania nie dbając o rozmiary tabel, ani nie uwzględniając rozkładu statystycznego danych. Taki Optymalizator (np. Oracie w wersji wcześniejszej niż 7.0) dokona analizy składni zapytania oraz wykona go w takiej kolejności działań, w jakiej zostało ono napisane, wprowadzając ewentualnie pewną reorganizację zapytania do postaci równoważnej, wykorzystując przy tym pewne reguły składniowe. – Optymalizator, działający w oparciu o koszt przetwarzania, analizuje zarówno zapytanie, jak i dane statystyczne dotyczące samej bazy danych oraz podejmuje decyzje o sposobie najkorzystniejszego wykonania zapytania. Te decyzje obejmują kwestie wykorzystania indeksów, zastosowania kodowania, przeniesienia pewnych tabel do pamięci głównej, doboru metody sortowania itd. . Pułapki języka SQL - Maciej Kuske - Styczeń 20 Optymalizacja zapytań • Metody dostępu – Dostęp sekwencyjny • Skanowanie tabeli polega na sekwencyjnym odczycie wszystkich danych w kolejności, w jakiej występują one w obszarze fizycznym pamięci, pobierając jednorazowo jedną stronę pamięci. Większość baz danych nie usuwa fizycznie wierszy, które zostały skasowane, więc tabela może zajmować sporo fizycznej przestrzeni i zawierać niewiele danych. – Dostęp indeksowy • W przypadku dostępu indeksowego zwracany jest jednorazowo jeden wiersz. – Dostęp mieszający . Pułapki języka SQL - Maciej Kuske - Styczeń 21 Optymalizacja zapytań • Wyrażenia i niezagnieźdżone zapytania – Optymalizator powinien rozpracowywać sytuacje, kiedy dwa zapytania są takie same oraz nie dawać nabierać się, kiedy dwa zapytania mają to samo znaczenie, lecz inną składnię. – Na przykład, standard SQL definiuje zapytanie: SELECT * FROM Magazyn WHERE ilość IN (SELECT ilość FROM Sprzedaż); jako identyczne z następującym: SELECT * FROM Magazyn WHERE ilość = ANY (SELECT ilość FROM Sprzedaż); . Pułapki języka SQL - Maciej Kuske - Styczeń 22 Optymalizacja zapytań • Proste wyrażenia – Dobra reguła praktyczna polega na tym, że dla danego łańcucha predykatów, zawierającego operatory AND i testującego stałe wartości, najpierw należy umieszczać najbardziej restrykcyjne. – Na przykład, zapytanie: SELECT * FROM Studenci WHERE płeć = 'kobieta’ AND ocena = 'A’; będzie prawdopodobnie działać wolniej niż następujące: SELECT * FROM Studenci WHERE ocena = 'A’ AND płeć = 'kobieta’; ponieważ występuje mniej studentów z ocenami „a" niż studentów-kobiet. . Pułapki języka SQL - Maciej Kuske - Styczeń 23 Optymalizacja zapytań • Proste wyrażenia cd. – Na przykład, aby znaleźć kogoś w tabeli Irlandia, kto nie jest katolikiem, napisalibyśmy zapewne: SELECT * FROM Irlandia WHERE religia <> 'Katolik'; Sposób obejścia tego problemu polega na rozłożeniu tej nierówności w następujący sposób: SELECT * FROM Irlandia WHERE religia < 'Katolik’ OR religia > 'Katolik’; i wymuszeniu użycia indeksu. Jednak bez indeksu na kolumnie religia wersja predykatu z OR mogłaby potrzebować więcej czasu na wykonanie. . Pułapki języka SQL - Maciej Kuske - Styczeń 24 Optymalizacja zapytań • Proste wyrażenia cd. – Zamiast wyrażenia: SELECT * FROM Sprzedaż WHERE kod_literowy IS NOT NULL; Lepiej jednak napisać: SELECT * FROM Sprzedaż WHERE kod_literowy > 'AAA'; ponieważ uniknie się dodatkowych odczytów. . Pułapki języka SQL - Maciej Kuske - Styczeń 25 Optymalizacja zapytań • Proste wyrażenia cd. – Zapytanie: SELECT * FROM Studenci WHERE nazwisko LIKE 'Sm_th'; nie będzie wykorzystywać indeksu na kolumnie nazwi sko, jednakże zapytanie: SELECT * FROM Studenci WHERE nazwisko BETWEEN 'Smath' AND 'Smzth' może wykorzystywać indeks na tej kolumnie. . Pułapki języka SQL - Maciej Kuske - Styczeń 26 Optymalizacja zapytań • Nadmiarowość w zapytaniach – Im więcej informacji będzie zawartych w zapytaniu, tym będzie większa szansa, że optymalizator będzie w stanie znaleźć ulepszony plan wykonania zapytania. SELECT * FROM Tabela1, Tabela2, Tabela3 WHERE Tabela2.wspólna_kolumna = Tabela3.wspólna_kolumna AND Tabela3.wspólna_kolumna = Tabela1.wspólna_kolumna; – alternatywne zapytanie: SELECT * FROM Tabela1, Tabela2, Tabela3 WHERE Tabela1.wspólna_kolumna = Tabela2.wspólna_kolumna AND Tabela1.wspólna_kolumna = Tabela3.wspólna_kolumna; – Niektóre Optymalizatory będą wykonywać złączenia par tabel w oparciu o kryteria równozłączenia w klauzuli WHERE w takiej kolejności, w jakiej występują. Załóżmy, że Tabela1 jest bardzo mała, a Tabela2 i Tabela3 są dużymi tabelami. W pierwszym przedstawionym powyżej zapytaniu wykonanie w pierwszej kolejności złączenia Tabela2Tabela3 zwróci duży zbiór wynikowy, który następnie zostanie obcięte przez złączenie Tabelal-Tabela2. . Pułapki języka SQL - Maciej Kuske - Styczeń 27 Optymalizacja zapytań • Nadmiarowość w zapytaniach – W przypadku drugiego zapytania, wykonanie w pierwszej kolejności złączenia Tabela1-Tabela2 zwróci mały zbiór wynikowy, który następnie zostanie dopasowany do małego zbioru wynikowego złączenia Tabela1-Tabela3 – Jednak najlepszym posunięciem jest zapewnienie wyczerpującej informacji, tak aby optymalizator mógł samodzielnie zdecydować, kiedy nastąpią zmiany rozmiarów tabel. Prowadzi to do nadmiarowości w klauzuli WHERE: SELECT * FROM Tabela1, Tabela2, Tabela3 WHERE Tabelal.wspólna_kolumna = Tabela2.wspólna_kolumna AND Tabela2.wspólna_kolumna = Tabela3.wspólna_kolumna AND Tabela3.wspólna_kolumna = Tabela1.wspólna_kolumna; . Pułapki języka SQL - Maciej Kuske - Styczeń 28 Bibliografia • • • Lech Banachowski „Bazy danych” Joe Celko „SQL for Smarties - Advanced SQL Programing” Strony internetowe „DBMS Magazine” . Pułapki języka SQL - Maciej Kuske - Styczeń 29