Dlaczego SELECT * jest szkodliwy?

Dlaczego SELECT * jest zła praktyka? Czy nie oznacza to mniej zmian kodu, jeśli dodasz nową kolumnę, którą chcesz?

Rozumiem, że SELECT COUNT(*) jest problem z wydajnością na niektórych DBs, ale co, jeśli naprawdę chcesz każdą kolumnę?

 272
Author: OMG Ponies, 2010-09-03

15 answers

Istnieją naprawdę trzy główne powody:

  • Nieefektywność w przenoszeniu danych do konsumenta. Po wybraniu opcji * często pobierasz z bazy danych więcej kolumn, niż Twoja aplikacja naprawdę potrzebuje do działania. Powoduje to przenoszenie większej ilości danych z serwera bazy danych do klienta, co spowalnia dostęp i zwiększa obciążenie maszyn, a także zajmuje więcej czasu na podróżowanie po sieci. Jest to szczególnie prawdziwe, gdy ktoś dodaje nowe kolumny do bazy tabele, które nie istniały i nie były potrzebne, gdy pierwotni konsumenci zakodowali dostęp do danych.

  • Problemy z indeksowaniem. rozważ scenariusz, w którym chcesz dostroić zapytanie do wysokiego poziomu wydajności. Jeśli użyjesz * i zwrócisz więcej kolumn, niż faktycznie potrzebujesz, serwer często musiałby wykonać droższe metody odzyskiwania danych, niż mogłoby to mieć miejsce w przeciwnym razie. Na przykład, nie byłoby w stanie utworzyć indeks, który po prostu obejmuje kolumny na liście wybierz, a nawet jeśli tak (w tym wszystkie kolumny [shudder]), następny facet, który przyszedł i dodał kolumnę do tabeli bazowej, spowodowałby, że optymalizator zignoruje Twój zoptymalizowany indeks pokrycia i prawdopodobnie zauważysz, że wydajność Twojego zapytania spadnie znacznie bez łatwo widocznego powodu.

  • Problemy Wiążące. Po wybraniu opcji * możliwe jest pobranie dwóch kolumn o tej samej nazwie z dwóch różnych tabel. Często może to spowodować awarię konsumenta danych. Wyobraź sobie zapytanie łączące dwie tabele, z których obie zawierają kolumnę o nazwie "ID". Skąd konsument miałby wiedzieć, które jest które? SELECT * może również mylić widoki (przynajmniej w niektórych wersjach SQL Server), gdy zmienią się podstawowe struktury tabeli -- widok nie jest odbudowywany, a dane, które wracają, mogą być nonsensem. A najgorsze jest to, że możesz zadbać o to, aby nazwać swoje kolumny, jak chcesz, ale następny facet, który przyjdzie może nie wiedzieć, że musi się martwić o dodanie kolumny, która zderzy się z Twoimi już rozwiniętymi nazwami.

Ale nie wszystko jest złe dla SELECT *. Używam go do tych przypadków użycia:

  • Zapytania Ad-hoc. podczas próby debugowania czegoś, szczególnie poza wąską tabelą, z którą mogę nie być zaznajomiony, SELECT * jest często moim najlepszym przyjacielem. To pomaga mi po prostu zobaczyć, co się dzieje bez konieczności robienia boatload badań nad tym, co podstawowe nazwy kolumn to. To staje się większym "plusem", im dłuższe będą nazwy kolumn.

  • Gdy * oznacza "wiersz". w następujących przypadkach użycia SELECT * jest w porządku, a plotki, że jest zabójcą wydajności, to tylko miejskie legendy, które mogły mieć pewną Ważność wiele lat temu, ale nie teraz: {]}

    SELECT COUNT(*) FROM table;
    

    W tym przypadku * oznacza "policz wiersze". Jeśli użyjesz nazwy kolumny zamiast*, będzie liczyć wiersze, w których wartość tej kolumny wynosi not null . COUNT (*), dla mnie, naprawdę napędza do domu koncepcję, że liczysz wiersze , i unikasz dziwnych przypadków krawędziowych spowodowanych przez nulle eliminowane z Twoich agregatów.

    To samo dotyczy tego typu zapytań:

    SELECT a.ID FROM TableA a
    WHERE EXISTS (
        SELECT *
        FROM TableB b
        WHERE b.ID = a.B_ID);
    

    W każdej bazie danych wartej swojej soli, * oznacza po prostu "rząd". Nieważne, co umieścisz w subquery. Niektórzy ludzie używają identyfikatora b na liście SELECT, albo użyją numeru 1, ale IMO te konwencje są dość bezsensowne. Co Ty mean to "count the row" , i to właśnie oznacza*. Większość optymalizatorów zapytań jest wystarczająco inteligentna, aby to wiedzieć. (Choć szczerze mówiąc, Wiem tylko to prawda z SQL Server i Oracle.)

 326
Author: Dave Markle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-18 12:03:49

Znak gwiazdki,"*", w instrukcji SELECT jest skrótem dla wszystkich kolumn w tabeli(tabelach) biorących udział w zapytaniu.

Wydajność

Skrót * może być wolniejszy, ponieważ:

  • nie wszystkie pola są indeksowane, co wymusza Pełne skanowanie tabeli-mniej wydajne
  • to, co zapisujesz, aby wysłać SELECT * przez przewód, grozi pełnym skanowaniem tabeli
  • zwracanie większej ilości danych niż jest to konieczne
  • zwracanie kolumn końcowych za pomocą danych o zmiennej długości type can result in search overhead

Utrzymanie

Przy użyciu SELECT *:

  • ktoś, kto nie zna kodu, musiałby zapoznać się z dokumentacją, aby dowiedzieć się, jakie kolumny są zwracane, zanim będzie mógł dokonać właściwych zmian. Uczynienie kodu bardziej czytelnym, minimalizując wieloznaczność i pracę niezbędną dla osób nieznających kodu oszczędza więcej czasu i wysiłku na dłuższą metę.
  • Jeśli kod zależy od kolejności kolumn, SELECT * ukryje błąd oczekiwanie na wystąpienie, jeśli w tabeli została zmieniona kolejność kolumn.
  • nawet jeśli potrzebujesz każdej kolumny w momencie pisania zapytania, może to nie być w przyszłości
  • użycie komplikuje profilowanie

Design

SELECT * jest anty-pattern:

  • cel zapytania jest mniej oczywisty; kolumny używane przez aplikację są nieprzezroczyste
  • łamie regułę modułowości o używaniu ścisłego pisania, gdy tylko możliwe. Explicit jest prawie powszechnie lepszy.

Kiedy należy użyć "SELECT*"?

Dopuszczalne jest użycie SELECT *, gdy istnieje wyraźna potrzeba każdej kolumny w tabeli(tabelach), w przeciwieństwie do każdej kolumny, która istniała podczas pisania zapytania. Baza danych wewnętrznie rozszerzy * na pełną listę kolumn - nie ma różnicy w wydajności.

W Przeciwnym Razie, jawnie wymień każdą kolumnę, która ma być użyta w zapytaniu - najlepiej podczas używanie aliasu tabeli.

 93
Author: OMG Ponies,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-03 22:43:20

Nawet jeśli chcesz teraz zaznaczyć każdą kolumnę, możesz nie chcieć zaznaczać każdej kolumny po tym, jak ktoś doda jedną lub więcej nowych kolumn. Jeśli piszesz zapytanie za pomocą SELECT *, ryzykujesz, że w pewnym momencie ktoś może dodać kolumnę tekstu, która sprawi, że Twoje zapytanie będzie działać wolniej, nawet jeśli w rzeczywistości nie potrzebujesz tej kolumny.

Czy nie oznacza to mniej zmian kodu, jeśli dodasz nową kolumnę, którą chcesz?

Są szanse, że jeśli naprawdę chcesz użyj nowej kolumny, a następnie będziesz musiał wprowadzić sporo innych zmian w kodzie i tak. Zapisujesz tylko , new_column - tylko kilka znaków wpisywania.

 20
Author: Mark Byers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-03 22:11:34

Jeśli nazwiesz kolumny w instrukcji SELECT, zostaną one zwrócone w podanej kolejności i w ten sposób mogą być bezpiecznie odwoływane przez indeks numeryczny. Jeśli użyjesz " SELECT*", możesz otrzymać kolumny w dowolnej kolejności, a zatem możesz bezpiecznie używać kolumn tylko po nazwie. Jeśli nie wiesz z góry, co chcesz zrobić z każdą nową kolumną, która zostanie dodana do bazy danych, najbardziej prawdopodobnym prawidłowym działaniem jest zignorowanie jej. Jeśli zamierzasz ignorować nowe kolumny że get dodane do bazy danych, nie ma żadnych korzyści do ich pobierania.

 4
Author: supercat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-03 22:44:33

W wielu sytuacjach, SELECT * spowoduje błędy w czasie uruchamiania aplikacji, a nie w czasie projektowania. Ukrywa wiedzę o zmianach kolumn lub błędnych odniesieniach w aplikacjach.

 3
Author: Andrew Lewis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-03 22:07:46

Jeśli naprawdę chcesz każdą kolumnę, nie widziałem różnicy wydajności między select ( * ) a nazwaniem kolumn. Sterownik do nazw kolumn może być po prostu jednoznaczny z tym, jakie kolumny mają być widoczne w kodzie.

Często jednak nie chcemy każdej kolumny, a select (*) może spowodować niepotrzebną pracę serwera bazy danych i niepotrzebne informacje muszą być przekazywane przez sieć. Jest mało prawdopodobne, aby spowodować zauważalny problem, chyba że system jest intensywnie wykorzystywane lub łączność sieciowa jest powolna.

 3
Author: brabster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-03 22:08:08

Pomyśl o tym jako o zmniejszeniu sprzężenia między aplikacją a bazą danych.

Podsumowując aspekt "zapachu kodu" :
SELECT * tworzy dynamiczną zależność między aplikacją a schematem. Ograniczenie jej użycia jest jednym ze sposobów na zdefiniowanie zależności, w przeciwnym razie zmiana bazy danych ma większe prawdopodobieństwo awarii aplikacji.

 3
Author: Kelly S. French,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-03 23:01:33

Jeśli dodasz pola do tabeli, zostaną one automatycznie uwzględnione we wszystkich zapytaniach, w których używasz select *. Może to wydawać się wygodne, ale sprawi, że aplikacja będzie wolniejsza, ponieważ pobierasz więcej danych niż potrzebujesz, a w pewnym momencie Twoja aplikacja ulegnie awarii.

Istnieje limit ilości danych, które można pobrać w każdym wierszu wyniku. Jeśli dodasz pola do tabel, aby wynik przekroczył ten limit, podczas próby uruchomienia zostanie wyświetlony komunikat o błędzie zapytanie.

Jest to rodzaj błędów, które są trudne do znalezienia. Dokonujesz zmiany w jednym miejscu, a to wybucha w innym miejscu, które w ogóle nie wykorzystuje nowych danych. Może to być nawet rzadziej używane zapytanie, więc zajmie trochę czasu zanim ktoś go użyje, co jeszcze trudniej jest połączyć błąd ze zmianą.

Jeśli określisz, które pola chcesz w wyniku, jesteś bezpieczny przed tego rodzaju overflow.

 3
Author: Guffa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-12 10:40:50

Odniesienie zaczerpnięte z tego artykułu.

Nigdy nie używaj "SELECT*",

Znalazłem tylko jeden powód, aby użyć "SELECT *"

Jeśli masz specjalne wymagania i utworzone dynamiczne środowisko, gdy Dodaj lub Usuń kolumnę automatycznie obsługiwać przez kod aplikacji. W tym szczególnym przypadku nie trzeba zmieniać kodu aplikacji i bazy danych, co automatycznie wpłynie na środowisko produkcyjne. W tym przypadku możesz użyć opcji " wybierz*".

 2
Author: Anvesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-07 12:32:02

Ogólnie trzeba dopasować wyniki swojej SELECT * ... do struktur danych różnych typów. Bez określenia, w jakiej kolejności pojawiają się wyniki, prawidłowe wyrównanie wszystkiego może być trudne (a bardziej niejasne pola są znacznie łatwiejsze do pominięcia).

W ten sposób możesz dodawać pola do tabel (nawet w ich środku) z różnych powodów bez łamania kodu dostępu sql w całej aplikacji.

 1
Author: jkerian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-03 22:05:10

Użycie SELECT *, gdy potrzebujesz tylko kilku kolumn, oznacza o wiele więcej przesłanych danych niż potrzebujesz. Dodaje to przetwarzanie w bazie danych i zwiększa opóźnienia w dostawie danych do klienta. Dodaj do tego, że będzie zużywać więcej pamięci po załadowaniu, w niektórych przypadkach znacznie więcej, takich jak duże pliki BLOB, głównie chodzi o wydajność.

Oprócz tego, jednak łatwiej jest sprawdzić, patrząc na zapytanie, jakie kolumny są ładowane, bez konieczności sprawdzania, co jest w tabeli.

Tak, jeśli dodasz dodatkową kolumnę, będzie to szybsze, ale w większości przypadków chcesz / musisz zmienić kod za pomocą zapytania, aby zaakceptować nowe kolumny i istnieje potencjał, że uzyskanie tych, których nie chcesz / oczekujesz, może powodować problemy. Na przykład, jeśli chwycisz wszystkie kolumny, a następnie polegaj na kolejności w pętli, aby przypisać zmienne, a następnie dodać jedną lub jeśli kolejność kolumn się zmieni (zauważyłeś, że dzieje się to podczas przywracania z kopii zapasowej), może rzucić wszystko wyłącz.

Jest to również ten sam rodzaj rozumowania, dlaczego jeśli robisz INSERT należy zawsze podawać kolumny.

 1
Author: Tarka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-03 22:07:23

Nie wydaje mi się, żeby naprawdę istniała na to ogólna zasada. W wielu przypadkach unikałem SELECT *, ale pracowałem również z frameworkami danych, w których SELECT * był bardzo korzystny.

Jak w przypadku wszystkich rzeczy, są korzyści i koszty. Myślę, że częścią równania korzyści vs. koszt jest tylko jak wiele kontroli masz nad strukturami danych. W przypadkach, gdy SELECT * działał dobrze, struktury danych były ściśle kontrolowane( było to oprogramowanie detaliczne), więc nie było zbyt wiele ryzyko, że ktoś będzie sneek ogromne pole BLOB do stołu.

 1
Author: JMarsch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-03 22:09:06

Wybranie z nazwą kolumny zwiększa prawdopodobieństwo, że silnik bazy danych może uzyskać dostęp do danych z indeksów, a nie odpytywać dane tabeli.

SELECT * naraża system na nieoczekiwane zmiany wydajności i funkcjonalności w przypadku zmiany schematu bazy danych, ponieważ masz zamiar uzyskać nowe kolumny dodane do tabeli, mimo że Twój kod nie jest przygotowany do użycia lub przedstawienia tych nowych danych.

 1
Author: Aradhana Mohanty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-22 12:20:25

Jest też bardziej pragmatyczny powód: pieniądze. Gdy korzystasz z bazy danych w chmurze i musisz zapłacić za przetwarzane dane, nie ma wyjaśnienia, aby odczytać dane, które natychmiast odrzucisz.

Na przykład: BigQuery :

Cennik zapytań

Wycena zapytań odnosi się do kosztów uruchamiania poleceń SQL i funkcji zdefiniowanych przez użytkownika. BigQuery pobiera opłaty za zapytania za pomocą jednej metryki: liczby przetwarzanych bajtów.

I sterowanie projekcją-unikaj wyboru *:

Najlepsza praktyka: sterowanie projekcją-Odpytywaj tylko kolumny, których potrzebujesz.

Projekcja odnosi się do liczby kolumn, które są odczytywane przez zapytanie. Wyświetlanie nadmiaru kolumn powoduje dodatkowe (zmarnowane) We / Wy i materializację (zapisywanie wyników).

Korzystanie z SELECT * jest najdroższym sposobem zapytania danych. Gdy używasz SELECT *, BigQuery wykonuje pełne skanowanie każdej kolumny w stolik.

 1
Author: Lukasz Szozda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-05 20:08:43

Zrozum swoje wymagania przed zaprojektowaniem schematu (jeśli to możliwe).

Poznaj dane, 1) indeksowanie 2) rodzaj stosowanego przechowywania, 3) Silnik dostawcy lub funkcje; tj...buforowanie, możliwości w pamięci 4) typy danych 5) rozmiar tabeli 6) częstotliwość zapytań 7) powiązane obciążenia, jeśli zasób jest współdzielony 8) Test

A) wymagania będą się różnić. Jeśli sprzęt nie może obsługiwać oczekiwanego obciążenia, należy ponownie ocenić, jak zapewnić wymagania w obciążeniu pracą. Odnośnie kolumny dodawania do tabeli. Jeśli baza danych obsługuje widoki, możesz utworzyć indeks(?) widok konkretnych danych z określonymi nazwanymi kolumnami (vs. wybierz"*"). Okresowo przeglądaj Dane i schemat, aby upewnić się, że nigdy nie napotkasz syndromu "garbage-in" -> "Garbage-out".

Zakładając, że nie ma innego rozwiązania; możesz wziąć pod uwagę następujące kwestie. Zawsze istnieje wiele rozwiązań problemu.

1) indeksowanie: Select * wykona tablescan. W zależności od różnych czynników może to wiązać się z poszukiwaniem dysku i / lub rywalizacją z innymi zapytaniami. Jeśli tabela jest wielozadaniowa, upewnij się, że wszystkie zapytania są wydajne i wykonują się poniżej czasów docelowych. Jeśli istnieje duża ilość danych, a Twoja sieć lub inny zasób nie jest dostrojony; musisz wziąć to pod uwagę. Baza danych jest współdzielonym środowiskiem.

2) rodzaj przechowywania. Ie: jeśli używasz dysków SSD, dysku lub pamięci. Czasy wejścia / wyjścia i obciążenie systemu / procesora będzie się różnić.

3) Czy DBA może dostroić bazę danych / tabele dla wyższej wydajności? Niezależnie od przyczyny, zespoły zdecydowały, że Wybierz ' * ' jest najlepszym rozwiązaniem problemu; czy DB lub Tabela mogą być ładowane do pamięci. (Lub inną metodą...może odpowiedź została zaprojektowana tak, aby reagować z opóźnieniem 2-3 sekund? --- podczas gdy reklama gra w celu uzyskania przychodów firmy...)

4) Zacznij od początku. Zrozumienie typów danych i sposobu uzyskiwania wyników być przedstawione. Mniejsze typy danych, Ilość pól zmniejsza ilość danych zwracanych w zestawie wynikowym. Pozostawia to zasoby dostępne dla innych potrzeb systemowych. Zasoby systemowe zwykle mają limit; "zawsze" działają poniżej tych limitów, aby zapewnić stabilność i przewidywalne zachowanie.

5) wielkość tabeli / danych. wybierz ' * ' jest wspólne dla małych tabel. Zazwyczaj mieszczą się w pamięci, a czasy reakcji są szybkie. Jeszcze raz....Przejrzyj swoje wymagania. Plan funkcji pełzania; zawsze zaplanuj obecne i możliwe przyszłe potrzeby.

6) Częstotliwość zapytań / zapytań. Należy pamiętać o innych obciążeniach w systemie. Jeśli to zapytanie odpala się co sekundę, a tabela jest mała. Zestaw wyników może być zaprojektowany tak, aby pozostawał w pamięci podręcznej/pamięci. Jeśli jednak zapytanie jest częstym procesem wsadowym z gigabajtami / Terabajtami danych...być może lepiej będzie przeznaczyć dodatkowe zasoby, aby upewnić się, że inne obciążenia nie zostaną naruszone.

7) powiązane obciążenia. Zrozumieć, jak zasoby są wykorzystywane. Czy sieć / system/baza danych/tabela / aplikacja jest dedykowana czy współdzielona? Kim są zainteresowane strony? Czy to do produkcji, rozwoju, czy QA? Czy jest to tymczasowe "szybkie naprawienie". Przetestowałeś scenariusz? Będziesz zaskoczony, jak wiele problemów może istnieć obecnie na obecnym sprzęcie. (Tak, wydajność jest szybka...ale projekt/wydajność jest nadal zdegradowany.) Czy system musi wykonywać 10K zapytań na sekundę vs. 5-10 zapytań na sekundę. Czy serwer bazy danych dedykowane lub inne aplikacje monitorują wykonanie na udostępnionym zasobie. Niektóre aplikacje / języki; O/S zużywają 100% pamięci powodując różne objawy / problemy.

8) Test: Przetestuj swoje teorie i zrozum jak najwięcej na temat. Twój wybrany problem " * " może być poważnym problemem lub może być czymś, o co nie musisz się nawet martwić.

 0
Author: kllee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-07 17:19:53