Pytam, ponieważ tak wiele pytań, które widzę w języku SQL, brzmi: „To jest powolne. Jak to przyspieszyć”? Lub są tutoriale z informacją: „Zrób to w ten sposób, a nie w ten sposób, ponieważ jest szybszy”.
Wydaje mi się, że duża część SQL zna się na tym, jak zostanie wykonane wyrażenie, i na podstawie tej wiedzy wybiera style wyrażeń, które działają lepiej. Nie jest to zgodne z jednym aspektem deklaratywnego programowania - pozostawieniem systemu, aby zdecydował, jak najlepiej wykonać obliczenia, a Ty sam określisz, co powinno dać obliczenie.
Nie należy silnik SQL nie obchodzi, jeśli jest używana in
, exists
lub join
jeśli jest to naprawdę deklaratywne nie należy po prostu dać poprawną odpowiedź w rozsądnym czasie, jeśli to możliwe przez jedną z trzech metod? Ten ostatni przykład jest podpowiedzi przez ten ostatni post, który jest typu wymienionego w moim pierwszym akapicie.
Indeksy
Wydaje mi się, że najłatwiejszy przykład, jaki mogłem zastosować, dotyczy utworzenia indeksu dla tabeli. Gumph tutaj na w3schools.com próbuje nawet wyjaśnić to jako coś, czego użytkownik nie widział ze względu na wydajność. Ich opis wydaje się umieszczać indeksy SQL w obozie nie deklaratywnym i są one rutynowo dodawane ręcznie ze względów czysto wydajnościowych.
Czy to prawda, że jest to gdzieś idealna baza danych SQL, która jest znacznie bardziej deklaratywna niż cała reszta, ale ponieważ jest tak dobra, że się o niej nie słyszy?
źródło
select whatever from sometable where FKValue in (select FKValue from sometable_2 where other_value = :param)
. To powinno być trywialne, aby zobaczyć, jak przekształcić to za pomocąexists
lubjoin
.Odpowiedzi:
SQL jest teoretycznie deklaratywny. Ale wiesz, co mówią o różnicy między teorią a praktyką ...
U jej podstaw koncepcja „programowania deklaratywnego” nigdy nie była naprawdę skuteczna i prawdopodobnie nigdy nie będzie, dopóki nie będziemy mieli kompilatora opartego na sztucznej inteligencji, który jest w stanie patrzeć na kod i odpowiadać na pytanie „jaka jest intencja tego kodu?”. inteligentnie, w taki sam sposób, jak zrobiłby to autor. Sercem każdego języka deklaratywnego jest cała masa imperatywnego kodu, który próbuje gorączkowo rozwiązać ten problem bez pomocy sztucznej inteligencji.
Często działa zaskakująco dobrze, ponieważ najczęstsze przypadki to zwykłe przypadki , o których ludzie, którzy napisali implementację języka, wiedzieli i znaleźli dobre sposoby radzenia sobie. Ale wtedy natrafisz na przypadek krawędzi, którego implementator nie wziął pod uwagę, i widzisz, że wydajność spada szybko, ponieważ interpreter jest zmuszony wziąć kod znacznie bardziej dosłownie i obsługiwać go w mniej wydajny sposób.
źródło
I rarely hit an edge case in any of them that couldn't be solved within the framework.
Tak, właśnie o to chodzi: konieczność wymyślenia sposobu ich rozwiązania w ramach, ponieważ framework nie jest wystarczająco inteligentny, aby rozwiązać go tak, jak go pierwotnie zadeklarowałeś.Myślałem o tym kilka dni temu po optymalizacji SQL. Myślę, że możemy się zgodzić, że SQL jest „językiem deklaratywnym” w definicji Wikipedii:
Jeśli zastanawiasz się, ile rzeczy wykonano za zasłonami (patrząc na statystyki, decydując, czy indeks jest przydatny, wybierając zagnieżdżone, scalone lub łączenie mieszające itp. Itd.), Musimy przyznać, że dajemy tylko wysoki poziom logika, a baza danych zajęła się całą logiką przepływu kontroli niskiego poziomu.
Również w tym scenariuszu czasami optymalizator bazy danych potrzebuje pewnych „wskazówek” od użytkownika, aby uzyskać najlepsze wyniki.
Inną popularną definicją języka „deklaratywnego” jest (nie mogę znaleźć autorytatywnego źródła):
Jeśli zaakceptujemy tę definicję, napotkamy problemy opisane przez PO.
Pierwszym problemem jest to, że SQL daje nam wiele równoważnych sposobów definiowania „tego samego wyniku”. Prawdopodobnie jest to zło konieczne: im bardziej ekspresyjną moc dajemy językowi, tym bardziej prawdopodobne jest, że będą mieli różne sposoby wyrażania tego samego.
Na przykład poproszono mnie kiedyś o optymalizację tego zapytania:
Ponieważ typy były znacznie mniejsze niż klient, a
cust_type
na stole klienta znajdował się indeks , osiągnąłem wielką poprawę, przepisując go jako:W tym konkretnym przypadku, gdy zapytałem programistę, co chciał osiągnąć, powiedział mi: „Chciałem wszystkich typów klientów, dla których miałem co najmniej jednego klienta”, tak przy okazji, dokładnie tak można opisać zapytanie optymalizatora.
Jeśli więc mogę znaleźć równoważne i bardziej wydajne zapytanie, dlaczego optymalizator nie może zrobić tego samego?
Domyślam się, że dzieje się tak z dwóch głównych powodów:
SQL wyraża logikę:
skoro SQL wyraża logikę wysokiego poziomu, czy naprawdę chcielibyśmy, aby optymalizator „przechytrzył” nas i naszą logikę? Z entuzjazmem wykrzykiwałbym „tak”, gdyby nie tyle razy musiałem zmusić optymalizator do wybrania najbardziej wydajnej ścieżki wykonania. Myślę, że pomysł może polegać na tym, aby optymalizator działał jak najlepiej (również zmieniając naszą logikę), ale dać nam „mechanizm podpowiedzi”, który przyjdzie nam na ratunek, gdy coś zwariuje (byłoby jak włączenie koła + hamulca w samochód autonomiczny).
Więcej możliwości = więcej czasu
Nawet najlepszy optymalizator RDBMS nie testuje WSZYSTKICH możliwych ścieżek wykonania, ponieważ muszą one być naprawdę szybkie: jak dobrze byłoby zoptymalizować zapytanie od 100 ms do 10 ms, jeśli muszę spędzać za każdym razem 100 ms na wyborze najlepszej ścieżki? I to w przypadku optymalizatora respektującego naszą „logikę wysokiego poziomu”. Gdyby również przetestował wszystkie równoważne zapytania SQL, czas optymalizatora mógłby wzrosnąć wiele razy.
Innym dobrym przykładem przepisania zapytania, którego nie jest w stanie wykonać żaden RDBMS, jest (z tego interesującego posta na blogu )
niż można zapisać w ten sposób (wymagane funkcje analityczne)
źródło