Можно выбрать * использование когда-либо оправдано?

Я всегда проповедовал моим разработчикам, что SELECT * является злым, и его следует избегать как чуму.

Есть ли случаи, когда это может быть оправдано?

Я не говорю о COUNT(*), который может определить большинство оптимизаторов.

Edit

Я говорю о производственном коде.

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

Ответ 1

Я очень доволен использованием * в триггерах аудита.

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

(Like dotjoe) Я также счастлив использовать его в производных таблицах и выражениях столбцов. Хотя я обычно делаю это наоборот.

WITH t
     AS (SELECT *,
                ROW_NUMBER() OVER (ORDER BY a) AS RN
         FROM   foo)
SELECT a,
       b,
       c,
       RN
FROM   t; 

Я в основном знаком с SQL Server и там, по крайней мере, у оптимизатора нет проблем, признавая, что потребуются только столбцы a,b,c, а использование * во внутреннем выражении таблицы не вызывает ненужных издержек и отбрасывание ненужных столбцов.

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

Ответ 2

Существует много сценариев, где SELECT * является оптимальным решением. Запуск специальных запросов в Management Studio, чтобы получить представление о данных, с которыми вы работаете. Запрос таблиц, в которых вы еще не знаете имена столбцов, поскольку это первый раз, когда вы работали с новой схемой. Создание одноразовых инструментов quick'n'dirty для однократной миграции или экспорта данных.

Я согласен с тем, что в "правильной" разработке вы должны избегать этого, но есть много сценариев, где "правильное" развитие не обязательно является оптимальным решением бизнес-задачи. Правила и лучшие практики велики, если вы знаете, когда их нарушать.:)

Ответ 3

Я буду использовать его в производстве при работе с CTE. Но в этом случае это не действительно select *, потому что я уже указывал столбцы в CTE. Я просто не хочу реагировать на окончательный выбор.

with t as (
    select a, b, c from foo
)

select t.* from t;

Ответ 4

Нет, о чем я могу думать, если вы говорите о реальном коде.

Люди говорят, что упрощают разработку добавочных столбцов (поэтому они автоматически возвращаются и могут использоваться без изменения хранимой процедуры) не имеют понятия о написании оптимального кода /sql.

Я использую его только при написании специальных запросов, которые не будут использоваться повторно (выяснение структуры таблицы, получение некоторых данных, когда я не уверен, что такое имена столбцов).

Ответ 5

Я думаю, что использование select * в предложении exists подходит:

select some_field from some_table 
where exists 
 (select * from related_table [join condition...])

Некоторым людям нравится использовать select 1 в этом случае, но это не изящно, и он не покупает никаких улучшений производительности (ранняя оптимизация снова наносит удар).

Ответ 6

В производственном коде я бы с тобой согласился на 100%.

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

Ответ 7

У вас есть ряд ответов на ваш вопрос, но вы, кажется, отклоняете все, что не отвлекает вас от того, что вы хотите услышать. Тем не менее, здесь это для третьего (до сих пор) времени: иногда нет узкого места. Иногда производительность лучше, чем штраф. Иногда таблицы находятся в потоке, и изменение каждого запроса SELECT - это еще один бит возможной несогласованности для управления. Иногда вам нужно выполнить невыполненный график, и это последнее, о чем вам нужно подумать.

Если вы живете в пуле, обязательно укажите все имена столбцов. Но зачем останавливаться? Перезапишите приложение в режиме без схемы. Черт, напишите свои собственные dbms в сборке. Это действительно показало бы им.

Ответ 8

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

Ответ 9

В качестве инструмента я использую его, чтобы быстро обновить свою память относительно того, что я могу получить от запроса. Как сам запрос уровня производительности.. никак.

Ответ 10

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

Ответ 11

О том, что я могу придумать, будет только при разработке утилиты или инструментальных средств SQL, которые записываются для работы с любой базой данных. Даже здесь, однако, я хотел бы запросить системные таблицы, чтобы получить структуру таблицы, а затем построить из нее любой необходимый запрос.

Было одно недавнее место, где моя команда использовала SELECT *, и я думаю, что все в порядке... у нас есть база данных, которая существует как фасад против другой базы данных (назовем ее DB_Data), поэтому она в основном состоит из представления против таблиц в другой базе данных. Когда мы генерируем представления, мы фактически генерируем списки столбцов, но в базе данных DB_Data создается один набор представлений, которые автоматически генерируются, поскольку строки добавляются в общую таблицу поиска (этот проект был создан до того, как я пришел сюда). Мы написали DDL-триггер, чтобы при создании представления в DB_Data этим процессом автоматически создавалось другое представление на фасаде. Поскольку представление всегда генерируется, чтобы точно соответствовать представлению в DB_Data и всегда обновляется и хранится в синхронизации, мы просто использовали SELECT * для простоты.

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

Ответ 12

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

Ответ 13

Как еще разработчики phpmyadmin гарантируют, что они отображают все поля таблиц БД?

Ответ 14

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

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

На практике я придерживаюсь SELECT * для 3-х случаев (некоторые упоминаются в других ответах:

  • Как специальный запрос, введенный в GUI или в командной строке SQL.
  • Как содержимое предиката EXISTS.
  • В приложении, которое обрабатывает общие таблицы, не требуя знать, что они означают (например, самосвал или отличается).

Ответ 15

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

Например, в одной системе, над которой я работал, у нас были UDF (User Defined Fields), где пользователь мог выбирать поля, которые они хотели в отчете, порядок, а также фильтрацию. При построении результирующего набора было больше смысла просто "выбирать" из временных таблиц, которые я строю, вместо того, чтобы отслеживать, какие столбцы были активны.

Ответ 16

  • Мне нужно несколько раз отображать данные из таблицы, имена столбцов которой неизвестны. Поэтому я сделал SELECT * и получил имена столбцов во время выполнения.

  • Мне было предоставлено устаревшее приложение, в котором таблица имела 200 столбцов, а представление было 300. Экспозиция риска от SELECT * была бы не хуже, чем из перечисления всех 300 столбцов явно.

Ответ 17

Select * в производственном коде оправдан в любое время, когда:

  • это не узкое место в производительности
  • Время разработки является критическим.

Почему мне нужно накладные расходы на возврат и необходимость беспокоиться об изменении соответствующих хранимых процедур каждый раз, когда я добавляю поле в таблицу?

Почему я даже хочу подумать о том, выбрали ли я правильные поля, когда в большинстве случаев я хочу, чтобы большинство из них в любом случае, и подавляющее большинство из немногих раз, что-то еще является узким местом?

Если у меня есть конкретная проблема с производительностью, я вернусь и исправлю это. В противном случае в моей среде это просто преждевременная (и дорогостоящая) оптимизация, без которой я могу обойтись.


Изменить.. после обсуждения, я думаю, я бы добавил к этому:

... и где люди не делали других нежелательных вещей, например, пытались получить доступ к столбцам (i), которые в любом случае могли бы прорваться в другие ситуации:)

Ответ 18

Если вы хотите найти все столбцы и хотите заказать, вы можете сделать следующее (по крайней мере, если вы используете MySQL):

SHOW COLUMNS FROM mytable FROM mydb; (1)

Вы можете увидеть каждую соответствующую информацию обо всех ваших полях. Вы можете предотвратить проблемы с типами, и вы можете точно знать все имена столбцов. Эта команда выполняется очень быстро, потому что вы просто запрашиваете структуру таблицы. Из результатов вы выберете все имя и построите такую ​​строку:

"select " + fieldNames[0] + ", fieldNames[1]" + ", fieldNames[2] from mytable". (2)

Если вы не хотите запускать две отдельные команды MySQL, потому что команда MySQL стоит дорого, вы можете включить (1) и (2) в хранимую процедуру, которая будет иметь результаты как параметр OUT, таким образом, вы будете просто вызовите хранимую процедуру, и каждая генерация команд и данных произойдет на сервере базы данных.

Ответ 19

Зависит от контекста производственного программного обеспечения.

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

Другими словами, если вы решили обрабатывать "выбор полей" с помощью некоторых других средств (как в автоматических или пользовательских фильтрах после извлечения набора результатов), то это выглядит просто отлично.

Если, с другой стороны, мы говорим о каком-то корпоративном программном обеспечении с бизнес-правилами, определенной схемой и т.д.... тогда я согласен, что * SELECT ** - плохая идея.

EDIT: О, и когда исходная таблица является хранимой процедурой для триггера или представления, "* SELECT **" должен быть точным, потому что вы управляете набором результатов с помощью других средств (определение представления или сохраненный результирующий набор).

Ответ 20

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

select * 
into staging.aTable 
from remotedb.dbo.aTable

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