Oracle to SQL Server i SQL Server to Oracle Migration Guide - Pt. 3
Opublikowany: 2022-03-11W pierwszej i drugiej części tej serii omówiono różnice między Oracle Database i Microsoft SQL Server w implementacji transakcji oraz wynikające z tego pułapki konwersji, a także niektóre powszechnie stosowane elementy składni.
Ta ostatnia część obejmie pojęcie spójności odczytu Oracle oraz sposób konwersji architektury opartej na tym pojęciu do wersji Microsoft SQL Server. Omówi również użycie synonimów (i jak ich NIE używać) oraz rolę procesu kontroli zmian w zarządzaniu środowiskiem bazy danych.
Spójność odczytu Oracle i jej odpowiednik w SQL Server
Spójność odczytu Oracle to gwarancja, że wszystkie dane zwracane przez pojedynczą instrukcję SQL pochodzą z tego samego pojedynczego punktu w czasie.
Oznacza to, że jeśli wydałeś instrukcję SELECT
o godzinie 12:01:02.345 i działała ona przez 5 minut przed zwróceniem zestawu wyników, wszystkie dane (i tylko dane), które zostały zatwierdzone w bazie danych od godziny 12:01:02.345, spowodują do zestawu zwrotnego. Twój zestaw zwrotny nie będzie zawierał żadnych nowych danych w ciągu tych 5 minut, które zajęło bazie danych przetworzenie wyciągu, ani żadnych aktualizacji, a żadne usunięcia nie będą widoczne.
Architektura Oracle zapewnia spójność odczytu dzięki wewnętrznemu oznaczaniu czasu każdej zmiany danych i budowaniem zestawu wyników z dwóch źródeł: stałych plików danych i segmentu cofania (lub „segmentu cofania”, jak to było znane do wersji 10g).
Aby to wspierać, należy zachować informacje o cofnięciu. Jeśli zostanie nadpisany, skutkuje to niesławnym ORA-01555: snapshot too old
.
Pomijając zarządzanie segmentami cofania — i sposób poruszania się po ORA-01555: snapshot too old
błąd — spójrzmy na wpływ spójności odczytu na każdą praktyczną implementację w Oracle. Ponadto, w jaki sposób powinien on zostać zdublowany w SQL Server, który – podobnie jak w przypadku innych implementacji RDBMS, z możliwym i kwalifikowanym wyjątkiem PostgreSQL – nie obsługuje go?
Kluczem jest to, że Oracle odczyty i zapisy nie blokują się nawzajem. Oznacza to również, że Twój zestaw zwracanych długoterminowych zapytań może nie zawierać najnowszych danych.
Nieblokujące odczyty i zapisy to zaleta Oracle, która wpływa na zasięg transakcji.
Ale spójność odczytu oznacza również, że nie masz najnowszego stanu danych. Gdy w niektórych scenariuszach jest to całkowicie dobre (np. tworzenie raportu na określony czas), w innych może powodować poważne problemy.
Brak najnowszych — nawet „brudnych” lub niezaangażowanych — danych może mieć krytyczne znaczenie: klasycznym scenariuszem jest system rezerwacji pokoi hotelowych.
Rozważ następujący przypadek użycia: Masz dwóch agentów obsługi klienta, którzy jednocześnie przyjmują zamówienia rezerwacji pokoju. Jak zapewnić, że pokoje nie będą przepełnione?
W SQL Server możesz rozpocząć jawną transakcję i SELECT
rekord z listy (może to być tabela lub widok) dostępnych pomieszczeń. Dopóki ta transakcja nie zostanie zamknięta (przez COMMIT
lub ROLLBACK
), nikt nie może uzyskać tego samego rekordu pokoju, który wybrałeś. Zapobiega to podwójnej rezerwacji, ale także sprawia, że wszyscy inni agenci czekają na siebie, aby zrealizować żądania rezerwacji pojedynczo, sekwencyjnie.
W Oracle ten sam wynik można osiągnąć, wydając SELECT ... FOR UPDATE
w odniesieniu do rekordów spełniających kryteria wyszukiwania.
Uwaga: istnieją lepsze rozwiązania, takie jak ustawienie tymczasowej flagi oznaczającej pokój „pod uwagę” zamiast ślepego blokowania do niego dostępu. Ale to są rozwiązania architektoniczne, a nie opcje językowe.
Wniosek : Spójność odczytu Oracle nie jest „cała dobra” lub „cała zła”, ale jest ważną właściwością platformy, którą należy dobrze zrozumieć i ma kluczowe znaczenie dla migracji kodu międzyplatformowego.
Publiczne (i prywatne) synonimy w Oracle i Microsoft SQL Server
„Publiczne synonimy są złe”. Nie jest to dokładnie moje osobiste odkrycie, ale przyjąłem je jako ewangelię, dopóki mój dzień, tydzień i rok nie zostały uratowane przez publiczne synonimy.
W wielu środowiskach baz danych — powiedziałbym, że we wszystkich środowiskach Oracle, z którymi miałem okazję pracować, ale w żadnym, które zaprojektowałem — użycie CREATE PUBLIC SYNONYM
dla każdego obiektu było rutyną, ponieważ „zawsze robiliśmy to w ten sposób”.
W tych środowiskach publiczne synonimy miały tylko jedną funkcję: umożliwiały odwoływanie się do obiektu bez określania jego właściciela. I to jest jeden słabo przemyślany powód, by upubliczniać synonimy.
Jednak publiczne synonimy Oracle mogą być niezwykle przydatne i dawać korzyści w zakresie produktywności zespołu, które znacznie przewyższają wszystkie ich wady, jeśli są prawidłowo wdrożone i zarządzane oraz mają powód. Tak, powiedziałem „wydajność zespołu”. Ale jak? W tym celu musimy zrozumieć, jak działa rozpoznawanie nazw w Oracle.
Kiedy parser Oracle znajduje nazwę (niezarezerwowane słowo kluczowe), próbuje dopasować ją do istniejącego obiektu bazy danych w następującej kolejności:
Uwaga: Zgłoszony błąd będzie ORA-00942: table or view does not exist
dla instrukcji DML lub PLS-00201: identifier 'my_object' must be declared
dla procedur składowanych lub wywołań funkcji.
W tej kolejności rozpoznawania nazw łatwo zauważyć, że gdy programista pracuje we własnym schemacie, każdy obiekt lokalny o tej samej nazwie co publiczny synonim ukryje ten publiczny synonim. (Uwaga: Oracle 18c zaimplementował typ schematu „tylko logowanie” i ta dyskusja nie ma do niego zastosowania).
Publiczne synonimy skalowania zespołów: Oracle Change Control
Spójrzmy teraz na hipotetyczny zespół 100 programistów pracujących na tej samej bazie danych (co jest czymś, czego doświadczyłem). Ponadto załóżmy, że wszyscy pracują lokalnie na swoich osobistych stacjach roboczych i wykonują niezależnie kompilacje niebędące bazą danych, wszystkie połączone z tym samym środowiskiem programistycznym baz danych. Rozwiązanie scalania kodu w kodzie niebędącym bazą danych (czy to C#, Java, C++, Python, czy cokolwiek innego) zostanie wykonane w czasie zaewidencjonowania kontroli zmian i zacznie obowiązywać od następnej kompilacji kodu. Jednak tabele bazy danych, kod i dane muszą być wielokrotnie zmieniane w tę iz powrotem w trakcie rozwoju. Każdy programista robi to niezależnie i zaczyna obowiązywać natychmiast.
W tym celu wszystkie obiekty bazy danych są tworzone we wspólnym schemacie aplikacji. To jest schemat , do którego odwołuje się aplikacja. Każdy programista:
- Łączy się z bazą danych za pomocą osobistego konta/schematu użytkownika
- Zawsze zaczyna się od pustego schematu osobistego
- Odwołuje się do wspólnego schematu tylko poprzez rozpoznawanie nazw do publicznego synonimu, jak opisano powyżej
Gdy programista musi wprowadzić jakiekolwiek zmiany w bazie danych — utworzyć lub zmienić tabelę, zmienić kod procedury, a nawet zmodyfikować zestaw danych w celu obsługi niektórych scenariuszy testowych — tworzy kopię obiektu w swoim osobistym schemacie. Robią to, pobierając kod DDL za pomocą polecenia DESCRIBE
i uruchamiając go lokalnie.
Od tego momentu kod dewelopera będzie widział lokalną wersję obiektu i danych, które nie będą widoczne (ani nie będą miały wpływu) na nikogo innego. Po zakończeniu opracowywania zmodyfikowany kod bazy danych jest sprawdzany w kontroli źródła, a konflikty są rozwiązywane. Następnie ostateczny kod (i dane, jeśli to konieczne) jest implementowany we wspólnym schemacie.
Po tym cały zespół programistów może ponownie zobaczyć tę samą bazę danych. Programista, który właśnie dostarczył kod, usuwa wszystkie obiekty ze swojego osobistego schematu i jest gotowy do nowego przypisania.
Ta zdolność do ułatwienia niezależnej pracy równoległej wielu programistom jest główną zaletą publicznych synonimów — znaczenie, które trudno przecenić. Jednak w praktyce nadal widzę zespoły tworzące publiczne synonimy we wdrożeniach Oracle „tylko dlatego, że zawsze to robimy”. Natomiast w zespołach korzystających z SQL Server nie uważam tworzenia publicznych synonimów za powszechną praktykę. Funkcjonalność istnieje, ale nie jest często używana.
W SQL Server bieżący domyślny schemat użytkownika jest zdefiniowany w konfiguracji użytkownika i można go zmienić w dowolnym momencie, jeśli masz uprawnienia „zmiennego użytkownika”. Można wdrożyć tę samą dokładną metodologię, jak opisano powyżej dla Oracle. Jeśli jednak ta metoda nie jest używana, publiczne synonimy nie powinny być kopiowane.
Ponieważ Microsoft SQL Server domyślnie nie kojarzy nowego konta użytkownika z własnym schematem (jak robi to Oracle), powiązanie powinno być częścią standardowego skryptu „utwórz użytkownika”.
Poniżej znajduje się przykład skryptu, który tworzy dedykowane schematy użytkownika i przypisuje go do użytkownika.
Najpierw utwórz schematy dla nowych użytkowników, które należy wprowadzić do bazy danych o nazwie DevelopmentDatabase
(każdy schemat musi być utworzony we własnej partii):
use DevelopmentDatabase; GO CREATE SCHEMA Dev1; GO CREATE SCHEMA Dev2; GO
Po drugie, utwórz pierwszego użytkownika z przypisanym domyślnym schematem:
CREATE LOGIN DevLogin123 WITH PASSWORD = 'first_pass123'; CREATE USER Dev1 FOR LOGIN DevLogin123 WITH DEFAULT_SCHEMA = Dev1; GO
W tym momencie domyślnym schematem dla użytkownika Dev1
będzie Dev1
.
Następnie utwórz innego użytkownika bez domyślnego schematu:
CREATE LOGIN DevLogin321 WITH PASSWORD = 'second_pass321'; CREATE USER Dev2 FOR LOGIN DevLogin321; GO
Domyślny schemat dla użytkownika Dev2
to dbo
.
Teraz zmień użytkownika Dev2
, aby zmienić jego domyślny schemat na Dev2
:
ALTER USER Dev2 WITH DEFAULT_SCHEMA = Dev2; GO
Teraz domyślnym schematem dla użytkownika Dev2
jest Dev2
.
Ten skrypt demonstruje dwa sposoby przypisywania i zmieniania domyślnego schematu dla użytkownika w bazach danych Microsoft SQL Server. Ponieważ SQL Server obsługuje wiele metod uwierzytelniania użytkowników (najczęściej jest to uwierzytelnianie Windows), a dołączanie użytkowników może być obsługiwane przez administratorów systemu, a nie administratorów baz danych, bardziej użyteczna będzie metoda ALTER USER
przypisywania/zmiany domyślnego schematu.
Uwaga: nazwa schematu jest taka sama jak nazwa użytkownika. Nie musi tak być w SQL Server, ale to moja preferencja, ponieważ (1) pasuje do tego, jak to się robi w Oracle i (2) upraszcza zarządzanie użytkownikami (odnosząc się do największych zastrzeżeń ze strony DBA, aby zrobić to dobrze po pierwsze) — znasz nazwę użytkownika i automatycznie znasz domyślny schemat użytkownika.
Wniosek : Publiczne synonimy są ważnym narzędziem do budowania stabilnego i dobrze chronionego środowiska programistycznego dla wielu użytkowników. Niestety, z moich obserwacji w branży wynika, że jest on częściej używany z niewłaściwych powodów — pozostawiając zespoły cierpiące na zamieszanie i inne wady publicznych synonimów, nie zdając sobie sprawy z ich korzyści. Zmiana tej praktyki w celu czerpania rzeczywistych korzyści z publicznych synonimów może przynieść realne korzyści w pracy zespołu programistycznego.

Zarządzanie dostępem do bazy danych i procesy zarządzania zmianami
Skoro właśnie rozmawialiśmy o wsparciu rozwoju równoległego przez duże zespoły, warto poruszyć jeden odrębny i często źle rozumiany temat: procesy kontroli zmian.
Zarządzanie zmianą często staje się formą biurokracji kontrolowanej przez kierowników zespołów i administratorów baz danych, pogardzaną przez zbuntowanych programistów, którzy chcą dostarczyć wszystko, jeśli nie „wczoraj”, to „teraz”.
Jako DBA zawsze stawiam bariery ochronne na drodze do „mojej” bazy danych. I mam bardzo dobry powód: baza danych to wspólny zasób.
Ćwierkać
W kontekście kontroli źródła zarządzanie zmianami jest ogólnie akceptowane, ponieważ umożliwia zespołowi powrót z nowego, ale uszkodzonego kodu do starego, ale działającego kodu. Jednak w kontekście bazy danych zarządzanie zmianą może wydawać się zestawem nieuzasadnionych barier i ograniczeń nakładanych przez administratorów baz danych: to czyste szaleństwo, które niepotrzebnie spowalnia rozwój!
Zostawmy na boku tyradę dewelopera: jestem DBA i nie będę rzucał w siebie kamieniami! Jako DBA zawsze stawiam bariery ochronne na drodze do „mojej” bazy danych. I mam bardzo dobry powód: baza danych to wspólny zasób.
Każdy zespół programistów — i każdy z ich programistów — ma bardzo konkretnie zdefiniowany cel i bardzo konkretny wynik. Jedynym celem, który codziennie stoi na biurku administratora baz danych, jest stabilność bazy danych jako współdzielonego zasobu. Administrator DBA pełni w organizacji wyjątkową rolę, ponieważ nadzoruje wszystkie działania programistyczne we wszystkich zespołach i kontroluje bazę danych, do której mają dostęp wszyscy programiści. To DBA zapewnia, że wszystkie projekty i wszystkie procesy działają bez wzajemnego zakłócania się i że każdy ma zasoby potrzebne do funkcjonowania.
Problem polega na tym, że zarówno zespoły deweloperskie, jak i DBA siedzą zamknięte w swoich wieżach z kości słoniowej.
Deweloperzy nie wiedzą, nie mają dostępu, a nawet nie dbają o to, co dzieje się w bazie danych, o ile działa ona dla nich dobrze. (Nie jest to ich rezultatem ani nie wpłynie to na ich ocenę wydajności).
Zespół DBA trzyma bazę danych blisko klatki piersiowej, chroniąc ją przed programistami, którzy „nic o niej nie wiedzą”, ponieważ ich celem zespołowym jest stabilność bazy danych. A najlepszym sposobem na zapewnienie stabilności jest zapobieganie destrukcyjnym zmianom — często skutkującym postawą ochrony bazy danych przed wszelkimi zmianami w jak największym stopniu.
Te sprzeczne postawy wobec bazy danych mogą, jak widziałem, prowadzić do animozji między zespołami programistycznymi a DBA i skutkować niemożliwym do pracy środowiskiem. Jednak administratorzy baz danych i zespół programistów muszą współpracować, aby osiągnąć wspólny cel: dostarczyć rozwiązanie biznesowe, które w pierwszej kolejności ich połączyło.
Będąc po obu stronach podziału między deweloperami a administratorami, wiem, że problem jest łatwy do rozwiązania, gdy administratorzy lepiej rozumieją wspólne zadania i cele zespołów programistycznych. Ze swojej strony programiści muszą postrzegać bazę danych nie jako abstrakcyjną koncepcję, ale jako wspólny zasób — i tam administrator DBA powinien przyjąć rolę nauczyciela.
Najczęstszym błędem popełnianym przez administratorów baz danych niebędących programistami jest ograniczanie dostępu programistów do słownika danych i narzędzi do optymalizacji kodu. Dostęp do widoków katalogu Oracle DBA_
, dynamicznych widoków V$
i tabel SYS
wydaje się wielu administratorom baz danych jako „uprzywilejowany DBA”, podczas gdy w rzeczywistości są to krytyczne narzędzia programistyczne.
To samo dotyczy SQL Server, z jedną komplikacją: dostęp do niektórych widoków systemowych nie może być przyznany bezpośrednio, ale jest to tylko część roli bazy danych SYSADMIN
, a tej roli nigdy nie należy przyznawać poza zespołem DBA. Można to rozwiązać (i powinno zostać rozwiązane w przypadku migracji projektu z Oracle do SQL Server), tworząc widoki i procedury składowane, które są wykonywane z uprawnieniami SYSADMIN
, ale są dostępne dla użytkowników niebędących użytkownikami DBA. Jest to zadanie programistyczne DBA do wykonania podczas konfigurowania nowego środowiska programistycznego SQL Server.
Ochrona danych jest jednym z głównych obowiązków administratora baz danych. Mimo to zespoły programistów często mają pełny dostęp do niefiltrowanych danych produkcyjnych, aby umożliwić rozwiązywanie problemów z biletami związanymi z danymi. Są to ci sami programiści, którzy mają ograniczony dostęp do struktury danych – struktury stworzonej przez nich lub w pierwszej kolejności dla nich.
Po ustanowieniu właściwych relacji roboczych między zespołami programistycznymi i DBA tworzenie dobrego procesu kontroli zmian staje się intuicyjne. Specyfiką i wyzwaniem zarządzania zmianami po stronie bazy danych jest jednocześnie sztywność i płynność bazy danych - struktura jest sztywna, dane są płynne.
Często zdarza się, że zarządzanie zmianą w przypadku modyfikacji struktury — tj. w języku definicji danych lub DDL — jest dobrze ugruntowane, podczas gdy zmiany danych nie mają wpływu na zarządzanie zmianami. Uzasadnienie jest proste – dane cały czas się zmieniają.
Ale jeśli przyjrzymy się temu bliżej, zobaczymy, że w każdym systemie wszystkie dane należą do jednej z dwóch kategorii: dane aplikacji i dane użytkownika.
Dane aplikacji to słownik danych, który definiuje zachowanie aplikacji i jest tak samo istotny dla jej procesów, jak dowolny kod aplikacji. Zmiany tych danych powinny podlegać ścisłym procesom kontroli zmian, tak jak w przypadku każdej innej zmiany aplikacji. Aby zapewnić przejrzystość procesu kontroli zmian dla zmian danych aplikacji, dane aplikacji i dane użytkownika powinny być wyraźnie rozdzielone.
W Oracle należy to zrobić, umieszczając dane aplikacji i użytkownika we własnym schemacie. W Microsoft SQL Server należy to zrobić umieszczając każdy z nich w osobnym schemacie lub – znacznie lepiej – w osobnej bazie danych. Dokonanie tych wyborów powinno być częścią planowania migracji: Oracle ma dwupoziomowe rozwiązywanie nazw (schemat/właściciel – nazwa obiektu), podczas gdy SQL Server ma trzypoziomowe rozwiązywanie nazw (baza danych – schemat/właściciel – nazwa obiektu).
Częstym źródłem nieporozumień między światami Oracle i SQL Server są — być może zaskakujące — terminy baza danych i serwer :
Termin serwera SQL | Termin Oracle | Definicja |
---|---|---|
serwer | baza danych (używana zamiennie z serwerem w potocznym języku, chyba że odnosi się konkretnie do sprzętu serwera, systemu operacyjnego lub elementów sieci; może istnieć jedna lub więcej baz danych na serwerze fizycznym/wirtualnym) | Działająca instancja, która może „rozmawiać” z innymi instancjami przez porty sieciowe |
baza danych (część serwera, zawiera wiele schematów/właścicieli) | schemat/właściciel | Grupowanie najwyższego poziomu |
Ta pomieszana terminologia powinna być jasno zrozumiana w projektach migracji międzyplatformowej, ponieważ błędna interpretacja terminów może skutkować nieprawidłowymi decyzjami dotyczącymi konfiguracji, które trudno rozwiązać z mocą wsteczną.
Prawidłowe oddzielenie aplikacji i danych użytkownika pozwala zespołowi DBA zająć się drugim najważniejszym problemem: bezpieczeństwem danych użytkownika. Ponieważ dane użytkowników znajdują się oddzielnie, bardzo łatwo będzie wdrożyć procedurę „tłuczenia szkła” w celu uzyskania dostępu do danych użytkownika w razie potrzeby.
Wniosek : Procesy kontroli zmian mają kluczowe znaczenie w każdym projekcie. W inżynierii oprogramowania zarządzanie zmianami po stronie bazy danych jest często zaniedbywane, ponieważ dane są postrzegane jako „zbyt płynne”. Ale właśnie dlatego, że dane są „płynne” i „trwałe” jednocześnie, dobrze zaprojektowany proces kontroli zmian powinien stanowić podstawę odpowiedniej architektury środowiska bazy danych.
O korzystaniu z narzędzi do migracji kodu
Standardowe narzędzia własne, Oracle Migration Workbench i SQL Server Migration Assistant, mogą być pomocne w migracjach kodu. Należy jednak wziąć pod uwagę zasadę 80/20: gdy kod zostanie zmigrowany w 80% poprawnie, rozwiązanie pozostałych 20% zajmie 80% wysiłku związanego z migracją.
Największym ryzykiem w korzystaniu z narzędzi migracyjnych jest zdecydowanie percepcja „srebrnej kuli”. Można pokusić się o myślenie: „To załatwi sprawę, a ja będę musiał tylko trochę posprzątać i posprzątać”. Obserwowałem projekt, który się nie powiódł z powodu takiej postawy zespołu konwersji i jego kierownictwa technicznego.
Z drugiej strony zajęło mi cztery dni robocze wykonanie podstawowej konwersji średniej wielkości systemu Microsoft SQL Server 2008 (około 200 obiektów) przy użyciu funkcji wymiany zbiorczej Notepad++ jako głównego narzędzia do edycji.
Żaden z krytycznych elementów migracji, którymi do tej pory się zajmowałem, nie może zostać rozwiązany za pomocą narzędzi do migracji.
Oczywiście, używaj narzędzi pomocy przy migracji, ale pamiętaj, że zapewniają one tylko pomoc w edycji. Wynikowy tekst wyjściowy musi mieć przegląd, modyfikację i – w niektórych przypadkach – przepisanie, aby stał się kodem nadającym się do produkcji.
Rozwój narzędzi sztucznej inteligencji może w przyszłości rozwiązać te braki narzędzi do migracji, ale spodziewałbym się, że różnice między bazami danych znikną wcześniej, a sam proces migracji stanie się niepotrzebny. Tak więc, dopóki tego typu projekty są potrzebne, będziemy musieli robić to po staremu, wykorzystując staromodną ludzką inteligencję.
Wniosek : Korzystanie z narzędzi wspomagających migrację jest pomocne, ale nie jest to „srebrna kula”, a każdy projekt konwersji nadal wymaga szczegółowego przeglądu powyższych punktów.
Migracje Oracle/SQL Server: zawsze przyjrzyj się bliżej
Oracle i Microsoft SQL Server to dwie najbardziej rozpowszechnione platformy RDBMS w środowisku korporacyjnym. Oba mają podstawową zgodność ze standardem ANSI SQL, a małe segmenty kodu można przenosić z bardzo małą modyfikacją, a nawet bez zmian.
To podobieństwo stwarza zwodnicze wrażenie, że migracja między dwiema platformami jest prostym, nieskomplikowanym zadaniem i że tę samą aplikację można łatwo zaadaptować z jednego zaplecza RDBMS do drugiego.
W praktyce takie migracje platform nie są trywialne i muszą uwzględniać drobne elementy wewnętrznego działania każdej platformy, a przede wszystkim sposób, w jaki wdrażają wsparcie dla najbardziej krytycznego elementu zarządzania danymi: transakcji.
Chociaż omówiłem dwie platformy RDBMS, które stanowią podstawę mojej wiedzy specjalistycznej, to samo ostrzeżenie — „wygląda podobnie, nie oznacza, że działa podobnie” — należy zastosować do przenoszenia kodu między dowolnymi innymi systemami zarządzania bazami danych zgodnymi z SQL. I we wszystkich przypadkach w pierwszej kolejności należy zwrócić uwagę na to, jak implementacja zarządzania transakcjami różni się między platformą źródłową i docelową.