Wzorce projektowe Azure Table Storage z przykładami, oraz co powinniśmy wiedzieć – część 2

Wzorce projektowe Azure Table Storage z przykładami, oraz co powinniśmy wiedzieć - część 2

Każda aplikacja niezależnie czy działa w chmurze czy lokalnie potrzebuje jakiegoś miejsca do przechowywania danych.

W tym artykule chciałbym poświęcić trochę czasu na temat projektowania naszego miejsca na dane jakim jest Table Storage i wzorców projektowych jakie są dostępne (bądź rekomendowane przez Microsoft).

Jest to drugą część serii artykułów poświęconych Table Storage, oraz tematyki projektowania naszego storage tak aby działał efektywnie.

A więc przejdźmy do konkretów.

Table storage automatycznie indeksuje kolumny PartitionKey i RowKey dzięki temu wyszukiwanie po nich jest szybkie i efektywne. Co w sytuacji gdy musimy wyszukać nasze dane używając innych parametrów? Tutaj z pomocą przychodzą nam wzorce projektowe dla Table Storage.

Przejdźmy przez kilka z nich i zobaczmy jakie mają cechy, kiedy je stosować, oraz jakie mają wady.

Jako nasz przykład wykorzystamy Contoso Movies Library ;). Jest to aplikacja do przechowywania bazy filmów umożliwiająca przeszukiwanie z wykorzystaniem różnych filtrów.

Index entities pattern

Problem do rozwiązania

Chcemy znaleźć wszystkie komedie z datą premiery w 2011 roku. Jak do tego podejść? Przychodzi tutaj z pomocą Index entities pattern.

Index entities pattern 1
Index entities pattern 1

Index entities pattern 2
Index entities pattern 2

Prezentowany wzorzec ma na celu przygotowanie kolekcji Id encji lub innych atrybutów umożliwiających wyszukiwanie.

Przykład

            // Collection of ids
            List<string> moviesType1 = new List<string>();
            List<string> moviesType2 = new List<string>();

...

            // Generate some data
            Console.WriteLine("...Generate test data...");
            for (int i = 1; i <= 10; i++)
            {
                var movie = new Movie(type: "Comedy", title: $"Movie {i}")
                {
                    Id = i,
                    Title = $"Movie {i}",
                    Description = "Sample description",
                    Type = "Comedy",
                    Premiere = 2011,
                    Timestamp = new DateTimeOffset(DateTime.UtcNow)
                };

                moviesType1.Add(movie.Title);
                batchOperation1.Insert(movie);
            }

...

            // Insert Index Entities
            var index1 = new Index(partitionKey: "Comedy", rowKey: "2011") { IndexEntities = string.Join(',', moviesType1.ToArray()) };
            var index2 = new Index(partitionKey: "Horror", rowKey: "2001") { IndexEntities = string.Join(',', moviesType2.ToArray()) };

            TableOperation insert1 = TableOperation.Insert(index1);
            TableOperation insert2 = TableOperation.Insert(index2);

            // Execute insert operations
            Console.WriteLine("...Execute insert operations...");
            await table.ExecuteAsync(insert1);
            await table.ExecuteAsync(insert2);

Jakie mogą się pojawić problemy?

W prezentowanym wzorcu pojawia się pewien narzut związanych z generowaniem i aktualizowaniem kolekcji „Id”. W wypadku gdy dane znajdują się w tej samej tabeli możemy wykorzystać do aktualizacji EGT. Niestety nie jest to możliwe do realizacji w podejściu drugim gdzie dane znajdują się w innej tabeli.

Denormalization pattern

Problem do rozwiązania?

Chcemy pobrać dane filmu wraz z aktorami w nim występującymi. Jak do tego podejść? Tutaj przychodzi z pomocą Denormalization pattern.

W bazach danych relacyjnych taki problem był rozwiązywany typowo poprzez użycie np. JOIN w zapytaniu SQL lub tzw. lazy loading. Dla baz danych NoSql jaką jest Azure Table Storage bardziej efektywnym będzie pobranie tych danych z jednej tabeli i dokonanie odpowiedniej transformacji po stronie aplikacji lub w backend na serwerze.

Przykład

Denormalization pattern
Denormalization pattern

Jaki mogą pojawić się problemy

W prezentowanym przykładzie w skrajnej sytuacji może pojawić się problem z ilością dopuszczalnych kolumn w jednej tabeli. Należy przy tym pamiętać, że kolumny „techniczne” również są liczone. Również tutaj pojawia się problem, że po stronie aplikacji lub backend spoczywa odpowiedzialności za przekształcenie danych na odpowiednie obiekty.

Compound key pattern

Problem do rozwiązania?

Chcemy pobrać film z podanym tytułem i datą premiery, oraz znamy jego gatunek. Tutaj przychodzi z pomocą Compound key pattern.

Innymi słowy w bazie danych NoSql tworzymy dobrze nam znany tzw. klucz złożony z tym, że znajduje się on w indeksowanej kolumnie jaką jest RowKey. Korzystając z pary PartitionKey i RowKey możemy szybko zlokalizować nasze dane.

Przykład

Compound key pattern
Compound key pattern

Jaki mogą pojawić się problemy

W przypadku wykorzystania tego wzorca może pojawić się problem z przechowywaniem podwójnej ilość danych, oraz koniecznością aktualizacji kilku rekordów równocześnie.

Podsumowanie

Uff…A więc przeszliśmy przez kolejne kilka wzorców projektowych dla Azure Table Storage. Dajcie znać czy jest to dla was użyteczna wiedza, oraz czy obecna formuła jest lepsza od tej która była w poprzedniej części serii.

Przykłady kodu użyte w artykule możecie znaleźć na GitHub. Jeżeli chodzi o szczegóły na temat Azure Table Storage to odsyłam was do dokumentacji na stronie Microsoft.

Share