Выбирает * все еще большой нет-нет на SQL Server 2012?

В прошлые дни считалось большим no-no делать select * from table или select count(*) from table из-за производительности удар.

Это все еще имеет место в более поздних версиях SQL Server (я использую 2012 год, но, думаю, вопрос будет применяться к 2008 - 2014 годам)?

Изменить: Поскольку люди, кажется, немного меня здесь привили, я смотрю на это с контрольной /академической точки зрения, а не на то, что это «правильная» вещь (какая из конечно, это не так)

40 голосов | спросил Piers Karsenbarg 30 J0000006Europe/Moscow 2014, 18:07:35

8 ответов


49

Если вы SELECT COUNT(*) FROM TABLE, который возвращает только одну строку (счетчик), относительно лёгкий, и это способ получить эту датум.

И SELECT * не является физическим no-no, поскольку он легален и разрешен.

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

Итак, Да рекомендуется использовать как общую практику, потому что это расточительно для ваших ресурсов.

Единственное реальное преимущество SELECT * - не вводить все имена столбцов. Но из SSMS вы можете использовать перетаскивание, чтобы получить имена столбцов в вашем запросе и удалить те, которые вам не нужны.

Аналогия: Если кто-то использует SELECT *, когда им не нужен каждый столбец, будут ли они также использовать SELECT без WHERE (или какое-либо другое ограничение), когда им не нужна каждая строка?

ответил RLF 30 J0000006Europe/Moscow 2014, 18:20:57
22

В дополнение к уже существующему ответу, я считаю, что стоит отметить, что разработчики часто слишком ленивы при работе с современными ORM, такими как Entity Framework. Хотя DBA стараются избегать SELECT *, разработчики часто пишут семантически эквивалентные, например, в c # Linq:

var someVariable = db.MyTable.Where(entity => entity.FirstName == "User").ToList();

В сущности, это приведет к следующему:

SELECT * FROM MyTable WHERE FirstName = 'User'

Также есть дополнительные накладные расходы, которые еще не были покрыты. Это ресурсы, необходимые для обработки каждого столбца в каждой строке соответствующему объекту. Кроме того, для каждого объекта, хранящегося в памяти, этот объект должен быть очищен. Если вы выбрали только те столбцы, которые вам нужны, вы можете сэкономить более 100 мб. Хотя это и не является огромной суммой, его совокупный эффект сбора мусора и т. Д., Который является стороной с клиентом затрат.

Так что да, для меня, по крайней мере, это и всегда будет большой нет. Мы также должны быть осведомлены о «скрытых» затратах на это больше.

Добавление

Вот пример вытягивания только данных, которые вам нужны по запросу в комментариях:

var someVariable = db.MyTable.Where(entity => entity.FirstName == "User")
                             .Select(entity => new { entity.FirstName, entity.LastNight });
ответил Stuart Blackler 30 J0000006Europe/Moscow 2014, 23:16:22
12

Производительность. Запрос с SELECT *, вероятно, никогда не будет закрывающим запросом ( Объяснение простого обсуждения , Описание переполнения стека ).

Будущая проверка: ваш запрос может вернуть все семь столбцов сегодня, но если кто-то добавит пять столбцов в следующем году, то через год ваш запрос вернет двенадцать столбцов, потеряв IO и CPU.

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

Лучшая практика : никогда не используйте SELECT * в производственном коде.

Для подзапросов я предпочитаю WHERE EXISTS ( SELECT 1 FROM … ).

Изменить : Чтобы ответить на комментарий Крейга Янга ниже, использование «SELECT 1» в подзапросе не является «оптимизацией» - это значит, что я могу встать перед моим классом и сказать: не используйте SELECT *, никаких исключений! "

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

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

Обратите внимание, что я рассматриваю COUNT(*) исключение, потому что это другое синтаксическое использование «*».

ответил Greenstone Walker 1 J000000Tuesday14 2014, 03:09:57
9

В SQL Server 2012 (или любой версии с 2005 года) использование SELECT *... является только возможной проблемой производительности в инструкции SELECT верхнего уровня для запроса.

Таким образом, это НЕ проблема в представлениях (*), в подзапросах, в предложениях EXIST, в CTE или в SELECT COUNT(*).. и т. д. и т. д. Обратите внимание, что это вероятно, верен и для Oracle, и для DB2, и возможно PostGres (не уверен), но очень вероятно, что во многих случаях это проблема во MySql.

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

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

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

Так что изменилось? В основном, оптимизаторы SQL успешно включили функцию «Оптимизация столбцов», которая просто означает, что теперь они могут вычисляться в подзапросах нижнего уровня, если вы когда-либо собираетесь использовать столбец на верхних уровнях запроса.

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

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

ответил RBarryYoung 1 J000000Tuesday14 2014, 01:28:59
4

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

ответил Jon of All Trades 2 J000000Wednesday14 2014, 17:15:10
3

Физически и проблематично разрешено использовать select * from table, однако это плохая идея. Зачем?

Прежде всего, вы обнаружите, что возвращаете столбцы, которые вам не нужны (ресурс тяжелый).

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

В-третьих, это делает его сложнее для разработчика. Как часто вам нужно переходить от SSMS к VS, чтобы получить все имена столбцов?

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

ответил CharlieHorse 1 J000000Tuesday14 2014, 18:50:58
3

Это может быть проблемой, если вы поместите код Select * ... в программу, поскольку, как указывалось ранее, база данных может со временем меняться и иметь больше столбцов, чем ожидалось когда вы написали запрос. Это может привести к сбою программы (в лучшем случае), или программа может пойти на ее веселье и испортить некоторые данные, потому что она смотрит на значения полей, которые она не была написана для обработки. Короче говоря, производственный код должен ВСЕГДА указывать поля, которые будут возвращены в SELECT.

Сказав это, у меня меньше проблем, когда Select * является частью предложения EXISTS, поскольку все, что будет возвращено в программу, является логическим, указывающим успех или неудача выбора. Другие могут не согласиться с этой позицией, и я уважаю их мнение по этому поводу. Это может быть немного менее эффективно для кода Select *, чем для кода «Выбрать 1» в предложении EXISTS, но я не думаю, что существует опасность повреждения данных , в любом случае.

ответил Mark Ross 2 J000000Wednesday14 2014, 03:29:48
2

Множество ответов, почему select * неверно, поэтому я расскажу, когда я чувствую, что это правильно или по крайней мере ОК.

1) В EXISTS содержимое части SELECT запроса игнорируется, поэтому вы даже можете записать SELECT 1/0, и это не приведет к ошибке. EXISTS просто проверяет, что некоторые данные вернутся и вернутся на boolean на основе этого.

IF EXISTS(
    SELECT * FROM Table WHERE [email protected]
)

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

ответил UnhandledExcepSean 2 J000000Wednesday14 2014, 19:09:01

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132