Jacek | 2011-02-19 01:01:41
Zajmiemy się podstawowymi (i nie tylko) funkcjami w bazie MySQL, których jeszcze nie opisałem. Zacznijmy od utworzenia tabeli:
CREATE TABLE `uzytkownicy` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`imie` VARCHAR(255) NOT NULL,
`nazwisko` VARCHAR(255) NOT NULL
)
Od razu można zauważyć kilka elementów, które nie pojawiły się w poprzednim artykule.
Dodanie NOT NULL sprawia, że przy dodawaniu rekordu (INSERT) musimy to pole wypełnić i nie możemy go pominąć. Można za to uzupełnić je wartością pustą: '', ale nie "wartością" NULL.
Pomimo ustawienia NOT NULL, jeśli pominiemy to pole, baza MySQL automatycznie wstawi tu następny wolny numer, począwszy od 1.
Tutaj zaczynają się ciekawsze funkcje bazy danych - indeksy. Bardzo dobrym porównaniem jest spis treści w książce. Aby dotrzeć do danych MySQL nie musi przechodzić przez wszystkie strony, a tylko sprawdzić w indeksie, na której stronie znajduje się szukana wartość. Indeks PRIMARY KEY oznacza, że wybrana wartość, w tym przypadku pole id, jednoznacznie wskazuje na konkretny rekord. Ponieważ indeks ten jest unikalny, dwa rekordy nie mogą mieć identycznego identyfikatora. W danej tabeli nie może być też dwóch indeksów PRIMARY.
Istnieją też inne typy indeksów:
Na potrzeby tego artykułu potrzebna będzie jeszcze jedna tabela:
CREATE TABLE `adresy` (
`uzytkownik` INT NOT NULL,
`adres` VARCHAR(255) NOT NULL,
`kod` CHAR(6) NOT NULL,
`miasto` VARCHAR(255) NOT NULL,
INDEX (`uzytkownik`),
INDEX (`miasto`, `uzytkownik`)
)
I kolejne dodatkowe informacje:
VARCHAR(n) pozwala na przechowywanie zmiennej liczby znaków, ale nie więcej niż n. CHAR(n) zawsze przechowuje dokładnie n znaków. Jeśli podamy ich mniej, to baza dopełni wartość zerami (dokładniej znakiem NUL). Przy zwracaniu wartości dodane zera są usuwane.
Składnia INDEX (`nazwa_pola`) to po prostu inny sposób zapisu indeksu. W pierwszym przykładzie usuwając PRIMARY KEY z drugiej linii i dodając po:
`nazwisko` VARCHAR(255) NOT NULL
przecinek, a po nim (najlepiej w nowej linii):
PRIMARY KEY (`id`)
uzyskalibyśmy identyczną tabelę.
Istnieje możliwość tworzenia indeksu dla więcej niż jednego pola. W tym wypadku musimy skorzystać z tej właśnie składni:
INDEX (`pole1`, `pole2`)
Indeks taki zachowuje się tak, jakby indeksował jedno pole, które składa się z połączonych w podanej kolejności wartości wskazanych pól.
Tu już bez niespodzianek:
INSERT INTO `uzytkownicy`
(`imie`, `nazwisko`)
VALUES
('Jan', 'Kowalski'),
('Adam', 'Nowak');
Tabela wygląda teraz tak:
SELECT * FROM `uzytkownicy`
/----------------------\\ | id | imie | nazwisko | |----|------|----------| | 1 | Jan | Kowalski | | 2 | Adam | Nowak | \\----------------------/
Jeszcze trochę danych:
INSERT INTO `adresy`
(`uzytkownik`, `adres`, `kod`, `miasto`)
VALUES
('1', 'Akacjowa 100', '28-133', 'Pacanów'),
('1', 'Bajkowa 6', '29-100', 'Włoszczowa'),
('1', 'Cicha 18', '14-530', 'Frombork'),
('2', 'Jasna 21', '29-100', 'Włoszczowa');
Zajmiemy się jedną z relacji - jeden do wielu. Jeden użytkownik może mieć kilka adresów, jednak każdy adres należy do jednego, konkretnego użytkownika. Spróbujmy wykorzystać dane z bazy:
SELECT imie, nazwisko
FROM uzytkownicy
LEFT JOIN adresy
ON (`uzytkownicy`.`id` = `adresy`.`uzytkownik`)
WHERE `miasto` = 'Włoszczowa'
Poproszę o imię i nazwisko (SELECT imie, nazwisko) z tabeli użytkownicy (FROM uzytkownicy). Proszę dołączyć tabelę adresy (LEFT JOIN adresy) tak, by pole `id` było równe polu `uzytkownik` (ON (warunki)). A teraz chcę tylko rekordy z `miasto` = 'Włoszczowa' (WHERE ...).
Tak zapytanie wygląda. MySQL dokonuje kilku sztuczek z indeksami, by zapytanie było wykonywane optymalniej i szybciej:
W celu sprawdzenia, czy MySQL zachowuje się tak jak chcemy i korzysta z indeksów, co jest szczególnie ważne przy dużej ilości danych, wykonujemy zapytanie:
EXPLAIN SELECT imie, nazwisko
FROM uzytkownicy
LEFT JOIN adresy
ON (`uzytkownicy`.`id` = `adresy`.`uzytkownik`)
WHERE `miasto` = 'Włoszczowa'
Zwróci ono taką "tabelkę" z wynikiem:
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | adresy | ref | uzytkownik,miasto | miasto | 257 | const | 2 | Using where; Using index |
1 | SIMPLE | uzytkownicy | eq_ref | PRIMARY | PRIMARY | 4 | test.adresy.uzytkownik | 1 |
Wiemy ile "prostych" zapytań wykonał MySQL (2), jakich indeksów próbował użyć (są to nazwy - zobacz np. w phpMyAdmin), i czy faktycznie ich użył (świadczy o tym tekst "Using index" w sekcji Extra).
EXPLAIN to bardzo użyteczne narzędzie do optymalizowania zapytań. Dokładne informacje na temat zwracanych wartości dostępne są w dokumentacji bazy MySQL.
SELECT imie, nazwisko
FROM adresy, uzytkownicy
WHERE `uzytkownicy`.`id` = `adresy`.`uzytkownik`
AND `miasto` = 'Włoszczowa'
Tak! Powyższe zapytanie zachowa się tak samo jak opisany powyżej LEFT JOIN.
Jesze jeden przykład:
SELECT imie, nazwisko
FROM uzytkownicy
WHERE `id` IN (
SELECT `uzytkownik`
FROM adresy
WHERE `miasto` = 'Włoszczowa'
)
Trzeba jednak zauważyć (EXPLAIN), że zapytanie to nie będzie optymalne i (najprawdopodobniej) MySQL przeszuka całą tablicę uzytkownicy.
O bazach danych i SQL można pisać długo - istnieje więc niezerowe prawdopodobieństwo, że pojawi się kolejna część artykułu. Niecierpliwych odsyłam do przepastnej dokumentacji: SELECT, JOIN, optymalizowanie zapytań SELECT.
© by Jacek Kowalski Sponsor: poszukiwany