Partycje Tabel OpenEdge cz. III

Zanim przejdę do kolejnej części związanej z partycjami tabel, winien jestem odpowiedzi na pytanie związane z definiowaniem zasad partycjonowanie.
Otóż kilku z Was chciało wiedzieć czy jest planowana możliwość definiowania podziału danych w tabeli w oparciu nie o wartość pola, lecz o funkcję (np. YEAR(TODAY)-1).
Miałem okazję niedawno rozmawiać z Richem Banvill’em – odpowiedzialnym za rozwój bazy OpenEdge. Taka możliwość nie jest w planach, ani w wersji OE12 ani w dalszej przyszłości.
Rich wspomniał, że problem ten można rozwiązać np. poprzez zdefiniowanie zadań w cronie.

Wróćmy jednak do tematu. W poprzedniej części zakończyliśmy podział tabeli w oparciu o wartości pola Country (lokalny idex). Wspomniałem, że partycjonowanie jest transparentne dla aplikacji, jednakże mogą zdarzyć się sytuacje gdy zapytanie zwraca nie te same rekordy co przed partycjonowaniem. Jednym z przykładów jest stosowanie w kodzie wyszukiwania po adresach RECID/ROWID. Ponieważ partycjonowanie przenosi rekordy, ich fizyczne adresy ulegają zmianom. W przypadku stosowania tego rozwiązania trzeba wprowadzić odpowiednie poprawki w kodzie aplikacji.

Innym, częstszym przykładem jest stosowanie w zapytaniu filtra na dane pole (WHERE). Ponieważ w partycjonowanej tabeli dodany jest zazwyczaj nowy, lokalny index, wyszukiwanie może być realizowane w oparciu o niego. Aby mieć pewność, że index nie został zmieniony i aby zachować ten sam porządek rekordów trzeba ew. dopisać frazę USE-INDEX.

Teraz trzeba wspomnieć o ważnej funkcji technologi partycjonowania tzw. pruning (okrajanie partycji).

Proces pruningu analizuje automatycznie zapytanie i (o ile to możliwe) nie bierze pod uwagę rekordów w partycjach, które nie spełniają warunków zapytania. Na rysunku widać przykład podziału rekordów na kwartały wg pola OrderDate. Jeśli w zapytaniu warunki będą dotyczyły rekordów tylko z kwartału drugiego, to tylko ta jedna partycja będzie w użyciu. Technologia ta może znacząco wpłynąć na poprawę wydajności.

Następnym zagadnieniem jest stosowanie frazy TABLE-SCAN. Powoduje ona pobranie rekordów bez dostępu do indexów i wyświetlenie ich w porządku, w jakim znajdują się w blokach bazy. Porządek rekordów zmieni się więc po partycjonowaniu, ze względu na przeniesienie ich do innych bloków. Przed pobieraniem wykonywana jest operacja pruning. Zobaczmy poniższy przykład:

FOR EACH order WHERE country = “USA” AND
  OrderDate >= 10-01-2014 AND
  OrderDate <= 12-31-2014 TABLE-SCAN:
DISPLAY OrderNum...

Jak widać, partycjonowanie tabel może wpłynąć na porządek przetwarzanych rekordów. Zobaczmy teraz jak wygląda sytuacja z tworzenie nowych rekordów i ich edytowaniem.

Należy pamiętać, że rekordy muszą mieć określone wartości dla pól, wg których odbywa się partycjonowanie. Dlatego warto stosować instrukcję ASSIGN grupującą ustawienia wartości dla rekordu, zaraz po instrukcji CREATE. Instrukcja ASSIGN wymusza fizyczne utworzenie rekordu w bazie, a więc zadziałanie mechanizmu portycjonowania. Poniższy przykład wywoła błąd (partycjonowanie po polu Country).

CREATE order.
ASSIGN ordernum = NEXT-VALUE(next-ord-num). /* ERROR! */
ASSIGN country = “USA”. 

Przykład ten łatwo poprawić do postaci:

CREATE order.
ASSIGN ordernum = NEXT-VALUE(next-ord-num)
       country = “USA”.

Edycja pola rekordu, wg którego realizowany jest podział tabeli niesie ze sobą przeniesienie całego rekordu do innego obszaru, a więc skasowanie rekordu, utworzenie go w nowym obszarze, aktualizacja indexów. Zbyt częste takie operacje mogą nieść ze sobą obniżenie wydajności. Może to być wynikiem niewłaściwie wybranego klucza partycji, co warto przedyskutować i ew. wybrać inny klucz.