Krótko mówiąc, zgodziłbym się z twoim CTO. Prawdopodobnie osiągnąłeś pewną wydajność kosztem skalowalności (jeśli te warunki są mylące, wyjaśnię poniżej). Moimi dwoma największymi obawami byłyby łatwość konserwacji i brak opcji skalowania w poziomie (zakładając, że będziesz tego potrzebować).
Odległość od danych: cofnijmy się o krok. Istnieje kilka dobrych powodów, aby wypychać kod do bazy danych. Argumentowałbym, że największym z nich jest bliskość danych - na przykład, jeśli spodziewasz się, że obliczenia zwrócą garść wartości, ale są to agregacje milionów rekordów, wysyłające miliony rekordów (na żądanie) ponad sieć, która ma być agregowana w innym miejscu, jest ogromnie marnotrawstwem i może łatwo zabić twój system. Powiedziawszy to, możesz osiągnąć tę bliskość danych na inne sposoby, zasadniczo używając pamięci podręcznej lub baz danych analizy, w których część agregacji jest wykonywana z góry.
Wydajność kodu w DB:Wtórne efekty wydajności, takie jak „buforowanie planów wykonania” są trudniejsze do argumentowania. Czasami buforowane plany wykonania mogą być bardzo negatywne, jeśli buforowany został niewłaściwy plan wykonania. W zależności od RDBMS możesz uzyskać jak najwięcej z nich, ale w większości przypadków nie uzyskasz dużo więcej niż sparametryzowany SQL (te plany również zwykle są buforowane). Argumentowałbym również, że większość skompilowanych lub JIT'owanych języków zazwyczaj działa lepiej niż ich odpowiedniki SQL (takie jak T-SQL lub PL / SQL) w podstawowych operacjach i programowaniu nierelacyjnym (manipulacja ciągami, pętle itp.), Więc nie nic tam nie stracisz, jeśli użyjesz czegoś takiego jak Java lub C #, aby skrócić liczbę. Drobnoziarnista optymalizacja jest również dość trudna - w DB możesz „ często utknąłem z ogólnym B-drzewem (indeksem) jako jedyną strukturą danych. Szczerze mówiąc, pełna analiza, w tym takie jak dłuższe transakcje, eskalacja blokady itp., Może wypełnić książki.
Konserwowalność: SQL jest wspaniałym językiem do tego, do czego został zaprojektowany. Nie jestem pewien, czy świetnie pasuje do logiki aplikacji. Większość narzędzi i praktyk, które czynią nasze życie znośnym (TDD, refaktoryzacja itp.), Jest trudna do zastosowania w programowaniu baz danych.
Wydajność a skalowalność:Aby wyjaśnić te warunki, mam na myśli to: wydajność to szybkość, z jaką można oczekiwać, że jedno żądanie przejdzie przez system (i wróci do użytkownika), na chwilę przy założeniu niskiego obciążenia. Będzie to często ograniczone przez takie rzeczy, jak liczba warstw fizycznych, przez które przechodzi, jak dobrze zoptymalizowane są te warstwy itp. Skalowalność to zmiana wydajności wraz ze wzrostem liczby użytkowników / obciążenia. Możesz mieć średnią / niską wydajność (powiedzmy 5 sekund + na żądanie), ale niesamowitą skalowalność (w stanie obsłużyć miliony użytkowników). W twoim przypadku prawdopodobnie osiągniesz dobrą wydajność, ale twoja skalowalność będzie ograniczona przez to, jak duży serwer możesz fizycznie zbudować. W pewnym momencie przekroczysz ten limit i będziesz zmuszony przejść do takich rzeczy, jak sharding, co może nie być możliwe w zależności od charakteru aplikacji.
Przedwczesna optymalizacja: myślę, że popełniłeś błąd, optymalizując przedwcześnie. Jak zauważyli inni, tak naprawdę nie ma pomiarów pokazujących, jak działałyby inne podejścia. Cóż, nie zawsze możemy zbudować prototypy w pełnej skali, aby udowodnić lub obalić teorię ... Ale ogólnie zawsze wahałbym się przed wyborem podejścia, które wymienia łatwość utrzymania (prawdopodobnie najważniejszą jakość aplikacji) w zakresie wydajności .
EDYCJA: Z pozytywnego punktu widzenia, pionowe skalowanie może rozciągać się dość daleko w niektórych przypadkach. O ile mi wiadomo, SO działało na jednym serwerze przez dłuższy czas. Nie jestem pewien, jak pasuje do twoich 10 000 użytkowników (wydaje mi się, że będzie to zależeć od charakteru tego, co robią w twoim systemie), ale daje ci wyobrażenie o tym, co można zrobić (w rzeczywistości są daleko bardziej imponujące przykłady, jest to po prostu popularny, który ludzie mogą łatwo zrozumieć).
EDYCJA 2: Aby wyjaśnić i skomentować kilka kwestii poruszonych w innym miejscu:
- Re: Spójność atomowa - Spójność ACID może być wymogiem systemu. Powyższe tak naprawdę nie przemawia przeciwko temu i powinieneś zdawać sobie sprawę, że spójność ACID nie wymaga od ciebie uruchamiania całej logiki biznesowej w bazie danych. Przesuwając kod, który tego nie robi musi tam być, do bazy danych, ograniczasz go do działania w środowisku fizycznym reszty bazy danych - konkuruje on o te same zasoby sprzętowe, co rzeczywista część bazy danych w zarządzaniu danymi. Jeśli chodzi o skalowanie tylko kodu na inne serwery DB (ale nie rzeczywiste dane) - jasne, może to być możliwe , ale co dokładnie zyskujesz, oprócz dodatkowych kosztów licencji w większości przypadków? Trzymaj rzeczy, które nie muszą znajdować się na DB, poza DB.
- Re: Wydajność SQL / C # - ponieważ wydaje się to być przedmiotem zainteresowania, dodajmy trochę do dyskusji. Z pewnością możesz uruchomić natywny / Java / C # kod w DB, ale o ile mi wiadomo, nie o to tu dyskutowano - porównujemy implementację typowego kodu aplikacji w coś takiego jak T-SQL w porównaniu do czegoś takiego jak C #. Istnieje szereg problemów, które w przeszłości trudno było rozwiązać za pomocą kodu relacyjnego - np. Weź pod uwagę problem „maksymalnej liczby równoczesnych logowań”, w którym masz rekordy wskazujące na logowanie lub wylogowanie oraz czas i musisz ustalić, jakie maksymalna liczba użytkowników zalogowanych jednocześnie. Najprostszym możliwym rozwiązaniem jest iteracja rekordów i ciągłe zwiększanie / zmniejszanie licznika podczas napotkania logowań / wylogowań oraz śledzenie maksymalnej wartości tej wartości.może, Nie wiem), najlepsze, co możesz zrobić, to KURSOR (rozwiązania czysto relacyjne mają różne stopnie złożoności, a próba ich rozwiązania za pomocą pętli while powoduje gorszą wydajność). W tym przypadku tak, rozwiązanie C # jest faktycznie szybsze niż to, co można osiągnąć w T-SQL, kropka. To może wydawać się zbyt daleko idące, ale ten problem może łatwo objawić się w systemach finansowych, jeśli pracujesz z wierszami reprezentującymi zmiany względne i musisz obliczyć na nich agregacje okienkowe. Przechowywane wywołania proc również wydają się być droższe - wywołuj trywialny SP milion razy i zobacz, jak to się ma do wywołania funkcji C #. Podpowiedziałem kilka innych przykładów powyżej - jeszcze nie spotkałem nikogo, kto zaimplementuje prawidłową tablicę skrótów w T-SQL (która faktycznie daje pewne korzyści), podczas gdy jest to dość łatwe w C #. Znów są rzeczy, w których DB są świetne, i rzeczy, w których nie są tak świetne. Tak jak nie chciałbym wykonywać JOIN, SUM i GROUP BY w C #, nie chcę pisać w języku T-SQL nic szczególnie wymagającego pod względem procesora.