W SQL Server 2012 (lub dowolnej wersji od 2005 r.) Użycie SELECT *...
jest tylko możliwym problemem z wydajnością w instrukcji SELECT najwyższego poziomu zapytania.
NIE jest to więc problem w Views (*), w podkwerendach, w klauzulach EXIST, w CTE, ani w SELECT COUNT(*)..
itp. Itd. Uwaga: prawdopodobnie dotyczy to również Oracle, DB2 i być może PostGres (nie jestem pewien) , ale jest bardzo prawdopodobne, że w wielu przypadkach nadal stanowi problem dla MySql.
Aby zrozumieć, dlaczego (i dlaczego nadal może być problemem w SELECT najwyższego poziomu), pomocne jest zrozumienie, dlaczego kiedykolwiek był to problem, ponieważ użycie SELECT *..
„oznacza WSZYSTKIE kolumny ”. Ogólnie rzecz biorąc, to zwróci o wiele więcej danych, niż naprawdę chcesz, co oczywiście może spowodować dużo więcej IO, zarówno dysku, jak i sieci.
Mniej oczywiste jest to, że ogranicza to również to, jakich indeksów i planów zapytań może używać optymalizator SQL, ponieważ wie, że ostatecznie musi zwrócić wszystkie kolumny danych. Jeśli z góry może wiedzieć, że chcesz tylko określone kolumny, to często może korzystać z bardziej wydajnych planów zapytań, korzystając z indeksów zawierających tylko te kolumny. Na szczęście istnieje sposób, aby wiedzieć to z wyprzedzeniem, a mianowicie, aby wyraźnie określić kolumny, które chcesz na liście kolumn. Ale kiedy używasz „*”, rezygnujesz z tego na korzyść „po prostu daj mi wszystko, wymyślę, czego potrzebuję”.
Tak, istnieje również dodatkowe użycie procesora i pamięci do przetwarzania każdej kolumny, ale prawie zawsze jest niewielkie w porównaniu z tymi dwiema rzeczami: znaczny dodatkowy dysk i przepustowość sieci wymagana dla kolumn, których nie potrzebujesz, i konieczność korzystania z mniejszej ilości zoptymalizowany plan zapytań, ponieważ musi zawierać każdą kolumnę.
Co się zmieniło? Zasadniczo optymalizatory SQL z powodzeniem wprowadziły funkcję o nazwie „Optymalizacja kolumny”, która po prostu oznacza, że mogą teraz dowiedzieć się w podkwerendach niższego poziomu, jeśli rzeczywiście zamierzasz użyć kolumny na wyższych poziomach kwerendy.
Rezultatem tego jest to, że nie ma już znaczenia, jeśli użyjesz „SELECT * ..” na niższych / wewnętrznych poziomach zapytania. Zamiast tego naprawdę ważne jest to, co znajduje się na liście kolumn SELECT najwyższego poziomu. O ile nie użyjesz go SELECT *..
u góry, to znowu musisz założyć, że chcesz WSZYSTKIE kolumny, więc nie możesz efektywnie zastosować optymalizacji kolumn.
(* - zwróć uwagę, że w widokach występuje inny, mniejszy problem z wiązaniem, w *
którym nie zawsze rejestrują zmianę w listach kolumn, gdy używane jest „*”. Istnieją inne sposoby rozwiązania tego problemu i nie wpływa to na wydajność.)
Jest to fizycznie i problematycznie dozwolone
select * from table
, jednak jest to zły pomysł. Czemu?Przede wszystkim przekonasz się, że zwracasz niepotrzebne kolumny (wymagające dużych zasobów).
Po drugie, na dużej tabeli zajmie to więcej czasu niż nazywanie kolumn, ponieważ gdy wybierzesz *, tak naprawdę wybierasz nazwy kolumn z bazy danych i mówisz „daj mi dane, które są powiązane z kolumnami, które mają nazwy na tej innej liście . ” Jest to szybkie dla programisty, ale wyobraź sobie, że możesz to sprawdzić na komputerze banku, który może dosłownie setki tysięcy wyszukiwań w ciągu minuty.
Po trzecie, robienie tego w rzeczywistości utrudnia programistom. Jak często trzeba przerzucać się między SSMS a VS, aby uzyskać wszystkie nazwy kolumn?
Po czwarte, jest to znak leniwego programowania i nie sądzę, aby jakikolwiek programista chciał takiej reputacji.
źródło
Może to stanowić problem, jeśli umieścisz
Select * ...
kod w programie, ponieważ, jak wskazano wcześniej, baza danych może z czasem ulec zmianie i zawierać więcej kolumn niż oczekiwano podczas pisania zapytania. Może to prowadzić do awarii programu (najlepszy przypadek) lub program może pójść swoją drogą i uszkodzić niektóre dane, ponieważ szuka wartości pól, których nie był napisany do obsługi. Krótko mówiąc, kod produkcyjny powinien ZAWSZE określać pola, które należy zwrócić w poluSELECT
.Powiedziawszy to, mam mniejszy problem, gdy
Select *
jest częściąEXISTS
klauzuli, ponieważ wszystko, co zostanie zwrócone do programu, to wartość logiczna wskazująca powodzenie lub niepowodzenie wyboru. Inni mogą nie zgodzić się z tym stanowiskiem i szanuję ich opinię na ten temat. Kodowanie MOŻE być nieco mniej wydajneSelect *
niż kodowanie „Wybierz 1” wEXISTS
klauzuli, ale nie sądzę, aby istniało jakiekolwiek ryzyko uszkodzenia danych.źródło
Wiele odpowiedzi na pytanie, dlaczego
select *
jest źle, więc omówię to, kiedy czuję, że jest to właściwe lub przynajmniej OK.1) W EXISTS zawartość części SELECT zapytania jest ignorowana, dzięki czemu można nawet pisać
SELECT 1/0
i nie będzie to powodować błędów.EXISTS
po prostu sprawdza, czy niektóre dane zwrócą i na tej podstawie zwraca wartość logiczną.2) Może to rozpocząć burzę ogniową, ale lubię używać
select *
w wyzwalaczach tabeli historii. Przezselect *
, zapobiega to, że główna tabela nie otrzyma nowej kolumny bez dodawania kolumny do tabeli historii, a także błąd natychmiast po wstawieniu / aktualizacji / usunięciu do głównej tabeli. Zapobiegało to wielokrotnie, gdy programiści dodawali kolumny i zapomnieli dodać je do tabeli historii.źródło
SELECT 1
ponieważ w sposób oczywisty powiadamia przyszłych twórców kodu o twoich zamiarach. Nie jest to wymóg , ale jeśli... WHERE EXISTS (SELECT 1 ...)
go widzę, to oczywiście ogłasza się jako test prawdy.SELECT 1
z mitów, że wydajność byłaby lepsza niżSELECT *
. Obie opcje są jednak całkowicie do przyjęcia. Nie ma różnicy w wydajności ze względu na sposób, w jaki optymalizator obsługuje EXISTS. Ani żadnej różnicy w czytelności ze względu na słowo „ISTNIEJE”, które wyraźnie zapowiada test prawdy.Column8
do głównego stołu, zapominając o stole historii. Deweloper zapisuje sporo kodu zredagowanego w kolumnie 8. Następnie dodajeColumn9
do tabeli głównej; tym razem pamiętając o dodaniu do historii. Później podczas testów zdaje sobie sprawę, że zapomniał dodaćColumn9
do historii (dzięki twojej technice wykrywania błędów) i natychmiast ją dodaje. Teraz wyzwalacz wydaje się działać, ale dane w kolumnach 8 i 9 są pomieszane w historii. : S