Почему SELECT * считается вредным? - PullRequest
225 голосов
/ 04 сентября 2010

Почему SELECT * плохая практика?Разве это не означало бы меньше кода для изменения, если вы добавили новый столбец, который вы хотели?

Я понимаю, что SELECT COUNT(*) - это проблема производительности на некоторых БД, но что если вы действительно хотите каждый столбец?

Ответы [ 16 ]

288 голосов
/ 04 сентября 2010

На самом деле есть три основные причины:

  • Неэффективность перемещения данных к потребителю. Когда вы выбираете *, вы часто извлекаете из базы данных больше столбцов, чем требуется вашему приложению. Это заставляет больше данных перемещаться с сервера базы данных на клиент, замедляя доступ и увеличивая нагрузку на ваши машины, а также тратя больше времени на перемещение по сети. Это особенно верно, когда кто-то добавляет новые столбцы в базовые таблицы, которые не существуют и не были нужны, когда первоначальные потребители кодировали свой доступ к данным.

  • Проблемы с индексированием. Рассмотрим сценарий, в котором вы хотите настроить запрос на высокий уровень производительности. Если бы вы использовали *, а он возвращал больше столбцов, чем вам было на самом деле нужно, серверу часто приходилось бы использовать более дорогие методы для извлечения ваших данных, чем в противном случае. Например, вы не сможете создать индекс, который бы просто покрывал столбцы в вашем списке SELECT, и даже если бы вы это сделали (включая все столбцы [ shudder ]), следующий парень, который пришел и добавление столбца в базовую таблицу приведет к тому, что оптимизатор проигнорирует оптимизированный индекс покрытия, и вы, вероятно, обнаружите, что производительность вашего запроса существенно снизится без видимой причины.

  • Проблемы с привязкой. Когда вы выбираете *, можно получить два столбца с одинаковым именем из двух разных таблиц. Это часто может привести к сбою вашего потребителя данных. Представьте себе запрос, который объединяет две таблицы, каждая из которых содержит столбец с именем «ID». Как потребитель узнает, что есть что? SELECT * также может запутать представления (по крайней мере, в некоторых версиях SQL Server), когда базовые структуры таблиц изменяются - представление не перестраивается, и возвращаемые данные могут быть бессмысленными . И хуже всего то, что вы можете позаботиться о том, чтобы назвать свои столбцы как угодно, но следующий парень, который придет, может не знать, что ему нужно беспокоиться о добавлении столбца, который будет конфликтовать с вашим уже разработанным имена.

Но не все так плохо для SELECT *. Я использую это свободно для этих случаев использования:

  • Специальные запросы. При попытке отладки чего-либо, особенно за узкой таблицей, с которой я, возможно, не знаком, SELECT * часто является моим лучшим другом. Это помогает мне просто увидеть, что происходит, без необходимости делать множество исследований относительно того, каковы основные названия столбцов. Это становится большим плюсом, чем длиннее имена столбцов.

  • Когда * означает «ряд». В следующих случаях использования SELECT * вполне подойдет, и слухи о том, что это убийца производительности - это всего лишь городские легенды, которые, возможно, имели некоторую обоснованность. лет назад, но не сейчас:

    SELECT COUNT(*) FROM table;
    

    в этом случае * означает «считать строки». Если бы вы использовали имя столбца вместо *, , он бы подсчитал строки, в которых значение этого столбца не было равно нулю . COUNT (*), на мой взгляд, действительно дает понять, что вы считаете строк , и вы избегаете странных крайних случаев, вызванных удалением NULL из ваших агрегатов.

    То же самое относится и к этому типу запроса:

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

    в любой базе данных стоит своей соли, * просто означает «ряд». Неважно, что вы положили в подзапрос. Некоторые люди используют идентификатор b в списке SELECT, или они будут использовать номер 1, но IMO эти соглашения в значительной степени бессмысленно. То, что вы имеете в виду, это «сосчитать ряд», и это то, что означает *. Большинство оптимизаторов запросов достаточно умны, чтобы это знать. (Хотя, если честно, я только знаю , что верно для SQL Server и Oracle.)

85 голосов
/ 04 сентября 2010

Символ звездочки "*" в операторе SELECT является сокращением для всех столбцов таблиц, участвующих в запросе.

Производительность

Сокращение * может быть медленнее, поскольку:

  • Не все поля проиндексированы, что приводит к полному сканированию таблицы - менее эффективно
  • То, что вы сохраняете для отправки SELECT * по сети, рискует отсканировать полную таблицу
  • Возврат большего количества данных, чем необходимо
  • Возврат конечных столбцов с использованием типа данных переменной длины может привести к накладным расходам при поиске

Обслуживание

При использовании SELECT *:

  • Кто-то, незнакомый с базой кода, будет вынужден обратиться к документации, чтобы узнать, какие столбцы возвращаются добыть в состоянии сделать компетентные изменения.Делая код более читабельным, сводя к минимуму неоднозначность и работу, необходимую людям, незнакомым с кодом, вы экономите больше времени и усилий в долгосрочной перспективе.
  • Если код зависит от порядка столбцов, SELECT * будет скрывать ошибку, ожидающую возникновенияесли у таблицы был изменен порядок столбцов.
  • Даже если вам понадобится каждый столбец во время написания запроса, в будущем это может быть не так
  • использование усложняет профилирование

Дизайн

SELECT * - это анти-шаблон :

  • Цель запросаменее очевидно;столбцы, используемые приложением, непрозрачны
  • Это нарушает правило модульности о строгой типизации, когда это возможно.Явное почти всегда лучше.

Когда следует использовать «SELECT *»?

Допустимо использовать SELECT *, когда есть явная необходимость для каждого столбца в таблице (ах), в отличие откаждый столбец, существовавший на момент написания запроса.База данных внутренне расширит * в полный список столбцов - разницы в производительности нет.

В противном случае явно перечислите каждый столбец, который будет использоваться в запросе - предпочтительно при использовании псевдонима таблицы.

18 голосов
/ 04 сентября 2010

Даже если вы хотите выбрать каждый столбец сейчас, вы можете не захотеть выбирать каждый столбец после того, как кто-то добавит один или несколько новых столбцов. Если вы пишете запрос с помощью SELECT *, вы рискуете, что в какой-то момент кто-то может добавить столбец текста, который заставит ваш запрос выполняться медленнее, даже если этот столбец вам на самом деле не нужен.

Разве это не означало бы меньше кода для изменения, если вы добавили новый столбец, который вы хотели?

Скорее всего, если вы действительно захотите использовать новый столбец, вам все равно придется внести в свой код довольно много других изменений. Вы только экономите , new_column - всего несколько символов ввода.

4 голосов
/ 04 сентября 2010

Если вы назовете столбцы в операторе SELECT, они будут возвращены в указанном порядке и, следовательно, могут безопасно ссылаться на числовой индекс. Если вы используете «SELECT *», вы можете получить столбцы в произвольной последовательности и, таким образом, можете безопасно использовать столбцы только по имени. Если вы заранее не знаете, что вы захотите делать с любым новым столбцом, который добавляется в базу данных, наиболее вероятным правильным действием будет его игнорирование. Если вы собираетесь игнорировать любые новые столбцы, добавляемые в базу данных, их извлечение не принесет никакой пользы.

3 голосов
/ 04 сентября 2010

Думайте об этом как об уменьшении связи между приложением и базой данных.

Подводя итог аспекту «запах кода»:
SELECT * создает динамическую зависимость между приложением и схемой. Ограничение его использования - один из способов сделать зависимость более определенной, в противном случае изменение базы данных повышает вероятность сбоя приложения.

3 голосов
/ 04 сентября 2010

Если вы добавите поля в таблицу, они будут автоматически включены во все ваши запросы, где вы используете select *.Это может показаться удобным, но это замедлит работу вашего приложения, поскольку вы извлекаете больше данных, чем вам нужно, и в какой-то момент приведет к сбою приложения.

Существует ограничение на количество данных, которое вы можете получитьв каждом ряду результата.Если вы добавите поля в свои таблицы, чтобы результат превысил этот предел, вы получите сообщение об ошибке при попытке выполнить запрос.

Это ошибки, которые трудно найти.Вы вносите изменения в одном месте, а оно взрывается в другом месте, которое вообще не использует новые данные.Это может быть даже менее часто используемый запрос, поэтому требуется некоторое время, прежде чем кто-то его использует, что еще более затрудняет привязку ошибки к изменению.

Если указать, какие поля вы хотите получить в результате,Вы защищены от такого рода переполнения.

3 голосов
/ 04 сентября 2010

Если вы действительно хотите каждый столбец, я не видел разницы в производительности между select (*) и именованием столбцов.Драйвер для именования столбцов может быть просто явным указанием того, какие столбцы вы ожидаете увидеть в своем коде.

Часто, однако, вам не нужен каждый столбец, и выбор (*) может привести к ненужной работедля сервера базы данных и ненужной информации, передаваемой по сети.Это вряд ли вызовет заметную проблему, если система интенсивно не используется или подключение к сети медленное.

3 голосов
/ 04 сентября 2010

В большинстве случаев SELECT * вызывает ошибки во время выполнения в вашем приложении, а не во время разработки. Он скрывает информацию об изменениях столбцов или неверных ссылках в ваших приложениях.

2 голосов
/ 07 февраля 2016

Ссылка взята из этой статьи.

Никогда не используйте "SELECT *",

Я нашел только одну причину использовать "SELECT *"

Если у вас есть особые требования и создана динамическая среда, при добавлении или удалении столбца автоматически обрабатывается код приложения. В этом особом случае вам не нужно менять код приложения и базы данных, и это автоматически повлияет на производственную среду. В этом случае вы можете использовать «SELECT *».

1 голос
/ 04 сентября 2010

Я не думаю, что для этого действительно может быть общее правило. Во многих случаях я избегал SELECT *, но я также работал с платформами данных, где SELECT * был очень полезен.

Как и у всех вещей, здесь есть свои преимущества и издержки. Я думаю, что часть соотношения выгоды и стоимости заключается в том, насколько вы контролируете структуры данных. В тех случаях, когда SELECT * работал хорошо, структуры данных строго контролировались (это было программное обеспечение для розничной торговли), поэтому не было большого риска, что кто-то собирается вставить огромное поле BLOB в таблицу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...