Чому SELECT * буде з величиною швидкішою, ніж SELECT foo?


28

Розглянемо таблицю значень та хешів, наприклад:

+------------+----------+------+-----+---------+----------------+
| 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    |                |
+------------+----------+------+-----+---------+----------------+

Наступний запит закінчується за 0,00 секунд:

SELECT * FROM hashes ORDER BY 1 DESC LIMIT 1;

Однак цей запит займає 3 хв 17 секунд:

SELECT val FROM hashes ORDER BY 1 DESC LIMIT 1;

Я бачу, що під час запуску запиту список процесів показує його як статус Sorting result. Ситуація повністю відтворювана. Зауважте, що існує інший процес, який постійно виконує INSERTоперації на столі.

Чому для запуску більш конкретного запиту потрібно більше часу, ніж *запит? Я завжди вважав, що *запитів слід уникати спеціально з міркувань продуктивності.


7
Перші вислови, ймовірно, використовують індекс первинного ключа на, idщоб знайти перший рядок. У другому потрібно сортувати повний результат у valстовпці (неіндексовано) .
a_horse_with_no_name

8
ORDER BY NUMBERСинтаксис дуже схильний до помилок.
usr

2
Додаючи до останнього коментаря, у SELECT *поєднанні з індексом стовпця в ORDER BYзаплутаному, який стовпець сортується - ще одна причина уникати *s ...
lc.

@ lc., що ти маєш на увазі?
Печер'є

@Pacerier Я маю на увазі, що *це не явно. Так що сказати "дай мені всі стовпчики та розбери по третьому" - це настільки ж детерміновано, як і сказати "піди до супермаркету та скажи мені, скільки світлофорів ти пройшов"
lc.

Відповіді:


33

Фраза ORDER BY 1стосується різних стовпців; у першому воно буде id, у другому val. Оскільки idце ключ, він буде проіндексований, а order byволя буде тривіальною кількістю роботи. Щоб order by val, однак, системі доведеться отримувати кожен рядок, сортувати повну таблицю val, а потім вибирати лише один із цих рядків.

Змініть обидва запити, order by idі я думаю, що час виконання буде майже однаковим.


3
Іноді найвибагливіші запитання - це ті, які просто дивляться нам в обличчя. Спасибі, Майкл!
dotancohen

7

MG добре пояснює різницю продуктивності у вашому запиті. Я збираюся вирішити це:

Я завжди вважав, що * запитів слід уникати спеціально з міркувань продуктивності.

select *не несе конкретних штрафних санкцій сам по собі, це проблематично при неправильному використанні. У запиті на одну таблицю він працює чудово. тепер приєднайте цю таблицю до іншої з 20 стовпцями, а пізніше додайте приєднується до 5 інших таблиць з багатьма стовпцями кожна. ЗАРАЗ це проблема. Так є і люди, які навчають широкої табірної допомоги "ніколи не роблять X", не пояснюючи чому.


3
SELECT *може бути проблемою навіть для запиту на одну таблицю. Наприклад, SELECT * FROM hashes ORDER BY val;ймовірно , буде виконано повне сканування таблиці, а потім сортування, в той час як SELECT val FROM hashes ORDER BY val;буде зроблено лише повне сканування індексу, і ніякого роду (якщо припустимо, що індекс існує на val). Отже, ніколи не зашкодить вибирати лише ті результати, які нам потрібні.
ypercubeᵀᴹ

Я припускаю, що ви це бачили? sqlblog.com/blogs/aaron_bertrand/archive/2009/10/10/…
Макс Вернон

@ypercube, чи означає це відбувається , навіть якщо наш select(*)використовується тільки в якості суб -Виберіть? Оскільки це вбудований вибір, чи не міг би MySQL бути досить розумним, щоб з'ясувати фактичні стовпці, які потрібно вибрати?
Pacerier

@Pacerier mysql оптимізатор має різні рівні "розумності", залежно від версії, яку ви використовуєте. У гернеалі він був досить тупим щодо вкладених підзапитів, тому все, що ви могли допомогти йому, було добре.
ypercubeᵀᴹ

@ypercube, Ах, якщо тільки він такий розумний, як pgsql.
Pacerier
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.