To pomysł, który słyszałem wielokrotnie w kilku miejscach. Niektórzy mniej lub bardziej uznają, że gdy próba rozwiązania problemu czysto w języku SQL przekracza pewien poziom złożoności, rzeczywiście powinieneś poradzić sobie z nim w kodzie.
Logika leżąca u podstaw tego pomysłu polega na tym, że w większości przypadków silnik bazy danych wykona lepszą pracę w znalezieniu najbardziej wydajnego sposobu wykonania zadania niż w kodzie. Zwłaszcza jeśli chodzi o uzależnienie wyników od operacji wykonywanych na danych. Prawdopodobnie dzięki nowoczesnym silnikom skutecznie JIT'ing + buforowanie skompilowanej wersji twojego zapytania, miałoby to sens na powierzchni.
Pytanie brzmi, czy wykorzystanie silnika bazy danych w ten sposób jest z natury złą praktyką projektową (i dlaczego). Linie zamazują się jeszcze bardziej, gdy cała logika istnieje w bazie danych i po prostu uderzasz ją za pomocą ORM.
źródło
Odpowiedzi:
Słowami laika:
Są to rzeczy, które wykonuje SQL, i wierzcie lub nie, widziałem to w kodzie:
Wykonanie tych czynności zamiast polegania na SQL lub RDBMS prowadzi do napisania ton kodu bez dodatkowej wartości , co oznacza więcej kodu do debugowania i utrzymania. Niebezpiecznie zakłada się, że dostęp do bazy danych będzie możliwy tylko za pośrednictwem aplikacji.
źródło
Chciałbym sformułować inaczej: „Nigdy nie rób w kodzie tego, co SQL Server może dla Ciebie zrobić dobrze ”.
Rzeczy takie jak manipulowanie ciągami, praca wyrażeń regularnych i takie, których nie zrobiłbym w SQL Server (z wyjątkiem SQL CLR).
Powyżej zwykle mówi się o takich rzeczach - przyłącza się, ustawia operacje i zapytania. Zamiarem tego jest przekazanie dużej części ciężkiego podnoszenia do SQL Server (w rzeczach, w których jest dobry) i zmniejszenie ilości IO tak bardzo, jak to możliwe (więc pozwól SQLowi wykonywać sprzężenia i filtrować za pomocą
WHERE
klauzuli, zwracając dużo mniejszy zestaw danych niż w innym przypadku).źródło
Kluczem do odpowiedzi jest to, że musisz poszukać SQL, który robi coś dobrze, a nie po prostu coś dla Ciebie. SQL jest niezwykle potężnym językiem. W połączeniu z wbudowanymi funkcjami może potencjalnie robić wiele rzeczy. Jednak fakt, że możesz zrobić coś w SQL, nie powinien być usprawiedliwieniem do tego, aby to robić w SQL.
Moim konkretnym kryterium przy podejmowaniu decyzji jest przyjrzenie się ilości danych, które odzyskasz, i liczbie podróży w obie strony: czy możesz zmniejszyć ilość danych, wysyłając zadanie do serwera, bez zwiększania liczby transakcji w obie strony wyłącza się, a następnie zadanie należy do serwera; jeśli ilość danych pozostaje taka sama lub wzrasta bez równoczesnego spadku liczby podróży w obie strony, zadanie należy do Twojego kodu.
Rozważ te przykłady:
źródło
WHERE
klauzuli.Krótko mówiąc , poprawne byłoby powiedzenie: „Nigdy nie wykonuj operacji specyficznych dla bazy danych w bazie kodu”, ponieważ są one lepiej adresowane w bazie danych.
Spójrz na przykład ustawionych operacji podstawowych . Jak zapewne wiesz, RDBMS są zbudowane do obsługi typowych operacji przechowywania danych i manipulacji.
Ponadto wybór projektu bazy danych odgrywa ważną rolę . Posiadanie RDBMS (MS SQL, Oracle itp.) Różni się od baz danych NoSQL, takich jak RavenDB.
źródło
Z reguły twoja baza danych ma więcej informacji do pracy niż aplikacja i może efektywniej wykonywać typowe operacje na danych. Baza danych przechowuje na przykład indeksy, a aplikacja musiałaby indeksować wyniki wyszukiwania na bieżąco. Tak więc wszystko inne jest równe, całkowite obciążenie pracą można zmniejszyć, przesuwając pracę do bazy danych, a nie do aplikacji.
Ale w miarę skalowania produktu zwykle łatwiej jest skalować aplikację niż skalować db. W dużych instalacjach często zdarza się, że liczba serwerów aplikacji przewyższa liczbę serwerów baz danych 10 do 1 lub więcej. Dodanie większej liczby serwerów aplikacji jest często prostą sprawą klonowania istniejącego serwera na nowy sprzęt. Z drugiej strony dodanie nowych serwerów baz danych jest znacznie trudniejsze.
W tym momencie mantra staje się ochroną bazy danych . Okazuje się, że buforując bazę danych
memcached
lub umieszczając ją w kolejce aktualizacji w dzienniku po stronie aplikacji, lub pobierając dane raz i obliczając statystyki w aplikacji, możesz radykalnie zmniejszyć obciążenie bazy danych, unikając konieczności uciekania się do jeszcze bardziej skomplikowana i delikatna konfiguracja klastra DB.źródło
Myślę, że źle byłoby nie wykorzystywać bazy danych do celów, do których jest przeznaczona. Nigdy nie widziałem żadnej bazy danych, w której reguły byłyby egzekwowane poza bazą danych zawierającą dobre dane. Przejrzałem setki baz danych.
Więc rzeczy, które należy zrobić w bazie danych:
Kontrola (kontrola tylko aplikacji nie śledzi wszystkich zmian w bazie danych i dlatego jest bezwartościowa).
Ograniczenia związane z fałszowaniem danych obejmują wartości domyślne, ograniczenia klucza obcego i reguły, które zawsze muszą być stosowane do wszystkich danych. Wszystkie dane nie zawsze są zmieniane lub wstawiane przez aplikację, istnieją jednorazowe poprawki danych, szczególnie dużych zestawów danych, które nie są praktyczne do wykonania jednego rekordu na raz (zaktualizuj te 100 000 rekordów, które zostały źle oznaczone jako status 1, kiedy powinny być 2 z powodu błędu kodu aplikacji lub zaktualizuj wszystkie rekordy od klienta A do klienta B, ponieważ firma B kupiła firmę A) oraz import danych i inne aplikacje, które mogą dotykać tej samej bazy danych.
ŁĄCZY SIĘ i filtrowanie klauzul gdzie (aby zmniejszyć liczbę rekordów wysyłanych przez sieć)
źródło
Baza danych jest dokładnie taka; warstwa danych Twojej aplikacji. Jego zadaniem jest dostarczenie do aplikacji wymaganych danych i przechowywanie podanych danych. Twoja aplikacja to miejsce na kod, który faktycznie działa z danymi; wyświetlanie, sprawdzanie poprawności itp.
Chociaż sentyment w linii tytułowej jest godny podziwu i dokładny do pewnego punktu (drobiazgowe filtrowanie, rzutowanie, grupowanie itp. Powinno się pozostawić w przeważającej liczbie przypadków DB), definicja „studni” może być zamówienie. Istnieje wiele zadań, które SQL Server może wykonywać przy wysokim poziomie wydajności, ale zadania, które można wykazaćże SQL Server działa poprawnie w izolowany, powtarzalny sposób, jest bardzo mało. SQL Management Studio to świetne IDE dla bazy danych (szczególnie biorąc pod uwagę inne opcje, z którymi pracowałem, jak TOAD), ale ma swoje ograniczenia, po pierwsze, że prawie wszystko, czego używasz do tego (lub dowolnego kodu proceduralnego, który wykonujesz w DB poniżej) jest z definicji „efektem ubocznym” (zmiana stanu leżącego poza domeną przestrzeni pamięci twojego procesu). Ponadto kod proceduralny w SQL Server jest dopiero teraz, z najnowszymi IDE i narzędziami, w stanie zmierzyć sposób, w jaki zarządzany kod może korzystać z metryk pokrycia i analizy ścieżki (dzięki czemu możesz wykazać, że to właśnie w przypadku wystąpienia instrukcji X , Y i Z, a test X ma na celu spełnienie warunku i wykonanie tej połowy, podczas gdy Y i Z wykonają „else” . To z kolei zakłada, że masz test, który może ustawić bazę danych z określonym stanem początkowym, wykonać kod proceduralny bazy danych przez jakąś akcję i zapewnić oczekiwane wyniki.
Wszystko to jest o wiele trudniejsze i wymaga więcej niż rozwiązanie zapewniane przez większość warstw dostępu do danych; zakładamy, że warstwa danych (i, w tym przypadku, DAL) wiedzą, jak wykonać swoją pracę, jeśli otrzymają prawidłowe dane wejściowe, a następnie przetestują, czy kod zapewnia prawidłowe dane wejściowe. Trzymając kod proceduralny, taki jak SP i wyzwalacze poza DB, i zamiast tego robiąc takie rzeczy w kodzie aplikacji, wspomniany kod aplikacji jest znacznie łatwiejszy do wykonania.
źródło
Jedną z rzeczy, o których ludzie nie zdają sobie sprawy, jest to, że wykonywanie całego przetwarzania na serwerze SQL niekoniecznie jest dobre, niezależnie od wpływu na jakość kodu.
Na przykład, jeśli chcesz pobrać niektóre dane, a następnie obliczyć coś z danych, a następnie zapisać te dane w bazie danych. Istnieją dwie możliwości:
Możesz pomyśleć, że drugie rozwiązanie jest zawsze najszybsze, ale to zdecydowanie nie jest prawda. Ignoruję, nawet jeśli SQL nie pasuje do problemu (tj. Regex i manipulacja ciągiem). Udawajmy, że masz SQL CLR lub coś podobnego, aby mieć nawet potężny język w bazie danych. Jeśli wykonanie podróży w obie strony zajmuje 1 sekundę i pobranie danych oraz 1 sekunda na ich przechowanie, a następnie 10 sekund na wykonanie obliczeń w poprzek. Robisz to źle, jeśli robisz to wszystko w bazie danych.
Jasne, golisz się 2 sekundy. Czy jednak zmarnowałeś 100% (przynajmniej) jednego rdzenia procesora na serwerze bazy danych przez 10 sekund, czy raczej zmarnowałeś ten czas na swoim serwerze internetowym?
Serwery WWW są łatwe do skalowania, bazy danych z drugiej strony są wyjątkowo drogie, szczególnie bazy danych SQL. Przez większość czasu serwery sieciowe są również „bezstanowe” i można je dodawać i usuwać według własnego uznania, bez dodatkowej konfiguracji niczego poza modułem równoważenia obciążenia.
Pomyśl więc nie tylko o stracie 2 sekund operacji, ale także o skalowalności. Po co marnować drogie zasoby, takie jak zasoby serwera bazy danych, kiedy można korzystać ze znacznie tańszych zasobów serwera WWW przy stosunkowo niewielkim wpływie na wydajność
źródło
Lubię na to patrzeć, ponieważ SQL powinien zajmować się tylko danymi. Reguły biznesowe, które decydują o tym, jak może wyglądać zapytanie, mogą wystąpić w kodzie. Ponowne wyrażenie lub sprawdzenie poprawności informacji powinno odbywać się w kodzie. Należy pozostawić SQL, aby po prostu dołączyć do tabeli, zapytać o dane, wstawić czyste dane itp.
To, co dostaje się do SQL, powinno być czystymi danymi, a SQL nie powinien tak naprawdę wiedzieć nic więcej niż musi go przechowywać, aktualizować, usuwać lub odzyskiwać. Zauważyłem, że zbyt wielu programistów chce rzucać swoją logiką biznesową i kodowaniem w SQL, ponieważ traktują dane jako swoją działalność. Oddziel swoją logikę od danych, a zobaczysz, że kod staje się czystszy i łatwiejszy w zarządzaniu.
Tylko moje 0,02 $.
źródło
Ogólnie zgadzam się, że kod powinien kontrolować logikę biznesową, a DB powinien być hashem wolnym od logiki. Ale oto kilka kontrapunktów:
Kod główny może wymuszać ograniczenia podstawowe, obce i wymagane (nie zerowe). Ograniczenia są logiką biznesową. Czy należy je pominąć w bazie danych, ponieważ duplikują kod?
Czy inne podmioty poza twoją kontrolą dotykają bazy danych? Jeśli tak, dobrze jest mieć ograniczenia narzucone blisko danych. Dostęp może być ograniczony do usługi sieciowej, która implementuje logikę, ale zakłada to, że byłeś tam „pierwszy” i masz moc egzekwowania korzystania z usługi na innych stronach.
Czy Twój ORM wykonuje osobne operacje wstawiania / aktualizacji dla każdego obiektu? Jeśli tak, wystąpią poważne problemy z wydajnością podczas przetwarzania wsadowego dużych zestawów danych. Ustaw operacje to droga. ORM będzie miał problem z dokładnym modelowaniem wszystkich możliwych połączonych zestawów, na których można wykonywać operacje.
Czy uważasz, że „warstwa” jest fizycznym podziałem na serwery, czy logicznym? Uruchamianie logiki na dowolnym serwerze teoretycznie może nadal wchodzić w jej warstwę logiczną. Możesz zorganizować podział, kompilując go do różnych bibliotek DLL, a nie tylko dzieląc serwery. Może to radykalnie wydłużyć czas reakcji (ale poświęcenie wydajności) przy jednoczesnym zachowaniu separacji obaw. Podzieloną bibliotekę DLL można później przenieść na inne serwery bez nowej wersji w celu zwiększenia przepustowości (kosztem czasu odpowiedzi).
źródło
Ten idiom dotyczy raczej utrzymywania reguł biznesowych, danych i relacji (danych, struktury i relacji). Nie jest to kompleksowe rozwiązanie dla każdego problemu, ale pomaga unikać rzeczy takich jak ręcznie utrzymywane liczniki rekordów, ręcznie utrzymywana integralność relacji itp., jeśli te rzeczy są dostępne na poziomie bazy danych. Więc jeśli ktoś inny przyjdzie i rozszerzy programy lub napisze inny program, który współdziała z bazą danych, nie będzie musiał wymyślić, jak zachować integralność bazy danych z poprzedniego kodu. Przypadek ręcznie utrzymywanego licznika rekordów jest szczególnie istotny, gdy ktoś inny chce stworzyć nowy program do interakcji z tą samą bazą danych. Nawet jeśli nowo utworzony program ma dokładnie odpowiedni kod dla licznika, oryginalny program i nowy uruchomiony mniej więcej w tym samym czasie mogą go uszkodzić. Istnieje nawet kod, który pobiera rekordy i sprawdza warunki przed zapisaniem nowego lub zaktualizowanego rekordu (w kodzie lub jako osobne zapytania), jeśli to możliwe, często można to osiągnąć bezpośrednio w instrukcji insert lub update. Ponownie może dojść do uszkodzenia danych. Silnik bazy danych gwarantuje atomowość; aktualizacja lub wstaw zapytanie z warunkami ma wpływ tylko na rekordy spełniające warunki i żadne zapytanie zewnętrzne nie może zmienić danych w połowie naszej aktualizacji. Istnieje wiele innych okoliczności, w których kod jest używany, gdy silnik bazy danych lepiej służy. Chodzi o integralność danych, a nie o wydajność. jest nawet dostępny kod, który pobiera rekordy i sprawdza warunki przed zapisaniem nowego lub zaktualizowanego rekordu (w kodzie lub jako osobne zapytania), jeśli to możliwe, często można to osiągnąć bezpośrednio w instrukcji insert lub update. Ponownie może dojść do uszkodzenia danych. Silnik bazy danych gwarantuje atomowość; aktualizacja lub wstaw zapytanie z warunkami ma wpływ tylko na rekordy spełniające warunki i żadne zapytanie zewnętrzne nie może zmienić danych w połowie naszej aktualizacji. Jest wiele innych okoliczności, w których kod jest używany, gdy silnik bazy danych lepiej służy. Chodzi o integralność danych, a nie o wydajność. jest nawet dostępny kod, który pobiera rekordy i sprawdza warunki przed zapisaniem nowego lub zaktualizowanego rekordu (w kodzie lub jako osobne zapytania), jeśli to możliwe, często można to osiągnąć bezpośrednio w instrukcji insert lub update. Ponownie może dojść do uszkodzenia danych. Silnik bazy danych gwarantuje atomowość; aktualizacja lub wstaw zapytanie z warunkami ma wpływ tylko na rekordy spełniające warunki i żadne zapytanie zewnętrzne nie może zmienić danych w połowie naszej aktualizacji. Jest wiele innych okoliczności, w których kod jest używany, gdy silnik bazy danych lepiej służy. Chodzi o integralność danych, a nie o wydajność. Silnik bazy danych gwarantuje atomowość; aktualizacja lub wstaw zapytanie z warunkami ma wpływ tylko na rekordy spełniające warunki i żadne zapytanie zewnętrzne nie może zmienić danych w połowie naszej aktualizacji. Istnieje wiele innych okoliczności, w których kod jest używany, gdy silnik bazy danych lepiej służy. Chodzi o integralność danych, a nie o wydajność. Silnik bazy danych gwarantuje atomowość; aktualizacja lub wstaw zapytanie z warunkami ma wpływ tylko na rekordy spełniające warunki i żadne zapytanie zewnętrzne nie może zmienić danych w połowie naszej aktualizacji. Istnieje wiele innych okoliczności, w których kod jest używany, gdy silnik bazy danych lepiej służy. Chodzi o integralność danych, a nie o wydajność.
Więc to właściwie dobry idiom lub zasada. Żadna wydajność nie pomoże w systemie z uszkodzonymi danymi.
źródło
Jak wspomniano wcześniej, celem jest wysyłanie i odbieranie jak najmniej danych z bazy danych, ponieważ podróże w obie strony są bardzo kosztowne pod względem czasowym. Ciągłe wysyłanie instrukcji SQL to strata czasu, szczególnie w przypadku bardziej złożonych zapytań.
Korzystanie z procedur przechowywanych w bazie danych pozwala programistom na interakcję z bazą danych, podobnie jak interfejs API, bez martwienia się o skomplikowany schemat z tyłu. Zmniejsza to również dane wysyłane do serwera, ponieważ wysyłane są tylko nazwa i kilka parametrów. W tym scenariuszu większość logiki biznesowej może nadal znajdować się w kodzie, ale nie w formie SQL. Kod zasadniczo przygotowuje to, co ma zostać wysłane lub wysłane z bazy danych.
źródło
Jest kilka rzeczy do zapamiętania:
źródło
Użyj narzędzia najbardziej odpowiedniego dla danego zadania. W celu zapewnienia integralności danych często jest to baza danych. W przypadku zaawansowanych reguł biznesowych jest to system oparty na regułach, taki jak JBoss Drools. W przypadku wizualizacji danych byłoby to ramy sprawozdawczości. itp.
Jeśli masz jakiekolwiek problemy z wydajnością, powinieneś następnie sprawdzić, czy jakieś dane mogą być buforowane lub czy implementacja w bazie danych byłaby szybsza. Ogólnie rzecz biorąc, koszt zakupu dodatkowych serwerów lub dodatkowej mocy w chmurze będzie znacznie niższy niż dodatkowy koszt konserwacji i wpływ dodatkowych błędów.
źródło