Większość z nas w którymś momencie swojej kariery trafiła na bojowe zadanie - MIGRACJA DANYCH. Niektórzy lubią gmerać w danych a inni na samo słowo MIGRACJA dostają gęsiej skórki. Niemniej jednak MIGRACJE są nieodłącznym elementem bazodanowego krajobrazu i trzeba śmiało stawić czoła temu wyzwaniu!
Jednym z problemów, na które można się natknąć podczas przenoszenia danych to problem z sequencerami. Jeśli kopiujemy dane z jednej bazy na drugą, łącznie z ustawionymi na bazie źródłowej sequencerami, to na bazie docelowej w tabelach będziemy mieli rekordy z identyfikatorami większymi niż stan liczników na bazie. Próba wstawienia rekordu w takiej sytuacji skończy się błędem DUP_VAL_ON_INDEX.
Żeby doprowadzić system do względnej równowagi musimy podnieść wartości naszych sequencerów tak, by liczniki były większe niż maksymalne wartości w tabelach.
Niestety w Oracle nie ma powiązania bezpośredniego między tabelą i seqencerem więc nie jesteśmy w stanie automatycznie zweryfikować, do jakiej wartości podnieść liczniki. Najczęściej po prostu podbija się wszystkie liczniki do jakiejś dużej wartości, tak by mieć pewność, że liczniki będą większe od maksymalnego ID w każdej tabeli. Warto w tym celu też zweryfikować wartości ID w naszych największych tabelach.
Jak już ustalimy naszą nową wartość liczników to dalej już będzie prosto! Wystarczy podbić wszystkie liczniki do nowej wielkości....
Ręczne podbijanie liczników jest dość monotonne i czasochłonne. Więc może przygotujmy sobie narzędzie.
W narzędziu skorzystamy z dwóch przydatnych funkcjonalności ORACLE.
SŁOWNIKI
w widokach słownikowych Oracle możemy znaleźć definicje obiektów (i nie tylko) naszej bazy danych. Dzisiaj będzie nam potrzebny słownik zawierający definicje seqencerów. Słownik ten to ALL_SEQUENCES.
EXECUTE IMMEDIATE
klauzula umożliwiająca nam tworzenie dynamicznych poleceń DDL (i nie tylko :))
Także zaczynajmy!
Dzięki słowniowi Oracle możemy się dowiedzieć, jakie mamy sequencery w bazie danych oraz jakie mają aktualne wartości. W bazie HR mamy trzy sequencery:
Załóżmy, że chcemy podbić je do wartości 100.
By to uczynić mamy dwie możliwości:
Pierwsza opcja to usunięcie i utworzenie ponownie sequencera z parametrem start with ustawioną na naszą oczekiwaną wartość.
1: DECLARE
2: N NUMBER := 100;
3: BEGIN
4: FOR Z IN (
5: SELECT SEQUENCE_NAME
6: FROM all_sequences where sequence_owner = 'HR') LOOP
7: execute immediate 'DROP SEQUENCE '||'HR'||'.'||z.SEQUENCE_NAME;
8: execute immediate 'CREATE SEQUENCE '||'HR'||'.'||z.SEQUENCE_NAME ||' START WITH ' || N ||' INCREMENT BY 1' ;
9: END LOOP;
10: END;
Po wykonaniu skryptu nasze liczniki powinny ustawić się na oczekiwane wartości. Sprawdźmy!
Udało się!
Drugą metodą, jest podkręcenie licznika przez zmianę licznika i podbicie parametru INCREMENT BY. Jak to zrobić?
Skrypt jest bardzo podobny do pierwszego.
1: set serveroutput on
2: declare
3: nSeqNew number := 100;
4: vOwner varchar2(30) := 'HR';
5: nseqTest number;
6: begin
7: for z in (
8: SELECT (nSeqNew - last_number) seqInc, SEQUENCE_NAME
9: FROM all_sequences where sequence_owner = vOwner) loop
10: execute immediate 'ALTER SEQUENCE '||vOwner||'.'||z.SEQUENCE_NAME ||' INCREMENT BY ' || z.seqInc;
11: execute immediate 'select '||vOwner||'.'||z.SEQUENCE_NAME || '.nextval from dual' into nseqTest;
12: execute immediate 'ALTER SEQUENCE '||vOwner||'.'||z.SEQUENCE_NAME ||' INCREMENT BY 1';
13: dbms_output.put_line(z.SEQUENCE_NAME || ' new '||nseqTest);
14: end loop;
15: end;
Czy zadziała? Zerknijmy...
I znów się udało :)
Dzięki słownikom oraz poleceniu EXECUTE IMMEDIATE migracja danych nie jest taka straszna!
Komentarze
Prześlij komentarz