„Zewnętrzne źródła finansowania przedsięwzięć innowacyjnych”
INDEKSY I SORTOWANIE ZEWNĘTRZNE
description
Transcript of INDEKSY I SORTOWANIE ZEWNĘTRZNE
INDEKSY I SORTOWANIE ZEWNĘTRZNE
Przygotował Lech Banachowski na podstawie: 1. Raghu Ramakrishnan, Johannes Gehrke, Database Management
Systems, McGrawHill, 2000 (książka i slide’y). 2. Lech Banachowski, Krzysztof Stencel, Systemy zarzadzania bazami
danych, Wydawnictwo PJWSTK, 2007.3. Dokumentacja Oracle.
2PJWSTK, L.Banachowski, SZB
Organizacje pliku z danymi
Plik nieuporządkowany Plik uporządkowany (posortowany) Plik haszowany
3PJWSTK, L.Banachowski, SZB
Wyszukiwanie
Najczęściej wykonywaną operacją w bazie danych jest wyszukiwanie danych. W najprostszej postaci: mając konkretną wartość poszukujemy rekordów, w których ta wartość występuje w danym polu.
4PJWSTK, L.Banachowski, SZB
Indeksy Plik nieuporządkowany umożliwia wyszukanie rekordu:
– mając rid rekordu, lub
– przeglądając sekwencyjnie wszystkie rekordy w
pliku.
Często wyszukiwanie na podstawie wartości jednego
lub więcej pól, np.
– wyznacz wszystkich studentów specjalizacji “BD”,
– wyznacz wszystkich studentów mających < 20 lat.
Indeksy są strukturami danych, których celem jest
wspomaganie szybkiego znajdowania odpowiedzi na
takiego rodzaju zapytania.
Takie samo znaczenie jak skorowidz (indeks) w książce!
5PJWSTK, L.Banachowski, SZB
Indeksy
Klucz wyszukiwania dla indeksu
– wybrane pola rekordu względem których ma
odbywać się wyszukiwanie.
Indeks składa się z :– pozycji danych k* określanych względem wartości klucza
wyszukiwania k, oraz z
– pozycji indeksu, kierujących wyznaczeniem właściwej
pozycji danych k* w oparciu o wartość klucza
wyszukiwania.
6PJWSTK, L.Banachowski, SZB
Indeksy
Plik danych – rekordy danych. Plik indeksu – pozycje danych, pozycje indeksu. Indeks wewnętrzny - plik indeksu zawiera w
sobie plik danych. Pozycjami danych k* w indeksie są rekordy danych.
Indeks zewnętrzny – plik indeksu jest rozłączny z plikiem danych. Pozycje danych k* zawierają wskaźniki do rekordów danych. Postacie:1. <k, rid rekordu z tą wartością klucza k> albo <k, lista rid rekordów z tą wartością klucza k >– Ad 2. Postać bardziej zwarta; zmienny format rekordu.
7PJWSTK, L.Banachowski, SZB
Klasyfikacja indeksów
Gdy klucz wyszukiwania zawiera klucz
główny – indeks główny wpp. indeks
niegłówny.
Indeks jednoznaczny - klucz wyszukiwania
zawiera klucz jednoznaczny.
Indeks pogrupowany - indeks wewnętrzny i
plik danych posortowany według wartości
klucza indeksu.
8PJWSTK, L.Banachowski, SZB
Indeks pogrupowany
Pozycje danych (czyli rekordy danych) są zapisane w kolejności uporządkowanej względem wartości klucza indeksu. W rezultacie, rekordy o tej samej wartości klucza lub zbliżonej znajdują się na tej samej stronie lub na kilku powiązanych.
9PJWSTK, L.Banachowski, SZB
Indeksy wewnętrzne i zewnętrzne
Indeks wewnętrzny haszowany = indeks wewnętrzny i plik danych haszowany.
Indeks wewnętrzny ->– Plik danych posortowany i indeks pogrupowany,
albo– Plik danych haszowany i indeks haszowany.
Indeks zewnętrzny ->– Plik danych nieuporządkowany , albo– Plik danych posortowany , albo– Plik danych haszowany.
10PJWSTK, L.Banachowski, SZB
Złożone klucze wyszukiwania
Złożone klucze wyszukiwania: kombinacja pól np. <sal,age>.– Zapytanie równościowe:
age=20 and sal =75– Zapytanie zakresowe:
age < 20; age=20 and sal > 10 Porządek leksykograficzny.
sue 13 75
bob
cal
joe 12
10
20
8011
12
name age sal
<sal, age>
<age, sal> <age>
<sal>
12,20
12,10
11,80
13,75
20,12
10,12
75,13
80,11
11
12
12
13
10
20
75
80
Rekordy danychposortowane <name>
Pozycje danychposortowane <sal,age>
Pozycje danychposortowane <sal>
11PJWSTK, L.Banachowski, SZB
Pseudo-wartość NULL
Indeksowane są wszystkie wiersze, w których co najmniej jedna składowa klucza wyszukiwania indeksu nie jest NULL.
Na przykład, za pomocą indeksu na kolumnie Comm nie można zrealizować wyszukiwania wierszy z nieokreśloną wartością w polu Comm:
SELECT EnameFROM EmpWHERE Comm IS NULL;
Można … WHERE Comm IS NOLL NULL; Ograniczenie to nie dotyczy indeksów
bitmapowych i klastrowych.
Wyszukiwanie zakresowe – plik posortowany
"Wyznacz studentów ze średnią > 4.0"– Gdy dane w pliku posortowanym:
wyszukiwanie binarne aby znaleźć pierwszego takiego studenta;
przejdź plik wypisując pozostałych takich studentów.
– Plik indeksu k1< k2< … <KN.
Wyszukiwanie binarne na mniejszym pliku indeksu!
Page 0 Page1 Page NPage 2 Plik danych posortowany
k2 kNk1 Plik indeksu
Strona indeksu
Statyczne drzewo ISAM (indexed sequential access method)
W liściach są pozycje danych.
P0
K1 P
1K 2 P
2K m
P m
Pozycja indeksu
Węzływewnętrzne
Strony główne
Liście
Strony nadmiarowe
1K < K …. < K
2 m
Drzewo ISAM
10* 15* 20* 27* 33* 37* 40* 46* 51* 55* 63* 97*
20 33 51 63
40
Korzeń
Wstawiamy 23*, 48*, 41*, 42* ...
10* 15* 20* 27* 33* 37* 40* 46* 51* 55* 63* 97*
20 33 51 63
40
Korzeń
23* 48* 41*
42*
Stronynadmiarowe
Stronyindeksu
Stronygłówne
B+ drzewo Wstawianie/usuwanie w czasie rzędu log N;
drzewo wyważone względem wysokości. (N = # liści)
Każdy węzeł (z wyjątkiem ewentualnie korzenia) zawiera d <= m <= 2d pozycji indeksu. Parametr d - stopień drzewa.
Zapytania równościowe i zakresowe.
Pozycje indeksu
Pozycje danych
B+ drzewo
Wyszukiwanie zaczyna się w korzeniu a porównania klucza wyszukiwania prowadzą do liścia tak jak dla ISAM.
Wyszukiwanie 5*, 15*, >= 24* ...
Na podstawie wyniku wyszukiwania 15*, wiemy że 15* nie ma w drzewie
Korzeń
17 24 30
2* 3* 5* 7* 14* 16* 19* 20* 22* 24* 27* 29* 33* 34* 38* 39*
13
Drzewa B+ w praktyce
Średni stopień d=100. Średnie zapełnienie: 67%.
Typowa pojemność:– Wysokość 4: 1334 = 312,900,700 rekordów – Wysokość 3: 1333 = 2,352,637 rekordów
Zwykle górne poziomy drzewa w cache:– Poziom 1 = 1 strona = 8 KB– Poziom 2 = 133 strony = 1 MB– Poziom 3 = 17,689 strony = 133 MB
Wstawienie pozycji danych do B+ drzewa
Wyznacz odpowiedni liść L. Wstaw pozycję danych do L.
– Jeśli mieści się – to koniec!– Wpp, podziel L (na L i nowy węzeł L2)
Rozdziel równo pozycje, skopiuj na wyższy poziom środkowy klucz (najmniejszy w prawym węźle L2).
Do “ojca” L wstaw pozycję indeksu z tym kluczem i wskaźnikiem wskazującym na L2.
W razie potrzeby powtórz krok podziału rekurencyjnie.
Kroki podziału mogą dojść do korzenia i w rezultacie drzewo może zwiększyć swoją wysokość o jeden.
Wstawianie 8*
2* 3* 5* 7* 8*
5
Pozycja wstawiana do “ojca”jest kopiowana.
5 24 30
17
13
Podział liścia
Podział węzła wewnętrznego
Pozycja wstawiana do “ojca”jest przesuwana w górę .
Drzewo po wstawieniu 8*
Poprzedni korzeń uległ podziałowi. Wysokość drzewa zwiększyła się o 1. Możliwa redystrybucja pozycji danych w poziomie nie jestw praktyce realizowana.
2* 3*
Korzeń
17
24 30
14* 16* 19* 20* 22* 24* 27* 29* 33* 34* 38* 39*
135
7*5* 8*
22PJWSTK, L.Banachowski, SZB
B+ drzewo jako indeks wewnętrzny i zewnętrzny
Indeks może być wewnętrzny i wtedy pozycje danych pokrywają się z rekordami danych, tzn. rekordy danych są zapisywane w strukturze B+ drzewa zgodnie z porządkiem klucza wyszukiwania. Z tego powodu jest to wtedy indeks pogrupowany.
Albo indeks jest zewnętrzny i wtedy rekordy z danymi są przechowywane poza indeksem w dowolnym porządku (dla plików nieuporządkowanych, posortowanych i haszowanych).
23PJWSTK, L.Banachowski, SZB
Strategia zastępowania ramek dla stron B+ drzewa
• LRU nie jest tu dobrą metodą!
Korzeń drzewa i najwyższe poziomy
dobrze jest trzymać cały czas w pamięci RAM.
24PJWSTK, L.Banachowski, SZB
Dodatkowe operacje na B+ drzewach
Gdy ilość zajętego miejsca w drzewie spada poniżej pewnego progu, możliwe:– REBUILD utworzenie indeksu od nowa– COALESCE połączenie ze sobą sąsiednich stron o
zajętości poniżej 50%. Gdy na samym początku mamy dany duży zbiór
rekordów, to wtedy zamiast powtarzania kolejnych operacji INSERT opłaca się zastosować algorytm Bulk Loading, którego działanie polega na posortowaniu pliku rekordów z danymi, a następnie dobudowaniu nad posortowanym ciągiem kolejnych poziomów indeksowych drzewa B+.
25PJWSTK, L.Banachowski, SZB
Dlaczego nie używamy B-drzew?
Dla pełności tematu pokazujemy schemat węzła zwykłego
B-drzewa (bez plusa).
Podsumowanie drzew
Zastosowanie indeksów o strukturze drzewa: – Wyszukiwanie zakresowe.– Wyszukiwanie równościowe. – Sortowanie (np. ORDER BY).
ISAM – struktura statyczna.– Modyfikowane są tylko liście.– Wymagane są strony nadmiarowe – mogące
istotnie pogorszyć działanie algorytmów. B+ drzewo – struktura dynamiczna.
– W praktyce wysokość zwykle <=4.
Indeks haszowany
Ustalona alokacja stron głównych; alokowane dodatkowe strony nadmiarowe w razie potrzeby.
h(k) np. = k mod M = “segment” do którego należy pozycja danych k* o kluczu k (M = # segmentów). h(klucz)
hklucz
Strony główne Strony nadmiarowe
10
M-1
Plik: nieuporządkowany, posortowany i haszowany.
28PJWSTK, L.Banachowski, SZB
Indeks haszowany z uporządkowanymi segmentami
Wariant w którym pozycje danych są uporządkowane względem wartości klucza wyszukiwania.
Podsumowanie haszowania
Mogą powstać długie łańcuchy nadmiarowych stron
co prowadzi do pogorszenia działania:– konieczność okresowego wykonywan ia operacji REBUILD,
– istnieją dynamiczne wersje haszowania – polegające na
zwiększaniu liczby M segmentów przez ich podział.
Indeksy haszowane dobre przy wyszukiwaniu
równościowym. Nie wspomagają wyszukiwania
zakresowego ani sortowania.
30PJWSTK, L.Banachowski, SZB
Podsumowanie indeksu wewnętrznego
Dla jednej tabeli może być zbudowany tylko jeden indeks wewnętrzny i wiele indeksów zewnętrznych względem różnych kluczy wyszukiwania.
W indeksie wewnętrznym zbudowanym na B+ drzewie rekordy z danymi są zapisywane na stronach reprezentujących liście drzewa. W indeksie haszowanym wewnętrznym rekordy z danymi są zapisywane na stronach segmentów. W obu przypadkach z definicji algorytmów wstawiania i usuwania wynika, że rekordy mogą być przesuwane między stronami. To znaczy, rekordy mogą zmieniać stronę a zatem nie może być do nich z zewnątrz bezpośrednich wskaźników używających identyfikatora strony. Za identyfikator rekordu używa się wtedy wartość jego klucza głównego a dostęp do rekordu jest zawsze realizowany poprzez indeks główny.
31PJWSTK, L.Banachowski, SZB
Indeks wewnętrzny – 2 przypadki
Indeks główny jest indeksem wewnętrznym. Wtedy wyszukiwanie rekordu według wartości klucza wyszukiwania indeksu zewnętrznego wymaga przejścia dwóch indeksów: najpierw zewnętrznego, w którym znajdujemy wartość klucza głównego szukanego rekordu, a następnie indeksu wewnętrznego głównego, w którym w oparciu o wartość klucza głównego znajdujemy szukany rekord.
Indeks główny jest indeksem zewnętrznym, w którego pozycjach danych są zapisywane (zmienne) wskaźniki do rekordów. Przy wyszukiwaniu rekordu przechodzimy tak jak poprzednio dwa indeksy: zewnętrzny i główny. Natomiast przy zmianach położenia rekordu w indeksie wewnętrznym wymagane jest znalezienie pozycji danych tego rekordu w indeksie głównym i zapisanie w niej nowego adresu tego rekordu.
32PJWSTK, L.Banachowski, SZB
Struktury danych wielowymiarowe
Siatka (ang. grid file) – podział obszaru wyszukiwań, powiedzmy leżącego na płaszczyźnie, poziomymi i pionowymi liniami na prostokąty. Punkty trafiające do jednego prostokąta są zapisywane w jednym segmencie. Gdy segmenty się przepełnią, można albo stosować strony nadmiarowe albo dzielić prostokąty na mniejsze zwiększając liczbę segmentów.
33PJWSTK, L.Banachowski, SZB
Struktury danych wielowymiarowe
Dzielona funkcja haszowana (ang. partitioned hash function):
H(v1,...,vn)=h1(v1)&h2(v2)&....&hn(vn)
Wartością funkcji haszującej dla układu wartości jest konkatenacja tekstowa wartości funkcji haszujących dla poszczególnych składowych.
34PJWSTK, L.Banachowski, SZB
Drzewa wielowymiarowe
R drzewa są uogólnieniem B drzew do n wymiarów. Pozycją danych w takim drzewie jest para złożona z n-wymiarowej kostki:{(v1,...,vn): ai<=vi<=bi dla 1<=i<=n} oraz adresu pewnego obiektu geometrycznego, który jest jednoznacznie ograniczony tą kostką.
Podobnie pozycją indeksu jest taka kostka oraz wskaźnik do węzła niższego poziomu, w którego poddrzewie znajdują się wyłącznie obiekty zawarte w tej kostce i w żadnym innym poddrzewie takie obiekty nie występują.
35PJWSTK, L.Banachowski, SZB
Powtórzenie
Plik danych – składowanie danych• nieuporządkowany• uporządkowany (posortowany)• haszowany
Indeks – wyszukiwanie danych i jednoznaczność kluczy• wewnętrzny - pozycja danych = rekord danych• zewnętrzny – pozycja danych = wskaźnik do rekordu danych• pogrupowany – wewnętrzny & plik danych uporządkowany według wartości klucza indeksu• B+ drzewo• tablica haszowana (jako indeks wewnętrzny lub zewnętrzny)
Zastosowania sortowania w bazach danych
ORDER BY - dane są wymagane w pewnym porządku.
Budowa indeksu - początkowego B+ drzewa dla wczytywanego zbioru rekordów.
Złączanie tabel metodą Sort-merge. Realizacja DISTINCT, GROUP BY, UNION, EXCEPT -
alternatywą haszowanie.
Problem: posortować 1GB danych za pomocą 10MB RAM.
Sortowanie zewnętrzne (wielofazowe przez scalanie)
Faza 0 – sortowanie rekordów w ramach stron: Wczytaj stronę, posortuj ją, zapisz na dysku.
Faza 1,2,3 …, itd: scalaj uporządkowane podpliki w większe uporządkowane podpliki aż cały plik zostanie uporządkowany.
Bufory w RAM
Wejście 1
Wejście 2
Wyjście
DyskDysk
Sortowanie wielofazowe przez scalanie
W każdej fazie odczytujemy i
zapisujemy każdą stronę w
pliku.
N = # stron => # faz =
Całkowity koszt = 2 N log N
Idea: Dziel i rządź: sortuj
podpliki i je scalaj.
Zamiast dwóch buforów
można użyć więcej.
Praktycznie liczba faz <=3.
log2 1N
Plik wejściowyFaza 0
Faza 1
Faza 2
Faza 3
9
3,4 6,2 9,4 8,7 5,6 3,1 2
3,4 5,62,6 4,9 7,8 1,3 2
2,34,6
4,7
8,91,35,6 2
2,3
4,46,7
8,9
1,23,56
1,22,3
3,4
4,56,6
7,8
Sortowanie za pomocą B+ drzewa
Warunek: Tabela ma indeks na B+ drzewie względem kolumn sortowania.
Idea: Przejść po liściach indeksu. Czy jest to dobra metoda? Przypadki:
– Indeks pogrupowany Bardzo dobra!
– Indeks nie pogrupowany Może być bardzo zła!
Wewnętrznyindeks pogrupowany
Od korzenia przejdź do skrajnie lewego liścia a następnie sekwencyjnie w prawo po liściach.
Zawsze lepsze od sortowania zewnętrznego!
Rekordy danych w pozycjach danych!
Indeks
Pozycje danych
Indeks niepogrupowany
Ogólnie, jedna operacja We/Wy na rekord danych!
Rekordy danych
Indeks
Pozycje danych
42PJWSTK, L.Banachowski, SZB
Indeksy w Oracle
• Indeks oparty na B+ drzewie
• Tabela połączona z indeksem opartym na B+ drzewie
• Indeks oparty na B+ drzewie z odwróconymi wartościami kluczy
• Indeks oparty na klastrze jednej lub więcej tabel (B+ drzewo lub hasz), indeks haszowany
• Indeks z pozycjami określonymi za pomocą wyrażeń
• Indeks bitmapowy – implementacja dwa B+ drzewa
43PJWSTK, L.Banachowski, SZB
Plik nieuporządkowany - bez indeksu wewnętrznego - indeks zewnętrzny oparty na B+ drzewie
Pozycja danych składa się z wartości indeksowanych kolumn oraz z identyfikatora ROWID wiersza w tabeli - określającego fizyczne położenie danego wiersza na dysku. Umożliwia:– znalezienie wiersza w oparciu o wartość klucza wyszukiwania,
– realizację zapytań zakresowych.
Przy wykonywaniu zapytania system używa indeksu opartego na B+ drzewie tylko wtedy gdy jest zapewniona wystarczająca selektywność wyszukiwania, powiedzmy zwracane zostaje co najwyżej 5 do 10% wszystkich rekordów w pliku.
Indeks zewnętrzny oparty na B+ drzewie jest automatycznie tworzony dla każdego klucza głównego i jednoznacznego.
44PJWSTK, L.Banachowski, SZB
Tabela połączona z indeksem głównym opartym na B+ drzewie
Pozycjami danych indeksu głównego są rekordy pliku tzn. wiersze tabeli są trzymane w indeksie. Jest zapewniony bardzo szybki dostęp do wierszy przez wartości klucza głównego.
Wiersze nie posiadają swoich identyfikatorów ROWID – identyfikacja wierszy przebiega wyłącznie przez wartości klucza głównego; w pozostałych indeksach wynikiem wyszukania jest wartość klucza głównego – a nie ROWID. Odpowiada to koncepcji indeksu pogrupowanego - ale budowanego tylko dla klucza głównego.
Budując osobno perspektywę zmaterializowaną można jej nadać inną organizację.
45PJWSTK, L.Banachowski, SZB
Załóżmy, że chcemy dokonywać analizy klientów wyszukując klientów mieszkających w określonym mieście.
• Miasta(Id_miasta, Nazwa_miasta)
• Klienci(Id_miasta, Id_klien_w_miescie, Nazwisko, Hobby, Wiek)
Jeśli tabela Klienci jest połączona z indeksem na swoim kluczu głównym, istotnie można przyśpieszyć wykonywanie zapytań w rodzaju:
SELECT K.Nazwisko, .HobbyFROM Klienci K INNER JOIN Miasta M ON K.Id_miasta = M.Id_miasta WHERE M.Nazwa_miasta = 'WARSZAWA' AND K.Wiek BETWEEN 18 and 25;
Tabela połączona z indeksem opartym na B+ drzewie
46PJWSTK, L.Banachowski, SZB
Tworzenie tabeli połączonej z indeksem opartym na B+ drzewie
CREATE TABLE Klienci( Id_miasta INTEGER, Id_klien_w_miescie INTEGER, Nazwisko VARCHAR2(80), Hobby VARCHAR(20), Wiek INTEGER, CONSTRAINT Klienci_pk PRIMARY KEY (Id_miasta, Id_klien_w_miescie), CONSTRAINT Klienci_fk FOREIGN KEY(Id_miasta) REFERENCES Miasta ) ORGANIZATION INDEX;
47PJWSTK, L.Banachowski, SZB
Indeks haszowany
Przykład zastosowania indeksu haszowanego dla klucza głównego Id_konta tabeli:
• Konta(Id_konta, Saldo, Imie, Nazwisko, Adres)
Zakładamy, że tabela Konta zawiera bardzo dużo wierszy oraz że często wielu kasjerów w banku równocześnie wykonuje zapytanie:
SELECT *FROM Konta kWHERE k.Id_konta = :numer;
48PJWSTK, L.Banachowski, SZB
Tworzenie indeksu haszowanego
CREATE CLUSTER Klast_konta(Id_konta INTEGER) SIZE 512 SINGLE TABLE HASHKEYS 100003 HASH IS mod(Id_konta, 100003);
- lub HASH IS Id_konta
Następnie definiujemy tabelę Konta:
CREATE TABLE Konta(Id_konta INTEGER PRIMARY KEY, Saldo NUMBER, Imie VARCHAR2(20), Nazwisko VARCHAR2(50), Adres VARCHAR2(70))CLUSTER Klast_konta(Id_konta);
49PJWSTK, L.Banachowski, SZB
Tworzenie indeksu haszowanego
Indeks klastra jest tworzony automatycznie. Parametr SIZE w definicji klastra określa ilość miejsca
w bajtach przeznaczoną do zapisania rekordów z tą samą wartością klucza klastra. Domyślną wartością (gdy brak klauzuli SIZE) jest rozmiar strony dyskowej. Jeśli wszystkie wiersze dla danej wartości klucza klastra nie mieszczą się w jednym bloku, są zapisywane na liście nadmiarowych bloków. Poprzez dobór odpowiedniej wartości SIZE można spowodować, że wszystkie rekordy z daną wartością klucza znajdą się na tej samej lub tylko na kilku stronach dyskowych.
50PJWSTK, L.Banachowski, SZB
Sortowanie segmentów haszowanych
CREATE CLUSTER call_detail_cluster ( telno NUMBER, call_timestamp NUMBER SORT, call_duration NUMBER SORT ) HASHKEYS 10000 HASH IS telno SIZE 256;
CREATE TABLE call_detail ( telno NUMBER, call_timestamp NUMBER SORT, call_duration NUMBER SORT, other_info VARCHAR2(30) ) CLUSTER call_detail_cluster ( telno, call_timestamp, call_duration );
Wyświetlić rozmowy wykonane z danego numeru w kolejności od najwcześniejszego.
SELECT * WHERE telno = 6505551212ORDER BY call_timestamp;
51PJWSTK, L.Banachowski, SZB
Przykład - słaba selektywność
SELECT E.Ename FROM Emp E WHERE E.Job=:job;
- ewentualnie z ORDER BY E.Ename
1. Klaster (indeks) haszowany z kluczem Emp.Job lub Emp(Job, Ename) – sortowane segmenty
2. Tabela połączona z indeksem głównym:Emp (Job, Empno, …) lub Emp (Job, Empno, Ename, …)
3. Zwykły indeks na E.Job może być zły ze względu na słabą selektywność
4. Indeks bitmapowy na E.Job