Dlaczego SELECT * byłby o magnitudo szybszy niż SELECT foo?

28

Rozważ tabelę wartości i skrótów, takie jak:

+------------+----------+------+-----+---------+----------------+
| Field      | Type     | Null | Key | Default | Extra          |
+------------+----------+------+-----+---------+----------------+
| id         | int(11)  | NO   | PRI | NULL    | auto_increment |
| val        | char(9)  | NO   |     | NULL    |                |
| val_hashed | char(50) | YES  |     | NULL    |                |
+------------+----------+------+-----+---------+----------------+

Następujące zapytanie kończy się za 0,00 sekundy:

SELECT * FROM hashes ORDER BY 1 DESC LIMIT 1;

Jednak to zapytanie zajmuje 3 min 17 sekund:

SELECT val FROM hashes ORDER BY 1 DESC LIMIT 1;

Widzę, że podczas działania zapytania lista procesów pokazuje go jako status Sorting result. Sytuacja jest całkowicie powtarzalna. Zauważ, że istnieje inny proces wykonujący INSERToperacje na stole w sposób ciągły.

Dlaczego uruchomienie bardziej szczegółowego zapytania trwa dłużej niż *zapytanie? Zawsze uważałem, że *należy unikać zapytań specjalnie ze względu na wydajność.

dotancohen
źródło
7
Pierwsze instrukcje najprawdopodobniej wykorzystują indeks klucza podstawowego iddo znalezienia pierwszego wiersza. Drugi musi posortować pełny wynik w valkolumnie (nieindeksowanej) .
a_horse_w_no_name
8
ORDER BY NUMBERSkładnia jest dość podatny na błędy.
usr
2
Dodanie do ostatniego komentarza w SELECT *połączeniu z indeksem kolumny w ORDER BYpowoduje zaciemnienie sortowanej kolumny - kolejny powód, dla którego należy unikać *...
lc.
@ lc., Co masz na myśli?
Pacerier
@Pacerier Mam na myśli, że *nie jest jednoznaczne. Zatem powiedzenie „daj mi wszystkie kolumny i posortuj według trzeciego” jest tak samo deterministyczne jak powiedzenie „idź do supermarketu i powiedz, ile świateł minąłeś”
lc.

Odpowiedzi:

33

Wyrażenie ORDER BY 1odnosi się do różnych kolumn; w pierwszym będzie id, w drugim val. Odid jest to klucz, zostanie zindeksowany i order bybędzie to trywialna ilość pracy. Aby order by valjednak system musiał pobrać każdy wiersz, posortuj całą tabelę według val, a następnie wybierz tylko jeden z tych wierszy.

Zmień oba zapytania na order by idi myślę, że czasy wykonania będą prawie identyczne.

Michael Green
źródło
3
Czasami najtrudniejsze pytania to te, które patrzą nam prosto w twarz. Dzięki, Michael!
dotancohen
7

Różnica wydajności w zapytaniu jest dobrze wyjaśniona przez MG. Zajmę się tym:

Zawsze uważałem, że * należy unikać zapytań specjalnie ze względu na wydajność.

select *nie wiąże się z żadnymi konkretnymi karami, jest problematyczne w przypadku niewłaściwego użycia. W zapytaniu z jedną tabelą działa dobrze. teraz połącz tę tabelę z inną z 20 kolumnami, a następnie dodaj połączenia do 5 innych tabel z wieloma kolumnami każda. TERAZ to problem. Podobnie są ludzie, którzy uczą szerokiej pomocy zespołu „nigdy nie rób X” bez wyjaśnienia dlaczego.

Paweł
źródło
3
SELECT *może być problemem nawet dla zapytania z jedną tabelą. Na przykład, SELECT * FROM hashes ORDER BY val;prawdopodobnie wykona pełne skanowanie tabeli, a następnie sortowanie, podczas gdy SELECT val FROM hashes ORDER BY val;wykona tylko pełne skanowanie indeksu i żadne sortowanie (zakładając, że indeks istnieje dla val). Tak więc nigdy nie boli wybrać tylko te wyniki, których potrzebujemy.
ypercubeᵀᴹ
Zakładam, że to widziałeś? sqlblog.com/blogs/aaron_bertrand/archive/2009/10/10/…
Max Vernon
@ypercube, czy to nastąpić nawet jeśli nasz select(*)służy jedynie jako sub -Wybierz? Ponieważ jest to osadzony wybór, czy MySQL nie byłby wystarczająco inteligentny, aby dowiedzieć się, które kolumny należy wybrać?
Pacerier
Optymalizator mysql @Pacerier ma różne poziomy „inteligencji”, w zależności od używanej wersji. W gerneal było dość głupio, jeśli chodzi o zagnieżdżanie podkwerend, więc cokolwiek można było mu pomóc, było dobrze.
ypercubeᵀᴹ
@ypercube, Ah, jeśli tylko jest tak mądry jak pgsql.
Pacerier