Почему SELECT * считается вредным?

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

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

Ответ 1

Существуют три основные причины:

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

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

  • Проблемы с привязкой. Когда вы выбираете *, можно получить два столбца с одинаковыми именами из двух разных таблиц. Это может часто приводить к сбою вашего потребителя данных. Представьте себе запрос, который объединяет две таблицы, каждая из которых содержит столбец с именем "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.)

Ответ 2

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

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

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

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

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

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

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

Дизайн

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

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

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

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

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

Ответ 3

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

Разве это не означает, что код будет изменен, если вы добавили новый столбец, который вам нужен?

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

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

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

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

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

Ответ 8

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

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

Ответ 9

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

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

Ответ 10

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

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

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

Это тоже то же рассуждение, почему, если вы делаете INSERT, вы всегда должны указывать столбцы.

Ответ 11

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

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

Ответ 12

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

Никогда не переключайтесь с "SELECT *" ,

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

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

Ответ 13

Понимайте свои требования до разработки схемы (если это возможно).

Узнайте о данных,     1) индексация     2) тип используемого хранилища,     3) двигатель или функции поставщика; то есть... кеширование, возможности памяти     4) типы данных     5) размер стола     6) частота запроса     7) связанные рабочие нагрузки, если общий ресурс     8) Тест

A) Требования будут различаться. Если аппаратное обеспечение не поддерживает ожидаемую рабочую нагрузку, вы должны переоценить, как обеспечить требования в рабочей нагрузке. Относительно столбца добавления к таблице. Если база данных поддерживает представления, вы можете создать индексированное (?) Представление конкретных данных с конкретными именованными столбцами (vs. select '*'). Периодически просматривайте свои данные и схему, чтобы убедиться, что вы никогда не сталкиваетесь с синдромом "Мусор" → "Мусор".

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

1) Индексирование: выбор * будет выполнять таблицы. В зависимости от различных факторов это может быть связано с запросом на диск и/или с другими запросами. Если таблица многоцелевая, убедитесь, что все запросы выполнены и выполняются ниже целевого времени. Если имеется большой объем данных, а ваша сеть или другой ресурс не настроен; вам нужно принять это во внимание. База данных - это общая среда.

2) тип хранилища. Т.е.: если вы используете SSD, диск или память. Время ввода/вывода и загрузка системы/процессора будут различаться.

3) Может ли администратор базы данных настроить базу данных/таблицы для повышения производительности? Усвоение по какой-либо причине, команды решили, что выбор "*" - лучшее решение проблемы; может ли БД или таблица быть загружены в память. (Или другой метод... может быть, ответ был спроектирован так, чтобы ответить на 2-3-секундную задержку? --- пока реклама играет, чтобы заработать доход компании...)

4) Начните с базовой линии. Поймите свои типы данных и как результаты будут представлены. Меньшие типы данных, количество полей уменьшают количество данных, возвращаемых в результирующий набор. Это оставляет ресурсы доступными для других системных потребностей. Системные ресурсы обычно имеют предел; "всегда" работают ниже этих пределов для обеспечения стабильности и предсказуемого поведения.

5) размер таблицы/данных. select '*' распространен с крошечными таблицами. Они обычно подходят в памяти, а время отклика - быстрое. Опять же... просмотрите свои требования. План ползучести функции; всегда планируют текущие и возможные будущие потребности.

6) Частота запросов/запросов. Помните о других нагрузках в системе. Если этот запрос срабатывает каждую секунду, а таблица крошечная. Результирующий набор может быть сконструирован так, чтобы оставаться в кеше/памяти. Однако, если запрос является частым пакетным процессом с гигабайтами/терабайтами данных... вам может быть лучше посвятить дополнительные ресурсы, чтобы не повлиять на другие рабочие нагрузки.

7) Связанные рабочие нагрузки. Понять, как используются ресурсы. Является ли сеть/система/база данных/таблица/приложение выделенной или разделяемой? Кто является заинтересованными сторонами? Это для производства, разработки или качества? Является ли это временным "быстрым решением". Вы протестировали сценарий? Вы будете удивлены, сколько проблем может существовать на сегодняшнем оборудовании. (Да, производительность быстро... но дизайн/производительность по-прежнему снижается.) Требуется ли системе для выполнения 10K запросов в секунду против 5-10 запросов в секунду. Разделяет ли сервер базы данных или выполняет другие приложения мониторинг выполнения на общем ресурсе. Некоторые приложения/языки; O/S будет потреблять 100% памяти, вызывая различные симптомы/проблемы.

8) Тест: исследуйте свои теории и понимайте как можно больше. Ваш выбор "*" может быть большой проблемой, или это может быть что-то, о чем вам даже не нужно беспокоиться.

Ответ 14

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

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

Ответ 15

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

Например: BigQuery:

Ценообразование запросов

Ценообразование запросов относится к стоимости запуска ваших SQL-команд и пользовательских функций. Стоимость BigQuery для запросов с использованием одной метрики: количество обработанных байтов.

и проекция управления - Избегайте SELECT *:

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

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

Использование SELECT * является самым дорогим способом запроса данных. Когда вы используете SELECT *, BigQuery выполняет полное сканирование каждого столбца в таблице.