Czarodziej czarujący podróże w czasie z komputera

Time Travel w Snowflake’u i Fail Safe

Jedną z podstawowych funkcjonalności dostępnych w Snowflake’u jest możliwość cofania się w czasie. Dzięki funkcjonalności Time Travel jesteś w stanie sprawdzić jak dane w tabeli prezentowały się w konkretnym punkcie w czasie i je odzyskać lub wykorzystać w inny kreatywny sposób!

Dzięki Fail Safe z kolei możesz odzyskać nawet dane, których podróż w czasie już nie obejmuje, jednak z pewnymi ograniczeniami.

Trochę teorii

Dzięki Time Travel możesz odpytywać stan tabeli z przeszłości na 3 sposoby:

  1. Sprawdzisz ostatnią zawartość tabeli przed konkretnym punktem w czasie,
  2. Sprawdzisz zawartość tabeli w przeszłości definiując przesunięcie w czasie o ile chcesz się cofnąć,
  3. Sprawdzisz zawartość tabeli przed uruchomieniem wybranego zapytania (tutaj wykorzystasz query ID),

a nawet odtworzyć usuniętą tabelę za pomocą komendy UNDROP.

Do Fail Safe docierają dane, których nie obejmuje już ustalony okres dostępności podróży w czasie, jednak użytkownik Snowflake’a nie ma do nich dostępu. Żeby wydobyć dane z przestrzeni Fail Safe konieczny jest kontakt z przedstawicielami Snowflake’a.

Okres dostępności Time Travel

Możliwości podróży w czasie i wykorzystania fail safe są zależne od ustawień poszczególnych tabel, ale również typów tabel, o czym wspomniałem we wcześniejszym wpisie.

Domyślnie podróże w czasie są ustalone na 24 godziny dla wszystkich baz danych, schematów i tabel. W zależności od licencji Snowflake’a, rodzaju tabeli i jej ustawień okres dostępności może wynosić od 0 do maksymalnie 90 dni.

TabelaLicencja StandardLicencja Enterprise i wyższe
Permanentna0-1 dni0-90 dni
Transient0-1 dni0-1 dni
Tymczasowa0-1 dni0-1 dni

Okres dostępności Fail Safe

Okres Fail Safe rozpoczyna się dla danych w momencie, jak są kasowane z przestrzeni Time Travel i przechowywany jest przez 7 dni.

Fail Safe w zamyśle ma Cię chronić przed utratą danych w wyniku awarii systemu lub innych krytycznych zdarzeń, jak choćby naruszenie bezpieczeństwa.

Jak już wcześniej wspomniałem, żeby odzyskać dane z Fail Safe musisz skontaktować się z przedstawicielem Snwoflake’a, chociażby przez formularz kontaktowy. Co więcej, odzyskanie danych z tego miejsca może zająć od kilku godzin do kilku dni.

W ten sposób chronione są jedynie tabele permanentne (te, które pozwalają na podróż w czasie do 90 dni w ramach licencji Enterprise).

Trochę praktyki z podróży w czasie

create or replace database time_travel;
create or replace schema time_travel.permanent_schema;
create or replace schema time_travel.extended_permanent_schema;
create or replace transient schema time_travel.transient_schema;
alter schema time_travel.extended_permanent_schema
    set data_retention_time_in_days=47;

show schemas like '%t_schema%' in database time_travel;

Powyżej stworzyłem bazę danych i 3 schematy. Jak widzisz, wszystkie domyślnie mają od początku retention_time 1 dzień, a dla EXTENDED_PERMANENT_SCHAMA przedłużyłem możliwe podróże w czasie do 47 dni.

Domyślny czas retention_time tworzonych obiektów możesz ustawić nawet na poziomie całego konta:

alter account set data_retention_time_in_days=15;
create or replace schema time_travel.extended_permanent_schema_default;

show schemas like '%t_schema%' in database time_travel;

Tutaj są 4 rzeczy warte zauważenia:

  • nowy schemat ma od razu domyślnie 15 dni retention_time.
  • permanentny schemat, który został utworzony wcześniej, ale nie miał dodatkowo zdefiniowanego retention_time zmienił wartość z 1 do 15 dni.
  • schemat, który miał dodatkowo zdefiniowane retention_time na 47 dni został niezmieniony.
  • schemat transient również został niezmieniony – ten nie pozwala zwiększyć okresu time travel na więcej niż 1 dzień.

Wszystkie obiekty, które umożliwiają podróże w czasie podlegają powyższym zasadom definiowania i dziedziczenia parametru retention_time.

Odczytywanie zmienionych danych

Najpierw stworzę małą tabelkę.

create table time_travel.extended_permanent_schema_default.dim_client
    (id int
    ,name varchar()
    ,surname varchar()
    );

insert into time_travel.extended_permanent_schema_default.dim_client
values (1, 'Marek', 'Nowak')
      ,(2, 'Adam', 'Kowalski')
      ,(3, 'Jan', 'Kowalski');

select *
from time_travel.extended_permanent_schema_default.dim_client;
podstawowa zawartość tabeli przed zmianami

Dodajmy 2 nowe wiersze z Panem Galem i Panią Joanną i mamy komplet.

insert into time_travel.extended_permanent_schema_default.dim_client
values (4, 'Gal', 'Anonim')
      ,(5, 'Joanna', 'd\'Arc');

W historii zapytań mamy informację o godzinie uruchomienia ostatniego inserta oraz query id.

Time Travel po Query ID

select *
from time_travel.extended_permanent_schema_default.dim_client
before(statement => '01b2bf2b-0002-292d-0000-0053f907b0ed');
poglądowy wygląd tabeli dim_client z przeszłości

Jak widzisz, nie ma śladu po Galu i Joannie.

Time Travel po Timestamp’ie

select *
from time_travel.extended_permanent_schema_default.dim_client
at(timestamp => '2024-03-03 11:23:36 -0800'::timestamp_tz);

Wynik będzie ten sam, ale… jak to jest, że jako timestamp wpisałem godzinę 11:23, skoro wcześniej na screenie widać czas wstawienia danych o 20:23?

Przyznaję, że w strefach czasowych łatwo się pogubić. Rozpracowanie pracy ze strefami czasowymi zostawię na odrębny wpis, a jeśli chcesz na szybko, to póki co zajrzyj do dokumentacji.

Sprawdzić obecną strefę czasową sesji / konta możesz sprawdzić poniższymi poleceniami. Sprawdzisz też godzinę strefy czasowej sesji.

--strefa czasowa bieżącej sesji
show parameters like 'timezone' for session;

--dostaniesz obecną datę i czas dokładny do strefy czasowej sesji wraz z informacją o przesunięciu względem strefu UTC
select current_timestamp();

Time Travel po offsecie czasowym

select *
from time_travel.extended_permanent_schema_default.dim_client
at(offset => -60 * 30);

Powyższy kod cofnie nas w czasie o 30 minut.

Odzyskanie usuniętej tabeli

Bardzo prosta rzecz. Najpierw usunę naszą tabelę dim_client.

drop table time_travel.extended_permanent_schema_default.dim_client;

/*
zauważ, że poniższe zapytanie zwróci błąd, pomimo, że chcę odczytać tabelę z momentu, w którym jeszcze ona istniała
*/
select *
from time_travel.extended_permanent_schema_default.dim_client
at(offset => -60 * 30);

Możesz sprawdzić listę tabel, która została usunięta komendą drop korzystając z poniższego zapytania.

show tables history;

W ten sposób zobaczysz informacje o wszystkich tabelach wraz z tymi usuniętymi, które jeszcze są objęte okresem podróży w czasie. Dowiesz się też kiedy dokładnie zostały usunięte.

Przywróćmy w końcu tę tabelę.

undrop table time_travel.extended_permanent_schema_default.dim_client;

select *
from time_travel.extended_permanent_schema_default.dim_client;
wynik polecenia UNDROP w Snowflake'u potwierdzający przywrócenie usuniętej tabeli

Przywróciliśmy tabelę i możemy z niej znów normalnie korzystać.

Zajęta przestrzeń przez dane z Time Travel

Żeby odczytać dane z historii Snowflake musi je gdzieś nadal przetrzymywać. Żeby sprawdzić zajmowaną przestrzeń wystarczy odpytać widok systemowy TABLE_STORAGE_METRICS.

select  table_schema
       ,table_name
       ,is_transient
       ,active_bytes
       ,time_travel_bytes
       ,failsafe_bytes
       ,table_dropped
       ,table_entered_failsafe
from time_travel.information_schema.table_storage_metrics;

Zauważ, że tabela dim_client, którą wykorzystałem do zaprezentowania przykładów zajmuje obecnie znacznie więcej przestrzeni w Time Travel niż w bieżących danych. Przy częstych zmianach na ogromnych tabelach może się to przełożyć na znaczące koszty.

Tylko co właściwie zajmuje tyle miejsca w zakresie Time Travel?

Do zakresu Time Travel Snowflake zapisuje mikropartycje, które uległy zmianie. Im częściej dokonujesz modyfikacji w tabeli, tym więcej miejsca będzie zajmował ten zakres. Jeśli u Ciebie Time Travel i Fail Safe zajmują znacznie więcej miejsca niż aktywna tabela, to Twoim pierwszym krokiem powinno być zbadanie procesów budujących tabele. Optymalizując liczbę zmian w tabeli masz szansę nie tylko na zmniejszenie kosztów przechowywania, ale też procesowania danych.

Jak nie kojarzysz tematu mikropartycji i sposobu przechowywania tabel w Snowflake’u koniecznie zajrzyj do tego wpisu. Zajrzyj też tutaj, jeśli interesuje Cię jak komendy INSERT, UPDATE i DELETE wpływają na mikropartycje.

Przykład zajmowanej przestrzeni przez Time Travel

Najpierw stworzę tabelę do testu i sprawdzę ile miejsca zajmuje.

create or replace table
  time_travel.extended_permanent_schema_default.time_travel_test 
as select *
from snowflake_sample_data.tpch_sf10.orders;

select  table_name
       ,is_transient
       ,active_bytes
       ,time_travel_bytes
       ,failsafe_bytes
from time_travel.information_schema.table_storage_metrics
where table_name = 'TIME_TRAVEL_TEST';

Mamy całkiem sporą tabelę z jedynie aktywnymi bajtami, bez time travel.

*Jeśli odczytujesz widok table_storage_metrics i nie widzisz nowych informacji od razu nie martw się – zaktualizowane dane w widoku dostępne są w ciągu około 2 godzin.

Teraz zaktualizuję pojedynczy wiersz.

update time_travel.extended_permanent_schema_default.time_travel_test
set o_orderstatus = 'P'
where o_orderkey = 50015776;

select  table_name
       ,is_transient
       ,active_bytes
       ,time_travel_bytes
       ,failsafe_bytes
from time_travel.information_schema.table_storage_metrics
where table_name = 'TIME_TRAVEL_TEST';

Zwróć uwagę na wagę time_travel_bytes. W tym przypadku to aż 5% wagi aktywnej tabeli. Już tu widać duży wpływ aktualizacji na wagę Time Travel. Tabela składa się tutaj z 24 mikro-partycji, a zaktualizowanie 1 wiersza w całej tabeli sprawia, że cała mikro-partycja trafiła do zakresu Time Travel.

Teraz zduplikuję wiersze w tej tabeli, żeby zasymylować proces jedynie dodawania nowych wierszy do tabeli.

insert into time_travel.extended_permanent_schema_default.time_travel_test
select *
from snowflake_sample_data.tpch_sf10.orders;

Jak widać sam insert nie wpływa na TIME_TRAVEL_BYTES, pomimo, że waga całej tabeli mocno się zwiększyła. (waga Time Travel się różni, bo żeby nie czekać na aktualizację widoku table_storage_metrics stworzyłem przykłady na kilku tabelach)

Na koniec zaktualizujmy wszystkie wiersze w tabeli przesuwając datę zamówienia o jeden dzień. Powiedzmy, że to będzie symulacja co się dzieje, jeśli dokonamy często dużych aktualizacji tabeli.

update time_travel.extended_permanent_schema_default.time_travel_test
set o_orderdate = dateadd(day,1,o_orderdate);

Noooo i tutaj już widać ciężar aktualizacji tabeli. Zawartość Time Travel zajmuje już więcej niż aktywna tabela. Obecnie w Time Travel przechowywane są wszystkie mikro-partycje przed aktualizacją. Wyobraź sobie teraz co się dzieje, jak duże aktualizacje są często uruchamiane. Taki sam rezultat wagi przestrzeni Time Travel otrzymasz aktualizując pojedynczy wiersz 48 razy. 48 to liczba mikro-partycji w obecnej tabeli.

Trochę podsumowania

Time travel pozwoli Ci naprawić błędy z przeszłości przywracając stan tabeli z konkretnego momentu w przeszłości. Choćby w sytuacji, gdy zidentyfikujesz błędne aktualizacje, które pojawiły się w związku z niespodziewanymi zmianami danych źródłowych, lub gdy ktoś popełnił błąd i zmienił ustawienia przepływu danych. Przywrócisz też tabelę, jeśli ktoś przeszarżuje z dropowaniem obiektów. Ewentualnie odtworzysz tabelę z przeszłości, żeby przeanalizować zmiany w czasie, lub przetestować skuteczność modeli ML.

Z drugiej strony jednak musisz uważać, na procesy budujące tabele, a także, żeby nie przesadzić z retention_time. Może to Cię słono kosztować. Snowflake musi dalej przechowywać zmienione dane tabeli zgodnie z okresem retencji, a Ty musisz za ich przechowywanie zapłacić.

Żeby zapobiec niepotrzebnym kosztom dostosuj procesy budowania i aktualizacji tabel, żeby nie aktualizować zapisanych danych tam, gdzie nie jest to konieczne, a także skrócić Retention Time tam, gdzie częste aktualizacje są niezbędne.


Nie przegap kolejnych wpisów -> śledź mnie:


Opublikowano

w

przez

Komentarze

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *