fbpx
devstyle.pl - Blog dla każdego programisty
devstyle.pl - Blog dla każdego programisty
8 minut

Kilka słów o tabelach w obiektowym świecie – ORM czy SQL?


24.09.2018

Jakie języki programowania przewijają się najczęściej w ofertach pracy? Cokolwiek, w czym jesteś w stanie stworzyć jakiś back-end, nieśmiertelny JS i niemalże równie wszechobecny SQL tego lub innego sortu.

Na rozmowie czasem zdarzy nam się odpowiedzieć na pytanie dotyczące where’ów, selectów i innych joinów i… bywa, że jest to ostatni raz, gdy masz do czynienia w SQL-em w tej konkretnej firmie.

Słowem wstępu

Założę, że programujesz obiektowo. W takim razie niemalże na pewno zdarzyło Ci się stanąć przed wyborem bibliotek w momencie tworzenia rozwiązania lub przeglądać stos technologiczny istniejącego projektu. Myślę, że się nie pomylę, jeżeli napiszę, że w większości, jeśli nie we wszystkich przypadkach przed Twoimi oczami mignął jakiś ORM. Czasem okazuje się też, że SQL jest wymagany tylko i wyłącznie dlatego, że ten konkretny maper stoi nad tą, a nie inną technologią bazodanową.

Pozwól jednak, że nieco odejdę od tematu i się przedstawię, bo prawdopodobnie nie mieliśmy jeszcze okazji się poznać. Nazywam się Rafał Hryniewski i na co dzień pracuję z technologiami Microsoftu – głównie o nich będę Ci opowiadał. Goszczę tu po raz drugi, wliczając cykl „Wasze Historie”. Tym razem planuję zostać na dłużej i zająć się tematyką baz danych z perspektywy programisty obiektowego lub osoby, która nigdy wcześniej nie pracowała z bazą danych. Pokażę Ci, jak ogarnąć podstawy, jakie narzędzia masz do wyboru i jakie są ich mocne oraz słabe strony, jak podejrzeć i zabrać się za optymalizację tego, co wypluje z siebie Entity Framework, i wiele innych rzeczy, o których możesz nie wiedzieć, jeśli za bardzo nie wychylasz się zza używanego przez Ciebie ORM-a. Postaram się, by co jakiś czas dać Ci coś ciekawego do przeczytania niezależnie od tego, czy dopiero zaczynasz z bazami danych, czy masz już z nimi trochę doświadczenia.

Ale ja programuję obiektowo!

Wróćmy do tematu. Moim zdaniem bardzo mocno zaniedbaliśmy znajomość technologii bazodanowych. Pewnie, możemy napisać parę klasek, nadać kilka atrybutów, odpalić migrację i wszystko śmiga, baza stoi, ma nawet jakąś sensowną strukturę. To o wiele szybsze rozwiązanie niż składanie tabel do kupy ręcznie, zastanawianie się nad typami danych dla każdej kolumny i różne inne „pierdoły”. Podobnie sprawa ma się z pisaniem zapytań do naszej bazy – niby po co mielibyśmy męczyć się z czystym SQL-em w stringach, skoro możemy użyć doskonale znanego nam LINQ (w przypadku C#)?

Programujesz obiektowo? Jeśli tak, to jestem przekonany, że czujesz się o wiele bardziej komfortowo w świecie obiektów i kolekcji niż tabel i rekordów. Mogło Ci się też zdarzyć strukturyzować dane w bazie, myśląc o nich w kontekście klas, kolekcji i biorąc pod uwagę zasady pisania czystego kodu. Jak jednak mają się dobre praktyki obiektowe do dobrych praktyk bazodanowych? Najczęściej nijak i jeśli tylko wszystko będzie działać, to gdy liczba rekordów skoczy nam do kilkuset tysięcy lub więcej, możemy się obudzić z poważnymi problemami z wydajnością.

W SQL-u też należy dbać o porządek!

Wspomniałem o czystym kodzie. Niepokojącym mnie zwyczajem jest bezpośrednie mapowanie tabel na model obiektowy i działanie bezpośrednio na nim. Czy jest w tym coś złego? A nie brakuje Ci może jakiejkolwiek sensownej warstwy abstrakcji między bazą danych a DAL-em (data access layer)? Kilka drobnych zmian w bazie i dane mogą przestać się modyfikować albo odczytywać.

Co możemy zrobić? Tak samo jak w kodzie obiektowym posługujemy się np. interfejsami do wystawienia publicznych metod, tak w SQL-u możemy skorzystać z trzech różnych widoków zawierających wyłącznie dane specyficzne dla – powiedzmy – użytkownika, klienta i adresata paczki, używając w nich jednej tabeli Users. Podobnie możemy zrobić z przeróżnymi procedurami i funkcjami, a wszystko to ładnie zmapować w naszym ORM-ie.

Czy jest to bardziej pracochłonne? Tak. A co zyskujemy? Przede wszystkim to, że tak długo, jak nasz widok czy funkcja poprawnie zwraca dane w określonej strukturze, nie musimy się martwić o tym, jak to wszystko składane jest pod spodem do kupy. Mieliśmy plątaninę joinów, którą zastąpiliśmy implementacją grafów w SQL Server? Wystarczy, że przepiszemy kod naszego widoku i wszystko pozostanie w jak najlepszym porządku. Ba, możemy sobie pozwolić na całkiem spore optymalizacje, denormalizację w celu uproszczenia formy odczytywanych danych czy co jeszcze przyjdzie nam do głowy. A wiesz, co jest najpiękniejsze? Widoki, procedury i funkcje same w sobie na ogół nie przechowują danych, ich modyfikacje są błyskawiczne i nie wymagają zatrzymywania aplikacji.

Świat, którego nie znasz

Sam SQL zawiera mnóstwo narzędzi, które mogą Ci znacząco ułatwić życie. Zdarzyło Ci się kiedyś pisać skomplikowane wersjonowanie treści w kodzie obiektowym? SQL Server 2016 i wyższe mają funkcję zwaną Temporal Tables, która ogarnia wersjonowanie out of the box. Podobnie ma się sprawa z aplikacjami multi-tenant i row level security, maskowaniem danych, konstruktami znanymi z grafowych baz danych czy otwieraniem JSON-ów jako tabele. SQL potrafi zrobić naprawdę bardzo dużo z naszymi danymi, trzeba się z nim tylko troszeczkę zapoznać i przede wszystkim zgłębić jego możliwości.

O praktycznie każdym z elementów, które wymieniłem gdzieś wyżej, można stworzyć oddzielny wpis. O niektórych nawet kilka. Dlatego też nie opiszę ich wszystkich w tym miejscu – jeśli ciekawi Cię jakiś konkretny temat, daj znać w komentarzu, a postaram się napisać o tym coś więcej. Chciałem Ci tylko pokazać, że na tym poziomie istnieje naprawdę wiele rzeczy, o których można nie wiedzieć, jeśli wszystko przesłaniają Ci różowe okulary z ORM-ów. Nieco więcej na ten temat opowiadałem chociażby na swojej sesji na tegorocznym 4 Developers, nagranie możesz obejrzeć poniżej, a z prezentacją pewnie od czasu do czasu wyskoczę w Polskę, więc może nawet spotkamy się na żywo.

To w końcu używać czy nie?

Tytuł tego wpisu jest pytaniem, a ja wciąż nie udzieliłem na nie odpowiedzi. Wychwalam SQL-e pod niebiosa, płaczę, jakie te ORM-y są ubogie. Myślę, że doskonale wiesz, że odpowiedź brzmi jak zwykle: to zależy. Ja osobiście niemalże nie używam ORM-ów w swoich projektach, ale… czasem mi się zdarza i pracuję z nimi na co dzień, więc przydaje mi się wiedza o tym, co dokładnie leci do bazy danych po użyciu kilku metod w LINQ.

Używanie zarówno ORM, jak i czystego SQL ma swoje wady i zalety. Development np. z takim Entity Frameworkiem jest niesamowicie szybki, a szlifowanie procedur i widoków z każdej zbędnej milisekundy z pewnością nie jest zadaniem dla każdego (i – co ważniejsze – istotnym w każdym projekcie!) i może sprawić, że terminy realizacji staną się nierealne. Oba podejścia mają swoje wady, ale za najgorsze z nich uważam to trzecie, w którym zamykamy się na jakąś opcję dla zasady. „ORM to smutny syf i nie użyję go nawet do CRUD-a”, ”Nie dotknę SQL-a – jestem programistą obiektowym”.

Na tytułowe pytanie musisz odpowiedzieć samodzielnie. Pamiętaj jednak, że jeśli dobrze skonstruujesz swojego SQL-a, to raczej nie zaistnieje potrzeba przepisania go na jakiegokolwiek ORM-a, zwłaszcza jeśli zadbasz o odpowiednią abstrakcję po stronie bazy danych. I myślę, że to tego tematu możesz się ode mnie spodziewać w najbliższym czasie – jakich narzędzi użyć, by zbudować solidną warstwę abstrakcji między Twoją aplikacją a Twoją bazą.

To… o czym chcesz poczytać w przyszłości?

Notify of
Jerzy Wickowski

Coś czuję, że kolejne Twoje wpisy będą zdroworozsądkowo sensowne, ale z drugiej strony mięsisto techniczne. Dlaczego? Mam nadzieję, że uda Ci się spełnić takie oczekiwania :).

Maciej Aniserowicz

Wow Rafał widzisz? :) Super, znając Rafała: tak właśnie będzie!

Kamil
Kamil

W IT pracuje już ponad 10 lat i zawsze jak tylko przejmowaliśmy jakiś projekt to był problem z wykorzystywaniem ORM do granic możliwości byleby tylko SQLa nie pisać. Zapytania, które na bazie DEV działały 1 sekundę (mało danych) na produkcji potrafiły wykonywać się ponad 60 sekund; oczywiście nie wyszło to od razu, ponieważ początkowo produkcja tez miała mało rekordów, ale już po roku… Co więcej, jeden z największych minusów pisania zapytań tylko z poziomu ORMu – moim zdaniem – to brak możliwości prostego sprawdzenia jaki proces biznesowy w najbardziej obciąża serwer bazodanowy. Zapytania generowane przez ORM bardzo ciężko jest zdekodować,… Read more »

Jacek Brożyna
Jacek Brożyna

Zgadzam się w 100%. Często programiści przyzwyczajają się do używania ORMów w prostych projektach, a jak przychodzi działać z bazą mającą po kilkadziesiąt milionów rekordów i wyciągać dane z kilku tabel, okazuje się, że to nie działa… Nie po to firmy rozwijają bazy danych, żeby później programista używał tylko tabel, a widoki generował za nie jakiś ORM. Niestety, ale spotkałem się z opinią, że klient dokupi droższy serwer, zrobi klaster, jak system nie będzie dawał rady, bo to tańsze niż praca programisty… Problem w tym, że przy naprawdę dużych systemach, kiepsko napisany kod obsługujący bazę danych zwiększy tak bardzo koszty… Read more »

Marcin
Marcin

Ja swego czasu, gdy nie umiałem jeszcze dobrze EF-a to wszystkie zapytania pisałem w SQL-u lub procedurach czy funkcjach.
Teraz większość piszę w EF-ie, ale nie które bardziej skomplikowane zapytania piszę w procedurach i wywołuje za pomocą EF-a, tudzież robię widoki w sql-u ale też wywołuje w EF-ie.
Czy to jest słuszne podejście?, nie wiem. Ja pracuje w ten sposób bo jest to dla mnie łatwiejsze.
Może dzięki Twoim artykułom dowiem się (w końcu) jak można podejść do tego zagadnienia (ORM i/lub SQL).
Czekam na więcej.

Michał Kuliński

ORM or not to ORM, this the QUERY.

Kamil Tkacz
Kamil Tkacz

W poprzedniej firmie, gdzie pracowałem ogólnie brzydzili się SQL-em i tylko ORM-o rządziło. W obecnym miejscu pracy mam naokoło takich magików od SQL-a, że EF dawno nikt nie widział. Większość operacji jest wykonywana na SQL-u a C# służy praktycznie tylko do “wyplucia” tego co procedury zmieliły. Z jednej skrajności w drugą ;)
Z perspektywy czasu, widząc efekty obu podejść sądzę, że działanie na SQL-u daje większą kontrolę i przejrzystość. Czekam na dalsze spisy ;)

Magda

Bardzo ciekawy artykul-moze dlatego ze moja dzialka;)
Chetnie sie dowiem:
1. jak zrobic warstwe posrednia miedzy klasa a baza danych
2. jak I czy wogole zastapic ORM SQLem [jest to moje preferowane podejscie-bo SQL jest dla mnie banalnie prosty I faktycznie cuda na kiju mozna zrobic;)]
3. jakie metody zastosujesz do walidacji danych I zapewnienie im spojnosci [np. przy kasowaniu]

Kamil Grzybek

ad 3)
Zależy co walidujemy :) Najlepiej mieć walidację na każdej “warstwie” aplikacji:

a) gdy sprawdzamy dane wprowadzone przez użytkownika np. czy kwota jest nieujemna (logika aplikacji)
b) gdy sprawdzamy reguły biznesowe np. czy użytkownikowi należy się rabat (logika biznesowa)
c) gdy sprawdzamy integralność i spójność danych

Najczęściej a) i b) realizuje się w kodzie aplikacji. Można skorzystać do tego z gotowych bibliotek np. FluentValidation.

c) najczęściej jest realizowane w postaci zakładania constraintów na bazie. Czasami jednak jest to niemożliwe – np. w przypadku mikroserwisów, gdy każdy serwis posiada własną bazę danych i niemożliwe jest zakładanie FK pomiędzy bazami.

Dariusz Lenartowicz

“CQRS to the rescue”. Po stronie Command ORM doskonale wczytuje nam pełny agregat, nie mniej – nie więcej. Po stronie Query proste zapytania można puszczać przez ORMa, ale w sumie proste query można szybko w SQLu napisać, natomiast cięższe query już tylko czysty SQL (wydajne i skrojone na daną potrzebę zapytanie). Zakładając, że mamy do czynienia z dwoma modelami w kodzie, nawet jeśli pod spodem jest jeden model bazodanowy można osiągnąć przyzwoitą szybkość działania jak i czystość kodu.

Radosław Maziarka

Dokładnie – ORM jest dobrze stosować po stronie zapisu, ale często nie daje rady po stronie odczytu, wtedy dobrze zastosować SQLa.

Jacek
Jacek

A kto komu zabrania mieszać w różnych miejscach aplikacji ORM z SQLem?
Może nie “ORM czy SQL” a kiedy jedno a kiedy drugie bo to się nie wyklucza. Zwłaszcza przy rozsądnej architekturze.
Wynik z SQLa i tak często (zwykle) trzeba przerobić na jakieś obiekty.

Dariusz Lenartowicz

Od transformacji danych z bazy na “jakieś obiekty” są tzw. MicroORMy (nie mylić właśnie z “pełnymi” ORMami). :)

Jacek
Jacek

A dlaczego? Poza wydajnością ale to trzeba by sprawdzić.
Masz EF DbContext bez żadnych dbsetów
Pytasz tylko sqlem, który mapuje na obiekty. Będzie dużo wolniej niż jakimś mikro?

Adrian
Adrian

Czekam na więcej artykułów. Ostatnio bardzo mnie interesuje temat ORMów i chętnie poczytam coś więcej na ten temat. Stosunkowo niedawno dowiedziałem się o tym. Jakiś czas temu miałem okazję poznać Entity Framework, teraz zapoznaję się z Jpa i springiem. Bardzo fajny tekst

Pan Z
Pan Z

Dobry artykuł, ciekawie się czyta, a i niesie ze sobą dobrą dawkę wiedzy :)

Odpowiadając na pytanie z artykułu, czym byłbym zainteresowany, to otwieraniem JSON-ów jako tabele. Brzmi ciekawie, a nie spotkałem się jeszcze z tym. Słyszałem o w spraciu dla jsonów w Postgres’ie, ale to wydaje mi się nie to :)

Jacek
Jacek

Ale po co?

Jacek
Jacek

Ja po wysłaniu to się chwilę zastanawiałem o co chodzi z “otwieraniem JSONów jako tabele”.
Chyba założyłem, że chodzi o zserializowanie tabeli do JSON-a.

To co piszesz to raczej jest jakieś Object DB. Ja rozumiem sens zapisu JSONów nawet np logowania całej komunikacji przychodzącej tylko nie w tabelach i raczej bez SQL-a.

Kurs Gita

Zaawansowany frontend

Szkolenie z Testów

Szkolenie z baz danych

Facebook

Książka

Zobacz również