Jeśli potrzebuję tylko 2/3 kolumn i wykonuję zapytanie SELECT *
zamiast dostarczania tych kolumn w zapytaniu wybierającym, czy występuje spadek wydajności dotyczący większej / mniejszej liczby operacji we / wy lub pamięci?
Narzut sieci może występować, jeśli wybiorę * bez potrzeby.
Ale czy w operacji wybierania silnik bazy danych zawsze pobiera atomową krotkę z dysku, czy też pobiera tylko te kolumny, których zażądano w operacji wybierania?
Jeśli zawsze pobiera krotkę, narzut we / wy jest taki sam.
W tym samym czasie może wystąpić zużycie pamięci na usunięcie żądanych kolumn z krotki, jeśli pobierze krotkę.
Więc jeśli tak jest, wybierz jakąś kolumnę będzie miała więcej narzutu pamięci niż ta z select *
sql
performance
Neel Basu
źródło
źródło
SELECT
wykonywania / przetwarzania zapytań różni się w zależności od bazy danych.CREATE VIEW foo_view AS SELECT * FROM foo;
Nawiasem mówiąc , w PostgreSQL, jeśli powiesz , a następnie dodasz kolumny do tabeli foo później, te kolumny nie pojawią się automatycznie w foo_view zgodnie z oczekiwaniami. Innymi słowy,*
w tym kontekście rozwija się tylko raz (w czasie tworzenia widoku), a nie na SELECT. Z powodu komplikacji wynikających z ALTER TABLE, powiedziałbym, że (w praktyce)*
jest uważane za szkodliwe.Odpowiedzi:
Zawsze pobiera krotkę (z wyjątkiem przypadków, gdy tabela została podzielona w pionie - podzielona na kolumny), więc odpowiadając na zadane pytanie, nie ma to znaczenia z punktu widzenia wydajności. Jednak z wielu innych powodów (poniżej) należy zawsze wybierać dokładnie te kolumny, które chcesz, według nazwy.
Zawsze pobiera krotkę, ponieważ (w każdym znanym mi systemie RDBMS sprzedawców) podstawowa struktura pamięci dyskowej dla wszystkiego (w tym danych tabeli) jest oparta na zdefiniowanych stronach we / wy (np. W SQL Server każda strona jest 8 kilobajtów). I każdy odczyt lub zapis we / wy odbywa się według strony. To znaczy, każdy zapis lub odczyt jest pełną stroną danych.
Z powodu tego podstawowego ograniczenia strukturalnego konsekwencją jest to, że każdy wiersz danych w bazie danych musi zawsze znajdować się na jednej i tylko jednej stronie. Nie może obejmować wielu stron danych (z wyjątkiem specjalnych rzeczy, takich jak obiekty blob, w których rzeczywiste dane obiektu blob są przechowywane w oddzielnych fragmentach strony, a rzeczywista kolumna wiersza tabeli otrzymuje tylko wskaźnik ...). Ale te wyjątki to tylko wyjątki i generalnie nie mają zastosowania, z wyjątkiem szczególnych przypadków (dla specjalnych typów danych lub pewnych optymalizacji dla specjalnych okoliczności).
Nawet w tych specjalnych przypadkach, ogólnie rzecz biorąc, sam wiersz tabeli danych (który zawiera wskaźnik do rzeczywistych danych dla obiektu Blob lub cokolwiek innego), musi być przechowywany na jednej stronie IO ...
WYJĄTEK. Jedyne miejsce, w którym
Select *
jest OK, znajduje się w zapytaniu podrzędnym po klauzuliExists
lubNot Exists
predykatu, na przykład:EDYCJA: Aby odnieść się do komentarza @Mike Sherer, tak, to prawda, zarówno pod względem technicznym, z odrobiną definicji dla twojego specjalnego przypadku, jak i estetycznie. Po pierwsze, nawet jeśli zestaw żądanych kolumn jest podzbiorem kolumn przechowywanych w jakimś indeksie, procesor zapytań musi pobrać każdą kolumnę przechowywaną w tym indeksie, a nie tylko żądane, z tych samych powodów - WSZYSTKIE I / O muszą być wykonane w stron, a dane indeksu są przechowywane na stronach we / wy, podobnie jak dane tabeli. Jeśli więc zdefiniujesz „krotkę” dla strony indeksu jako zestaw kolumn przechowywanych w indeksie, instrukcja nadal będzie prawdziwa.
a stwierdzenie jest prawdziwe estetycznie, ponieważ chodzi o to, że pobiera dane na podstawie tego, co jest przechowywane na stronie I / O, a nie na podstawie tego, o co prosisz, i to prawda, niezależnie od tego, czy uzyskujesz dostęp do strony I / O tabeli bazowej, czy indeksu Strona I / O.
Z innych powodów, których nie należy używać
Select *
, zobacz Dlaczego jestSELECT *
uważany za szkodliwy? :źródło
select *
będzie miał mniejszy narzut pamięci niż tenselect column
sam narzut we / wy. więc jeśli zostawimy narzut sieci.select *
jeśli jest mniejszy niż ten zselect column
Jest kilka powodów, dla których nigdy (przenigdy) nie powinieneś używać
SELECT *
w kodzie produkcyjnym:ponieważ nie dajesz swojej bazie danych żadnych wskazówek, co chcesz, najpierw będzie musiała sprawdzić definicję tabeli, aby określić kolumny w tej tabeli. To wyszukiwanie będzie kosztować trochę czasu - niewiele w przypadku pojedynczego zapytania - ale sumuje się z czasem
jeśli potrzebujesz tylko 2/3 kolumn, wybierasz 1/3 za dużo danych, które muszą być pobierane z dysku i wysyłane przez sieć
jeśli zaczniesz polegać na pewnych aspektach danych, np. kolejności zwracanych kolumn, możesz spotkać się z przykrą niespodzianką po reorganizacji tabeli i dodaniu nowych kolumn (lub usunięciu istniejących)
w SQL Server (brak pewności co do innych baz danych), jeśli potrzebujesz podzbioru kolumn, zawsze istnieje szansa, że indeks nieklastrowy może pokryć to żądanie (zawiera wszystkie potrzebne kolumny). Z a
SELECT *
, od samego początku rezygnujesz z tej możliwości. W tym konkretnym przypadku dane byłyby pobierane ze stron indeksowych (jeśli zawierają one wszystkie niezbędne kolumny), a zatem obciążenie we / wy dysku i pamięć byłyby znacznie mniejsze w porównaniu z wykonywaniemSELECT *....
zapytania.Tak, początkowo wymaga to nieco więcej pisania (narzędzia takie jak SQL Prompt for SQL Server nawet Ci w tym pomogą) - ale tak naprawdę jest to jeden przypadek, w którym istnieje zasada bez wyjątku: nigdy nie używaj SELECT * w kodzie produkcyjnym. ZAWSZE.
źródło
Where Exists (Select * From ...
) użycie zSelect *
pewnością nie stanowi problemu, aw niektórych kręgach jest uważane za najlepszą praktykę.IF EXISTS(SELECT *...
jest szczególny przypadek - ponieważ nie ma danych, które są naprawdę pobierane, ale to tylko sprawdzenie istnienia, SELECT * nie jest problemem ...Powinieneś zawsze używać tylko
select
tych kolumn, których naprawdę potrzebujesz. Nigdy nie jest mniej wydajne wybieranie mniej, a nie więcej, a ponadto napotkasz mniej nieoczekiwanych efektów ubocznych - takich jak dostęp do kolumn wyników po stronie klienta po indeksie, a następnie ich niepoprawne indeksy przez dodanie nowej kolumny do tabeli.[edytuj]: Oznaczało dostęp. Głupi mózg wciąż się budzi.
źródło
SELECT *
z tym.O ile nie przechowujesz dużych obiektów blob, wydajność nie jest problemem. Głównym powodem, dla którego nie należy używać funkcji SELECT *, jest to, że jeśli używasz zwracanych wierszy jako krotek, kolumny wracają w dowolnej kolejności, którą określa schemat, a jeśli to się zmieni, będziesz musiał naprawić cały kod.
Z drugiej strony, jeśli używasz dostępu w stylu słownikowym, nie ma znaczenia, w jakiej kolejności wracają kolumny, ponieważ zawsze uzyskujesz do nich dostęp po nazwie.
źródło
To natychmiast przywodzi mi na myśl tabelę, której używałem, która zawierała kolumnę typu
blob
; zwykle zawierał obraz JPEG oMb
rozmiarze kilku sekund.Nie trzeba dodawać, że nie zrobiłem
SELECT
tego artykułu, chyba że naprawdę tego potrzebowałem. Posiadanie tych danych unoszących się dookoła - zwłaszcza gdy wybrałem wiele wierszy - było po prostu kłopotliwe.Jednak przyznam, że w przeciwnym razie zwykle odpytuję o wszystkie kolumny w tabeli.
źródło
Podczas wyboru SQL baza danych zawsze będzie odwoływać się do metadanych tabeli, niezależnie od tego, czy jest to SELECT * dla SELECT a, b, c ... Dlaczego? Bo tam znajdują się informacje o strukturze i układzie tabeli w systemie.
Musi przeczytać te informacje z dwóch powodów. Po pierwsze, aby po prostu skompilować oświadczenie. Musi upewnić się, że określisz co najmniej istniejącą tabelę. Ponadto struktura bazy danych mogła ulec zmianie od czasu ostatniego wykonania instrukcji.
Oczywiście metadane bazy danych są buforowane w systemie, ale nadal trzeba je przetwarzać.
Następnie metadane są używane do generowania planu zapytania. Dzieje się tak za każdym razem, gdy kompilowana jest instrukcja. Ponownie, działa to w przypadku metadanych zapisanych w pamięci podręcznej, ale zawsze jest to robione.
Jedynym przypadkiem, w którym to przetwarzanie nie jest wykonywane, jest sytuacja, gdy baza danych używa wstępnie skompilowanego zapytania lub buforuje poprzednie zapytanie. To jest argument przemawiający za używaniem parametrów wiązania zamiast dosłownego SQL. „SELECT * FROM TABLE WHERE key = 1” to inne zapytanie niż „SELECT * FROM TABLE WHERE key =?” a „1” jest związane z wezwaniem.
Bazy danych w dużym stopniu polegają na buforowaniu stron, aby działać. Wiele nowoczesnych baz danych jest wystarczająco małych, aby całkowicie zmieścić się w pamięci (lub, być może powinienem powiedzieć, nowoczesna pamięć jest wystarczająco duża, aby pomieścić wiele DB). Następnie głównym kosztem we / wy na zapleczu jest rejestrowanie i opróżnianie stron.
Jeśli jednak nadal trafiasz na dysk dla swojej bazy danych, podstawową optymalizacją wykonywaną przez wiele systemów jest poleganie na danych w indeksach, a nie na samych tabelach.
Jeśli masz:
Następnie, jeśli wykonasz „SELECT id, name FROM customer WHERE id = 1”, jest bardzo prawdopodobne, że baza danych pobierze te dane z indeksu, a nie z tabel.
Czemu? Prawdopodobnie i tak użyje indeksu, aby spełnić zapytanie (w porównaniu ze skanowaniem tabeli), i chociaż „nazwa” nie jest używana w klauzuli where, indeks ten nadal będzie najlepszą opcją dla zapytania.
Teraz baza danych zawiera wszystkie dane potrzebne do spełnienia zapytania, więc nie ma powodu, aby same trafiać na strony tabeli. Korzystanie z indeksu skutkuje mniejszym ruchem na dysku, ponieważ masz większą gęstość wierszy w indeksie niż ogólnie w tabeli.
Jest to faliste wyjaśnienie konkretnej techniki optymalizacji używanej w niektórych bazach danych. Wiele z nich ma kilka technik optymalizacji i strojenia.
Ostatecznie SELECT * jest przydatne w przypadku dynamicznych zapytań, które trzeba wpisywać ręcznie, nigdy bym go nie używał do „prawdziwego kodu”. Identyfikacja poszczególnych kolumn daje DB więcej informacji, których może użyć do optymalizacji zapytania i daje lepszą kontrolę nad kodem przed zmianami schematu itp.
źródło
Myślę, że nie ma dokładnej odpowiedzi na Twoje pytanie, ponieważ zastanawiasz się nad wydajnością i łatwością obsługi swoich aplikacji.
Select column
jest bardziej wydajneselect *
, ale jeśli tworzysz zorientowany system obiektowy, spodoba ci się używanieobject.properties
i możesz potrzebować właściwości w dowolnej części aplikacji, wtedy będziesz potrzebować napisać więcej metod, aby uzyskać właściwości w specjalnych sytuacjach, jeśli nie użyjselect *
i wypełnij wszystkie właściwości. Twoje aplikacje muszą mieć dobrą wydajność,select *
aw niektórych przypadkach będziesz musiał użyć kolumny wyboru, aby poprawić wydajność. Wtedy będziesz mieć lepszy z dwóch światów, łatwość pisania i utrzymywania aplikacji oraz wydajność, gdy potrzebujesz wydajności.źródło
Przyjęta tutaj odpowiedź jest błędna. Natknąłem się na to, gdy inne pytanie zostało zamknięte jako duplikat tego (gdy nadal pisałem swoją odpowiedź - grr - stąd poniższy SQL odwołuje się do drugiego pytania).
Należy zawsze używać atrybutu SELECT, atrybutu .... NOT SELECT *
Dotyczy to głównie problemów z wydajnością.
Nie jest to zbyt przydatny przykład. Zamiast tego rozważ:
Jeśli istnieje indeks (nazwisko, telefon), wówczas zapytanie można rozwiązać bez konieczności wyszukiwania odpowiednich wartości w tabeli - istnieje indeks obejmujący .
Co więcej, załóżmy, że w tabeli znajduje się BLOB zawierający zdjęcie użytkownika i przesłane CV oraz arkusz kalkulacyjny… używając SELECT * ściągnie wszystkie te informacje z powrotem do buforów DBMS (wymuszając inne przydatne informacje z pamięci podręcznej). Następnie wszystko zostanie wysłane do klienta, wykorzystując czas w sieci i pamięć klienta na dane, które są nadmiarowe.
Może również powodować problemy funkcjonalne, jeśli klient pobiera dane jako wyliczoną tablicę (np. Mysql_fetch_array ($ x, MYSQL_NUM) PHP). Być może, gdy kod został zapisany, „telefon” była trzecią kolumną zwracaną przez SELECT *, ale potem ktoś podchodzi i decyduje się dodać adres e-mail do tabeli, umieszczony przed „telefon”. Żądane pole jest teraz przesunięte do czwartej kolumny.
źródło
Tak czy inaczej są powody. Często używam SELECT * w PostgreSQL, ponieważ jest wiele rzeczy, które możesz zrobić z SELECT * w PostgreSQL, a których nie możesz zrobić z jawną listą kolumn, szczególnie w procedurach składowanych. Podobnie w Informix, polecenie SELECT * w dziedziczonym drzewie tabeli może dać postrzępione wiersze, podczas gdy jawna lista kolumn nie może, ponieważ zwracane są również dodatkowe kolumny w tabelach podrzędnych.
Głównym powodem, dla którego robię to w PostgreSQL, jest to, że zapewnia to, że otrzymam dobrze sformułowany typ specyficzny dla tabeli. To pozwala mi wziąć wyniki i użyć ich jako typu tabeli w PostgreSQL. Pozwala to również na znacznie więcej opcji w zapytaniu niż sztywna lista kolumn.
Z drugiej strony sztywna lista kolumn umożliwia sprawdzenie na poziomie aplikacji, czy schematy bazy danych nie uległy zmianie w określony sposób, co może być pomocne. (Robię takie kontrole na innym poziomie.)
Jeśli chodzi o wydajność, zwykle używam WIDOKÓW i procedur składowanych zwracających typy (a następnie listy kolumn wewnątrz procedury składowanej). To daje mi kontrolę nad tym, jakie typy są zwracane.
Ale pamiętaj, że używam SELECT * zwykle przeciwko warstwie abstrakcji, a nie tabelom bazowym.
źródło
Odniesienie zaczerpnięte z tego artykułu:
Bez funkcji SELECT *: Jeśli używasz „SELECT *” w tym momencie, wybierasz więcej kolumn z bazy danych, a niektóre z tych kolumn mogą nie być używane przez aplikację. Spowoduje to dodatkowe koszty i obciążenie systemu bazy danych oraz większą ilość danych przesyłanych przez sieć.
Z SELECT *: Jeśli masz specjalne wymagania i stworzyłeś dynamiczne środowisko, po dodaniu lub usunięciu kolumny automatycznie obsługiwane przez kod aplikacji. W tym szczególnym przypadku nie musisz zmieniać kodu aplikacji i bazy danych, co automatycznie wpłynie na środowisko produkcyjne. W takim przypadku możesz użyć „SELECT *”.
źródło
Aby dodać niuans do dyskusji, którego tutaj nie widzę: Jeśli chodzi o I / O, jeśli używasz bazy danych z pamięcią kolumnową , możesz zrobić DUŻO mniej I / O, jeśli zapytasz tylko o pewne kolumny. Gdy przechodzimy na dyski SSD, korzyści mogą być nieco mniejsze w porównaniu z pamięcią opartą na wierszach, ale istnieje a) odczytywanie tylko bloków zawierających kolumny, na których Ci zależy b) kompresja, która ogólnie znacznie zmniejsza rozmiar danych na dysku, a tym samym ilość danych odczytanych z dysku.
Jeśli nie jesteś zaznajomiony z magazynowaniem kolumnowym, jedna implementacja Postgres pochodzi z Citus Data, inna to Greenplum, inna Paraccel, a inna (luźno mówiąc) to Amazon Redshift. Dla MySQL istnieje Infobright, prawie nieistniejąca już InfiniDB. Inne oferty handlowe obejmują Vertica firmy HP, Sybase IQ, Teradata ...
źródło
równy
źródło