Dlaczego „Wybierz * z tabeli” jest uważane za złą praktykę

96

Wczoraj rozmawiałem z programistą „hobby” (sam jestem profesjonalnym programistą). Spotkaliśmy się z niektórymi jego pracami i powiedział, że zawsze odpytuje wszystkie kolumny w swojej bazie danych (nawet na / w serwerze / kodzie produkcyjnym).

Próbowałem go przekonać, żeby tego nie robił, ale nie odniosłem jeszcze takiego sukcesu. Moim zdaniem programista powinien zapytać tylko, co jest faktycznie potrzebne ze względu na „ładność”, wydajność i ruch. Czy mylę się z moim poglądem?

bekonowanie
źródło
1
Powiedziałbym, że co, jeśli zawartość tabeli się zmieni? dodawać / usuwać kolumny? nadal wybierasz * .., więc będziesz tracić rzeczy lub cofać więcej danych, niż potrzebujesz.
JF it
2
@JFit To część tego, ale dalekie od całej historii.
jwenting
6
I dobre powody, dlaczego wybór * uważa się za szkodliwy?
Ellie Kesselman
@gnat czy pytanie naprawdę można uznać za duplikat pytania zamkniętego? (tj. ponieważ zamknięty nie był w ogóle odpowiedni)
gbjbaanb

Odpowiedzi:

67

Pomyśl o tym, co otrzymujesz i jak powiążesz je ze zmiennymi w kodzie.

Zastanów się teraz, co się stanie, gdy ktoś zaktualizuje schemat tabeli, aby dodać (lub usunąć) kolumnę, nawet taką, z której nie korzystasz bezpośrednio.

Używanie select * podczas pisania zapytań ręcznie jest w porządku, a nie podczas pisania zapytań o kod.

gbjbaanb
źródło
8
Wydajność, obciążenie sieci itp. Są znacznie ważniejsze niż wygoda przywracania kolumn w kolejności i pod żądaną nazwą.
jwenting
21
@jwenting naprawdę? wydajność jest ważniejsza niż poprawność? W każdym razie nie widzę, aby „select *” działało lepiej niż zaznaczanie tylko tych kolumn, które chcesz.
gbjbaanb
9
@Bratch, w rzeczywistych środowiskach produkcyjnych możesz mieć setki aplikacji korzystających z tych samych tabel i nie ma możliwości, aby wszystkie te aplikacje mogły być odpowiednio obsługiwane. Masz rację, ale praktycznie argument nie udaje się z powodu realiów pracy w firmach. Ciągłe zmiany schematu w aktywnych tabelach.
użytkownik1068,
18
Nie rozumiem sensu tej odpowiedzi. Jeśli dodasz kolumnę do tabeli, zarówno SELECT *, jak i SELECT [Kolumny] będą działać, jedyną różnicą jest to, że jeśli kod musi zostać powiązany z nową kolumną, SELECT [Kolumny] będzie musiał zostać zmodyfikowany, podczas gdy WYBIERZ * nie będzie. Jeśli kolumna zostanie usunięta z tabeli, SELECT * ulegnie zerwaniu w punkcie wiązania, a SELECT [Kolumny] zepsuje się podczas wykonywania zapytania. Wydaje mi się, że SELECT * jest bardziej elastyczną opcją, ponieważ wszelkie zmiany w tabeli wymagałyby jedynie zmian w powiązaniu. Czy coś brakuje?
TallGuy,
11
@gbjbaanb, a następnie uzyskaj dostęp do kolumn według nazwy. Wszystko inne byłoby oczywiście głupie, chyba że określisz kolejność kolumn w zapytaniu.
immibis
179

Zmiany schematu

  • Pobierz według kolejności --- Jeśli kod pobiera kolumnę # jako sposób na uzyskanie danych, zmiana schematu spowoduje ponowne dostosowanie numerów kolumn. Spowoduje to zepsucie aplikacji i zdarzają się złe rzeczy.
  • Pobierz według nazwy --- Jeśli kod pobiera kolumnę według nazwy, na przykład foo, a inna tabela w zapytaniu dodaje kolumnę foo, sposób, w jaki jest ona obsługiwana, może powodować problemy przy próbie uzyskania właściwej foo kolumny.

Tak czy inaczej zmiana schematu może powodować problemy z wyodrębnieniem danych.

Ponadto rozważ, czy używana kolumna została usunięta z tabeli. select * from ...Nadal działa, ale błędy się, kiedy próbuje wyciągnąć dane z tabeli wynikowej. Jeśli kolumna jest podana w zapytaniu, zapytanie spowoduje błąd, dając wyraźne wskazanie, co i gdzie jest problem.

Obciążenie danych

Niektóre kolumny mogą być powiązane z dużą ilością danych. Wybranie z powrotem *spowoduje pobranie wszystkich danych. Tak, oto varchar(4096)to na 1000 wierszy, które wybrałeś z powrotem, dając ci dodatkowe 4 megabajty danych, których nie potrzebujesz, ale i tak są przesyłane przez sieć.

W związku ze zmianą schematu, ten varchar może nie istnieć tam, kiedy tworzyłeś tabelę po raz pierwszy, ale teraz ona tam jest.

Brak przekazania zamiaru

Gdy wybierzesz z powrotem *i otrzymasz 20 kolumn, ale potrzebujesz tylko 2 z nich, nie przekazujesz zamiaru kodu. Patrząc na zapytanie, które select *je wykonuje, nie wiadomo, jakie są jego ważne części. Czy mogę zmienić zapytanie, aby użyć tego innego planu, aby przyspieszyć, nie uwzględniając tych kolumn? Nie wiem, ponieważ cel tego, co zwraca zapytanie, nie jest jasny.


Przyjrzyjmy się niektórym skrzypkom SQL, które eksplorują nieco zmiany schematu .

Po pierwsze, początkowa baza danych: http://sqlfiddle.com/#!2/a67dd/1

DDL:

create table one (oneid int, data int, twoid int);
create table two (twoid int, other int);

insert into one values (1, 42, 2);
insert into two values (2, 43);

SQL:

select * from one join two on (one.twoid = two.twoid);

A kolumny wrócisz to oneid=1, data=42, twoid=2, i other=43.

Co się stanie, jeśli dodam kolumnę do tabeli pierwszej? http://sqlfiddle.com/#!2/cd0b0/1

alter table one add column other text;

update one set other = 'foo';

I moje wyniki z tego samego zapytania, jak wcześniej to oneid=1, data=42, twoid=2, i other=foo.

Zmiana w jednej z tabel zaburza wartości a select *i nagle twoje powiązanie „innego” z int spowoduje zgłoszenie błędu i nie wiesz dlaczego.

Jeśli zamiast tego twoja instrukcja SQL była

select 
    one.oneid, one.data, two.twoid, two.other
from one join two on (one.twoid = two.twoid);

Zmiana w tabeli pierwszej nie zakłóciłaby danych. To zapytanie działa tak samo przed zmianą i po zmianie.


Indeksowanie

Kiedy robisz a select * from, ciągniesz wszystkie wiersze z wszystkich tabel, które pasują do warunków. Nawet stoły, na których tak naprawdę nie zależy. Chociaż oznacza to, że przesyłanych jest więcej danych, w dalszej części stosu czai się inny problem z wydajnością.

Indeksy (powiązane z SO: Jak używać indeksu w instrukcji select? )

Jeśli wycofujesz wiele kolumn, optymalizator planu bazy danych może zignorować użycie indeksu, ponieważ i tak będziesz musiał pobrać wszystkie te kolumny, a użycie indeksu i pobranie wszystkich kolumn w zapytaniu zajęłoby więcej czasu. niż byłoby po prostu wykonać pełne skanowanie tabeli.

Jeśli po prostu wybierasz, powiedzmy, nazwisko użytkownika (które często robisz, a więc masz na nim indeks), baza danych może wykonać skanowanie tylko indeksu (skanowanie tylko indeksu postgres wiki , pełne skanowanie tabeli mysql vs pełne skanowania indeksu , indeksu Tylko scan: Unikanie tabeli programu Access ).

Jeśli jest to możliwe, istnieje sporo optymalizacji dotyczących odczytu tylko z indeksów. Informacje mogą być pobierane szybciej na każdej stronie indeksu, ponieważ również pobierasz mniej - nie pobierasz wszystkich innych kolumn dla select *. Możliwe jest, że skanowanie tylko indeksu zwraca wyniki 100 razy szybciej (źródło: Wybierz * jest złe ).

Nie oznacza to, że pełne skanowanie indeksu jest świetne, nadal jest to pełne skanowanie - ale jest lepsze niż skanowanie pełnego stołu. Kiedy zaczniesz ścigać wszystkie sposoby, które select *szkodzą wydajności, wciąż znajdujesz nowe.

Powiązane czytanie

Społeczność
źródło
2
@Tonny Zgadzam się - ale kiedy odpowiedziałem (po pierwsze), nigdy nie myślałem, że to pytanie wywołałoby tyle dyskusji i komentarzy! Oczywiste jest, że zapytanie dotyczy tylko nazwanych kolumn, prawda ?!
gbjbaanb
3
Zniszczenie wszystkiego przez dodanie kolumny jest również dobrym powodem, dla którego kod powinien zawsze uzyskiwać dostęp do kolumn w module danych według nazwy, a nie przez porządek porządkowy ...
Julia Hayward
1
@gbjbaanb To jest dla mnie. Ale wiele osób przychodzi do pisania zapytań SQL bez formalnego przygotowania / szkolenia. Dla nich może nie być oczywiste.
Tonny
1
@Aaronaught Zaktualizowałem go o dodatkowy bit dotyczący problemów z indeksowaniem. Czy są jeszcze jakieś kwestie, które powinienem poruszyć za niewłaściwość select *?
3
Wow, przyjęta odpowiedź była tak słaba w wyjaśnianiu czegokolwiek, że głosowałem za nią. Dziwię się, że to nie jest akceptowana odpowiedź. +1.
Ben Lee,
38

Kolejny problem: jeśli jest to JOINzapytanie, a wyniki zapytania są pobierane do tablicy asocjacyjnej (jak w przypadku PHP), jest podatne na błędy.

Chodzi o to, że

  1. jeśli tabela fooma kolumny idiname
  2. jeśli tabela barma kolumny idi address,
  3. i w kodzie, którego używasz SELECT * FROM foo JOIN bar ON foo.id = bar.id

zgadnij, co się stanie, gdy ktoś doda kolumnę namedo bartabeli.

Kod nagle przestanie działać poprawnie, ponieważ teraz namekolumna pojawia się w wynikach dwa razy, a jeśli przechowujesz wyniki w tablicy, dane z second name( bar.name) zastąpią pierwszą name( foo.name)!

To dość paskudny błąd, ponieważ jest bardzo nieoczywisty. To może chwilę potrwać, a osoba dodająca kolejną kolumnę do stołu nie mogła przewidzieć takiego niepożądanego efektu ubocznego.

(Prawdziwa historia).

Więc nie używaj *, kontroluj, które kolumny pobierasz i używaj aliasów tam, gdzie jest to właściwe.

Konrad Morawski
źródło
w tym przypadku (co uważam za rzadkie) może to być poważny problem. Ale nadal możesz tego uniknąć (a większość ludzi prawdopodobnie tego zrobi), wysyłając zapytanie za pomocą symbolu wieloznacznego i po prostu dodając alias dla identycznych nazw kolumn.
boczek
4
Teoretycznie, ale jeśli użyjesz symbolu wieloznacznego dla wygody, polegaj na nim, aby automatycznie dać ci wszystkie istniejące kolumny i nigdy nie zawracaj sobie głowy aktualizowaniem zapytania w miarę powiększania się tabel. Jeśli określasz każdą kolumnę, musisz przejść do zapytania, aby dodać kolejną do swojej SELECTklauzuli, i wtedy, gdy masz nadzieję, że zauważysz, że nazwa nie jest unikalna. BTW Nie sądzę, że jest to tak rzadkie w systemach z dużymi bazami danych. Jak powiedziałem, kiedyś spędziłem kilka godzin na polowaniu na tego błędu w wielkim błocie kodu PHP. I właśnie znalazłem inny przypadek: stackoverflow.com/q/17715049/168719
Konrad Morawski
3
W zeszłym tygodniu spędziłem godzinę, starając się to uzyskać od szefa konsultantów. Ma być guru SQL ... Westchnienie ...
Tonny
22

W wielu przypadkach zapytanie każdej kolumny może być całkowicie uzasadnione.

Zawsze zapytanie o każdą kolumnę nie jest.

Jest to więcej pracy dla silnika bazy danych, który musi się uruchomić i przeszukiwać wewnętrzne metadane, aby dowiedzieć się, z którymi kolumnami musi się uporać, zanim będzie mógł zająć się prawdziwym biznesem polegającym na otrzymywaniu danych i wysyłaniu ich z powrotem do ciebie. OK, nie jest to największy narzut na świecie, ale katalogi systemowe mogą być znaczącym wąskim gardłem.

To więcej pracy dla Twojej sieci, ponieważ wycofujesz dowolną liczbę pól, gdy możesz chcieć tylko jednego lub dwóch z nich. Jeśli ktoś [inny] pójdzie i doda kilka tuzinów dodatkowych pól, z których wszystkie zawierają duże fragmenty tekstu, twoja przepustowość nagle przejdzie przez podłogę - bez wyraźnego powodu. Sytuacja staje się jeszcze gorsza, jeśli twoja klauzula „where” nie jest szczególnie dobra, a także wycofujesz wiele wierszy - to potencjalnie dużo danych wędruje przez sieć do ciebie (tj. Będzie wolno).

To więcej pracy dla Twojej aplikacji, konieczność wycofania i zapisania wszystkich tych dodatkowych danych, które prawdopodobnie nie obchodzą.

Ryzykujesz, że kolumny zmienią ich kolejność. OK, nie powinieneś się tym martwić (i nie zrobisz tego, jeśli wybierzesz tylko kolumny, których potrzebujesz), ale jeśli przejdziesz do nich wszystkie naraz, a ktoś [inny] zdecyduje się zmienić kolejność kolumn w tabeli , ten starannie spreparowany eksport CSV, który przekazujesz kontom w korytarzu, nagle przechodzi do puli - znowu, bez wyraźnego powodu.

BTW, kilka razy mówiłem „ktoś [jeszcze]”. Pamiętaj, że bazy danych są z natury wieloużytkownikowe; możesz nie mieć nad nimi kontroli, tak jak myślisz.

Phill W.
źródło
3
Pomyślałbym, że zawsze sprawdzanie każdej kolumny może być uzasadnione dla takich rzeczy, jak narzędzia do przeglądania tabel niezależne od schematu. Niezbyt powszechna sytuacja, ale w kontekście narzędzi przeznaczonych wyłącznie do użytku wewnętrznego takie rzeczy mogą się przydać.
supercat
1
@ superupat To tylko JEDYNY prawidłowy przypadek użycia dla „WYBIERZ *”, o którym mogę myśleć. I nawet wtedy wolę ograniczyć zapytanie do „SELECT TOP 10 *” (w MS SQL) lub dodać „LIMIT 10” (mySQL) lub dodać „WHERE ROWNUM <= 10” (Oracle). Zwykle w takim przypadku chodzi bardziej o „jakie kolumny są i niektóre przykładowe dane” niż o pełną treść.
Tonny
@ Tonny: SQL Server zmienił domyślne skrypty, aby dodać TOPograniczenie; Nie jestem pewien, jak ważne jest to, że kod odczytuje tyle, ile chce wyświetlić, a następnie usuwa zapytanie. Myślę, że odpowiedzi na zapytania są przetwarzane nieco leniwie, chociaż nie znam szczegółów. W każdym razie uważam, że zamiast mówić, że „nie jest uzasadniony”, lepiej byłoby powiedzieć „… jest uzasadniony w znacznie mniejszej liczbie”; w zasadzie podsumowałbym uzasadnione przypadki jako te, w których użytkownik miałby lepszy pomysł, co jest znaczący niż programista.
supercat
@ superupat Mogę się na to zgodzić. I bardzo podoba mi się sposób, w jaki umieściłeś to w ostatnim zdaniu. Muszę to pamiętać.
Tonny
11

Krótka odpowiedź brzmi: zależy od tego, jakiej bazy danych używają. Relacyjne bazy danych są zoptymalizowane do wydobywania potrzebnych danych w szybki, niezawodny i atomowy sposób. W przypadku dużych zestawów danych i złożonych zapytań jest to znacznie szybsze i prawdopodobnie bezpieczniejsze niż WYBIERANIE * i wykonuje równoważenie złączeń po stronie „kodu”. Magazyny klucz-wartość mogą nie mieć zaimplementowanych takich funkcji lub mogą nie być wystarczająco dojrzałe, aby można je było wykorzystać w produkcji.

To powiedziawszy, nadal możesz wypełnić dowolną strukturę danych za pomocą SELECT * i wypracować resztę kodu, ale znajdziesz wąskie gardła wydajności, jeśli chcesz skalować.

Najbliższym porównaniem jest sortowanie danych: możesz użyć szybkiego sortowania lub bąbelkowego, a wynik będzie poprawny. Ale nie zostanie zoptymalizowany i na pewno będą mieć problemy, gdy wprowadzisz współbieżność i będziesz musiał sortować atomowo.

Oczywiście taniej jest dodawać pamięć RAM i procesory niż inwestować w programistę, który potrafi wykonywać zapytania SQL, a nawet ma niejasne zrozumienie, czym jest JOIN.

lorenzog
źródło
Naucz się SQL! To nie jest takie trudne. Jest to „natywny” język baz danych daleko i szeroko. Jest potężny. Jest elegancki. To przetrwało próbę czasu. I nie ma mowy, żebyś napisał złączenie po stronie „kodu”, które jest bardziej wydajne niż złączenie w bazie danych, chyba że naprawdę nie jesteś w stanie wykonać złączeń SQL. Weź pod uwagę, że aby wykonać „łączenie kodu”, musisz pobrać wszystkie dane z obu tabel w nawet prostym złączeniu 2 tabel. A może pobierasz statystyki indeksu i używasz tych, aby zdecydować, które dane tabeli pobrać przed dołączeniem? Nie sądziłem ... Naucz się poprawnie korzystać z bazy danych, ludzie.
Craig,
@Craig: SQL jest powszechny w relacyjnych bazach danych daleko i szeroko. Nie jest to jednak jedyny typ DB ... i istnieje powód, dla którego bardziej nowoczesne metody baz danych są często nazywane NoSQL. : P Nikt, kogo znam, nie nazwałby SQL „eleganckim” bez dużej dawki ironii. Jeśli chodzi o relacyjne bazy danych, to po prostu wysysa mniej niż wiele alternatyw.
cHao
@cHao Byłem bardzo świadomy różnych innych typów baz danych tam przez dziesięciolecia . Baza danych Pick „nosql” istnieje już od zawsze. „NoSQL” nie jest nawet nową koncepcją. ORM również istnieją od zawsze i zawsze były powolne. Wolno! = Dobrze. Jeśli chodzi o elegancję (LINQ?), Nie możesz mnie przekonać, że jest to rozsądne lub eleganckie, jeśli chodzi o klauzulę „gdzie”: Customer customer = this._db.Customers.Where( “it.ID = @ID”, new ObjectParameter( “ID”, id ) ).First();Zobacz czas na obrazę na stronie 2.
Craig
@Craig: Nawet nie zaczynaj mnie od ORM. Prawie każdy system robi to okropnie, a abstrakcja przecieka wszędzie. Wynika to z faktu, że relacyjne rekordy DB nie są obiektami - w najlepszym wypadku są serialnymi częściami obiektu. Ale jeśli chodzi o LINQ, naprawdę chcesz tam pójść? Odpowiednik SQLish jest podobny do var cmd = db.CreateCommand(); cmd.CommandText = "SELECT TOP 1 * FROM Customers WHERE ID = @ID"; cmd.Parameters.AddWithValue("@ID", id); var result = cmd.ExecuteReader();.... a następnie przejdź do tworzenia klienta z każdego wiersza. LINQ pokonuje spodnie.
cHao
@Craig: To prawda, że ​​nie jest tak elegancki, jak mógłby być. Ale nigdy nie będzie tak elegancki, jak bym chciał, dopóki nie może przekonwertować kodu .net na SQL. :) W którym momencie można powiedzieć var customer = _db.Customers.Where(it => it.id == id).First();.
cHao
8

IMO polega na byciu jawnym a niejawnym. Kiedy piszę kod, chcę, żeby działał, ponieważ sprawiłem, że działał, a nie tylko dlatego, że wszystkie części po prostu tam były. Jeśli przeszukujesz wszystkie rekordy, a Twój kod działa, będziesz miał tendencję do przechodzenia dalej. Później, jeśli coś się zmieni, a teraz twój kod nie działa, królewskim problemem jest debugowanie wielu zapytań i funkcji szukających wartości, która powinna tam być, a jedynymi wartościami odniesienia są *.

Również w podejściu wielopoziomowym nadal najlepiej jest izolować zakłócenia schematu bazy danych w warstwie danych. Jeśli warstwa danych przechodzi * do logiki biznesowej i najprawdopodobniej na warstwę prezentacji, rozszerzasz zakres debugowania wykładniczo.

zkent
źródło
3
Jest to prawdopodobnie jeden z najważniejszych powodów tutaj i ma tylko niewielką część głosów. Utrzymanie zaśmieconej bazy kodu select *jest znacznie gorsze!
Eamon Nerbonne,
6

ponieważ jeśli tabela otrzyma nowe kolumny, otrzymasz je wszystkie, nawet jeśli ich nie potrzebujesz. dzięki varcharstemu może stać się wiele dodatkowych danych, które muszą być przesyłane z bazy danych

niektóre optymalizacje DB mogą również wyodrębnić rekordy o nieokreślonej długości do osobnego pliku, aby przyspieszyć dostęp do części o stałej długości, używając select * pokonuje cel tego

maniak zapadkowy
źródło
1

Oprócz narzutu, czegoś, czego przede wszystkim chcesz uniknąć, powiedziałbym, że jako programista nie polegasz na kolejności kolumn zdefiniowanej przez administratora bazy danych. Wybierz każdą kolumnę, nawet jeśli potrzebujesz ich wszystkich.

dj bazzie wazzie
źródło
3
Zgadzam się, ale w każdym razie zaleciłbym również wyciągnięcie wartości z zestawu wyników według nazwy kolumny.
Rory Hunter
Oddelegowany, niesiony. Użyj nazw kolumn, nie zależą od kolejności kolumn. Kolejność kolumn jest kruchą zależnością. Nazwy powinny być (masz nadzieję) wyprowadzone z rzeczywistego wysiłku projektowego, albo jawnie aliasujesz kolumny kompozytowe lub obliczenia albo nazwy sprzecznych kolumn w swoim zapytaniu i odwołujesz się do jawnego aliasu, który podałeś. Ale poleganie na zamówieniu to po prostu taśma klejąca i modlitwa ...
Craig,
1

Nie widzę żadnego powodu, dla którego nie powinieneś używać go do celu, w którym jest budowany - pobierz wszystkie kolumny z bazy danych. Widzę trzy przypadki:

  1. Kolumna jest dodawana do bazy danych i chcesz ją również w kodzie. a) Z * zakończy się niepowodzeniem z prawidłowym komunikatem. b) Bez * będzie działać, ale nie zrobi tego, czego oczekujesz, co jest dość złe.

  2. Kolumna jest dodawana do bazy danych i nie jest wymagana w kodzie. a) Z * zawiedzie; oznacza to, że * nie ma już zastosowania, ponieważ jego semantyka oznacza „pobierz wszystko”. b) Bez * będzie działać.

  3. Usunięto kolumnę Kod nie powiedzie się w żaden sposób.

Teraz najczęstszym przypadkiem jest przypadek 1 (ponieważ użyłeś *, co oznacza, że ​​najprawdopodobniej chcesz wszystkiego); bez * możesz mieć kod, który działa dobrze, ale nie działa zgodnie z oczekiwaniami, co jest znacznie, a najgorsze, kod, który nie działa z odpowiednim komunikatem błędu .

Nie biorę pod uwagę kodu, który pobiera dane kolumny na podstawie indeksu kolumny, który moim zdaniem jest podatny na błędy. Odzyskiwanie go na podstawie nazwy kolumny jest znacznie bardziej logiczne.

m3th0dman
źródło
Twoje założenie jest nieprawidłowe. Select *był przeznaczony raczej jako wygoda do tworzenia zapytań ad hoc, a nie do celów tworzenia aplikacji. Lub do użycia w konstrukcjach statystycznych, takich jak select count(*)który pozwala silnikowi zapytań zdecydować, czy użyć indeksu, którego indeksu użyć itd. I nie zwracasz żadnych rzeczywistych danych kolumny. Lub do użycia w klauzulach takich jak where exists( select * from other_table where ... ), które ponownie są zaproszeniem do silnika zapytań, aby sam wybrał najbardziej wydajną ścieżkę, a podzapytanie służy tylko do ograniczenia wyników z głównego zapytania. Itd.
Craig,
@Craig Wierzę, że każda książka / samouczek SQL select *zawiera semantykę pobierania wszystkich kolumn; jeśli twoja aplikacja naprawdę tego potrzebuje, nie widzę powodów, dla których miałbyś z niej korzystać. Czy możesz wskazać jakieś odniesienie (Oracle, IBM, Microsoft itp.), Które wspomina, że ​​celem select *kompilacji nie było pobranie wszystkich kolumn?
m3th0dman
Cóż, oczywiście select *istnieje możliwość pobierania wszystkich kolumn ... jako wygodnej funkcji, do zapytań ad hoc, nie dlatego, że jest to świetny pomysł w oprogramowaniu produkcyjnym. Przyczyny są już dość dobrze omówione w odpowiedziach na tej stronie, dlatego nie stworzyłem własnej szczegółowej odpowiedzi: •) Problemy z wydajnością, wielokrotne zestawianie danych w sieci, których nigdy nie używasz, •) problemy z aliasingiem kolumn, •) awarie optymalizacji planu zapytań (w niektórych przypadkach nieużywanie indeksów), •) nieefektywne operacje we / wy serwera w przypadkach, w których ograniczony wybór mógł wykorzystywać wyłącznie indeksy itp.
Craig
Być może istnieje tu lub tam przypadek krawędzi, który uzasadnia użycie select *w rzeczywistej aplikacji produkcyjnej, ale natura przypadku krawędzi jest taka, że ​​nie jest to powszechny przypadek. :-)
Craig
@Craig Powody są przeciwko pobieraniu wszystkich kolumn z bazy danych, a nie przeciwko select *; co mówiłem, jeśli naprawdę potrzebujesz wszystkich kolumn, nie widzę powodu, dla którego nie powinieneś tego używać select *; choć niewiele musi istnieć scenariuszy, w których potrzebne są wszystkie kolumny.
m3th0dman
1

Pomyśl o tym w ten sposób ... jeśli przeszukujesz wszystkie kolumny z tabeli zawierającej tylko kilka małych ciągów lub pól numerycznych, to łącznie 100 000 danych. Zła praktyka, ale się spełni. Teraz dodaj jedno pole, które zawiera, powiedzmy, obraz lub dokument tekstowy o wielkości 10 MB. teraz twoje szybko wykonujące zapytanie natychmiast i w tajemniczy sposób zaczynają słabo działać, tylko dlatego, że pole zostało dodane do tabeli ... możesz nie potrzebować tego ogromnego elementu danych, ale ponieważ już to Select * from Tablezrobiłeś.

Kevin Mitchell
źródło
6
wydaje się to tylko powtórzyć punkt, który został już kilka godzin temu postawiony w pierwszej odpowiedzi i kilku innych odpowiedziach
komara