Если мне просто нужны 2/3 столбца, и я запрашиваю SELECT *
вместо предоставления этих столбцов в запросе выбора, есть ли какое-либо снижение производительности в отношении большего / меньшего количества операций ввода-вывода или памяти?
Если я выберу * без необходимости, то могут возникнуть накладные расходы сети.
Но в операции выбора всегда ли движок базы данных извлекает атомарный кортеж с диска или извлекает только те столбцы, которые запрашиваются в операции выбора?
Если он всегда извлекает кортеж, то накладные расходы ввода-вывода такие же.
В то же время может потребоваться память для удаления запрошенных столбцов из кортежа, если он извлекает кортеж.
Поэтому, если это так, select someColumn будет иметь больше накладных расходов на память, чем select *
источник
SELECT
выполняются / обрабатываются запросы, отличается от базы данных к базе данных.CREATE VIEW foo_view AS SELECT * FROM foo;
, а затем добавьте столбцы в таблицу foo позже, эти столбцы не будут автоматически отображаться в foo_view, как ожидалось. Другими словами,*
в этом контексте раскрывается только один раз (во время создания представления), а не для каждого SELECT. Из-за сложностей, связанных с ALTER TABLE, я бы сказал, что (на практике)*
считается вредным.Ответы:
Он всегда извлекает кортеж (за исключением случаев, когда таблица была сегментирована по вертикали - разбита на части по столбцам), поэтому, чтобы ответить на заданный вами вопрос, это не имеет значения с точки зрения производительности. Однако по многим другим причинам (ниже) вы всегда должны выбирать именно те столбцы, которые вам нужны, по имени.
Он всегда извлекает кортеж, потому что (в РСУБД всех поставщиков, с которыми я знаком), базовая структура хранения на диске для всего (включая данные таблиц) основана на определенных страницах ввода-вывода (в SQL Server, например, каждая страница 8 килобайт). И каждое чтение или запись ввода / вывода осуществляется по страницам .. Т.е. каждая запись или чтение - это полная страница данных.
Из-за этого основного структурного ограничения следствием этого является то, что каждая строка данных в базе данных всегда должна находиться на одной и только одной странице. Он не может охватывать несколько страниц данных (за исключением особых вещей, таких как капли, где фактические данные больших двоичных объектов хранятся в отдельных блоках страниц, а фактический столбец строки таблицы тогда получает только указатель ...). Но эти исключения являются просто исключениями и обычно не применяются, за исключением особых случаев (для особых типов данных или определенных оптимизаций для особых обстоятельств).
Даже в этих особых случаях, как правило, фактическая строка данных самой таблицы (которая содержит указатель на фактические данные для Blob или что-то еще), он должен храниться на одной странице ввода-вывода ...
ИСКЛЮЧЕНИЕ. Единственное место, где
Select *
ОК, - это подзапрос после предложения предикатаExists
илиNot Exists
, например:РЕДАКТИРОВАТЬ: Чтобы обратиться к комментарию @Mike Sherer, да, это правда, как технически, с небольшим определением для вашего особого случая, так и эстетически. Во-первых, даже когда запрошенный набор столбцов является подмножеством тех, которые хранятся в каком-либо индексе, обработчик запросов должен получить каждый столбец, хранящийся в этом индексе, а не только запрошенные, по тем же причинам - ВСЕ операции ввода-вывода должны выполняться в страниц, а данные индекса хранятся на страницах ввода-вывода так же, как данные таблицы. Поэтому, если вы определяете «кортеж» для страницы индекса как набор столбцов, хранящихся в индексе, утверждение все равно остается верным.
и утверждение истинно эстетически, потому что дело в том, что он извлекает данные на основе того, что хранится на странице ввода-вывода, а не на основе того, что вы запрашиваете, и это верно независимо от того, обращаетесь ли вы к странице ввода-вывода базовой таблицы или к индексу. Страница ввода / вывода.
По другим причинам, чтобы не использовать
Select *
, см. ПочемуSELECT *
считается вредным? :источник
select *
накладные расходы на память будут меньше, чемselect column
накладные расходы ввода-вывода. Итак, если мы оставим сетевые накладные расходы.select *
если накладные расходы меньше, чем уselect column
Есть несколько причин, по которым вы никогда (никогда) не должны использовать
SELECT *
в производственном коде:поскольку вы не даете своей базе данных никаких подсказок относительно того, что вы хотите, сначала нужно будет проверить определение таблицы, чтобы определить столбцы в этой таблице. Этот поиск будет стоить некоторое время - не так много в одном запросе - но со временем он накапливается.
если вам нужно только 2/3 столбца, вы выбираете на 1/3 слишком много данных, которые необходимо получить с диска и отправить по сети
если вы начнете полагаться на определенные аспекты данных, например порядок возвращаемых столбцов, вы можете получить неприятный сюрприз после реорганизации таблицы и добавления новых столбцов (или удаления существующих)
в SQL Server (не уверен в других базах данных), если вам нужно подмножество столбцов, всегда есть вероятность, что некластеризованный индекс может покрывать этот запрос (содержать все необходимые столбцы). С a
SELECT *
вы отказываетесь от этой возможности с самого начала. В этом конкретном случае данные будут извлекаться из страниц индекса (если они содержат все необходимые столбцы), и, таким образом, дисковый ввод-вывод и накладные расходы на память будут намного меньше по сравнению с выполнениемSELECT *....
запроса.Да, сначала требуется немного больше ввода (такие инструменты, как SQL Prompt для SQL Server даже помогут вам в этом), но это действительно тот случай, когда есть правило без каких-либо исключений: никогда не используйте SELECT * в своем производственном коде. КОГДА-ЛИБО.
источник
Where Exists (Select * From ...
) использование,Select *
безусловно, не является проблемой и в некоторых кругах считается лучшей практикой.IF EXISTS(SELECT *...
это особый случай - поскольку там данные на самом деле не извлекаются, но это всего лишь проверка на существование, SELECT * здесь не проблема ...Вы должны всегда только
select
столбцы , которые вы на самом деле нужно. Никогда не менее эффективно выбирать меньше вместо большего, и вы также сталкиваетесь с меньшим количеством неожиданных побочных эффектов, таких как доступ к столбцам результатов на стороне клиента по индексу, а затем эти индексы становятся неверными из-за добавления нового столбца в таблицу.[править]: имел в виду доступ. Глупый мозг все еще просыпается.
источник
SELECT *
с ним.Если вы не храните большие двоичные объекты, производительность не имеет значения. Основная причина не использовать SELECT * заключается в том, что если вы используете возвращаемые строки как кортежи, столбцы возвращаются в том порядке, который указан в схеме, и если это изменится, вам придется исправить весь свой код.
С другой стороны, если вы используете доступ в стиле словаря, то не имеет значения, в каком порядке возвращаются столбцы, потому что вы всегда обращаетесь к ним по имени.
источник
Это сразу заставляет меня думать о таблице, которую я использовал, которая содержала столбец типа
blob
; обычно он содержал изображение в формате JPEG размером несколькоMb
секунд.Излишне говорить, что я не писал
SELECT
эту колонку, если она мне действительно не нужна. Распространение этих данных - особенно когда я выбрал несколько строк - было просто проблемой.Однако я признаю, что в противном случае я обычно запрашиваю все столбцы в таблице.
источник
Во время выбора SQL база данных всегда будет ссылаться на метаданные для таблицы, независимо от того, является ли это SELECT * для SELECT a, b, c ... Почему? Потому что именно здесь находится информация о структуре и расположении таблицы в системе.
Он должен прочитать эту информацию по двум причинам. Во-первых, просто составить заявление. Он должен убедиться, что вы указали как минимум существующую таблицу. Кроме того, структура базы данных могла измениться с момента последнего выполнения оператора.
Теперь очевидно, что метаданные БД кэшируются в системе, но их еще нужно обработать.
Затем метаданные используются для создания плана запроса. Это также происходит каждый раз при компиляции оператора. Опять же, это работает с кешированными метаданными, но это всегда делается.
Единственный раз, когда эта обработка не выполняется, - это когда БД использует предварительно скомпилированный запрос или кэширует предыдущий запрос. Это аргумент в пользу использования параметров привязки, а не буквального SQL. «SELECT * FROM TABLE WHERE key = 1» - это другой запрос, чем «SELECT * FROM TABLE WHERE key =?» и "1" привязана к вызову.
БД в значительной степени полагаются на кеширование страниц для своей работы. Многие современные БД достаточно малы, чтобы полностью уместиться в памяти (или, возможно, я должен сказать, что современная память достаточно велика, чтобы вместить многие БД). Тогда ваша основная стоимость ввода-вывода на серверной части - это ведение журнала и сброс страниц.
Однако, если вы все еще используете диск для своей БД, основная оптимизация, выполняемая многими системами, заключается в том, чтобы полагаться на данные в индексах, а не на сами таблицы.
Если у вас есть:
Затем, если вы выполните «ВЫБРАТЬ id, имя FROM customer WHERE id = 1», весьма вероятно, что ваша БД будет извлекать эти данные из индекса, а не из таблиц.
Зачем? Он, скорее всего, в любом случае будет использовать индекс для удовлетворения запроса (в отличие от сканирования таблицы), и даже если 'name' не используется в предложении where, этот индекс по-прежнему будет лучшим вариантом для запроса.
Теперь в базе данных есть все данные, необходимые для удовлетворения запроса, поэтому нет причин обращаться к самим страницам таблицы. Использование индекса приводит к уменьшению дискового трафика, поскольку у вас более высокая плотность строк в индексе по сравнению с таблицей в целом.
Это краткое объяснение конкретного метода оптимизации, используемого некоторыми базами данных. У многих есть несколько методов оптимизации и настройки.
В конце концов, SELECT * полезен для динамических запросов, которые вам нужно вводить вручную, я бы никогда не использовал его для «реального кода». Идентификация отдельных столбцов дает БД больше информации, которую она может использовать для оптимизации запроса, и дает вам лучший контроль в вашем коде от изменений схемы и т. Д.
источник
Я думаю, что на ваш вопрос нет точного ответа, потому что вы задумываетесь о производительности и возможности поддержки своих приложений.
Select column
является более производительнымselect *
, но если вы разрабатываете ориентированную объектную систему, вам понравится использование,object.properties
и вам могут понадобиться свойства в любой части приложений, тогда вам нужно будет написать больше методов для получения свойств в особых ситуациях, если вы не использоватьselect *
и заполнить все свойства. Ваши приложения должны иметь хорошую производительность при использовании,select *
и в некоторых случаях вам понадобится использовать столбец выбора для повышения производительности. Тогда у вас будет лучшее из двух миров: возможность писать и поддерживать приложения и производительность, когда вам нужна производительность.источник
Принятый ответ здесь неверен. Я столкнулся с этим, когда другой вопрос был закрыт как дубликат этого (пока я все еще писал свой ответ - grr - следовательно, SQL ниже ссылается на другой вопрос).
Вы всегда должны использовать атрибут SELECT, атрибут .... NOT SELECT *
Это в первую очередь для проблем с производительностью.
Не очень полезный пример. Вместо этого подумайте:
Если есть индекс для (имя, телефон), то запрос может быть решен без необходимости искать соответствующие значения в таблице - есть индекс покрытия .
Кроме того, предположим, что в таблице есть большой двоичный объект, содержащий изображение пользователя, загруженное резюме и электронную таблицу ... использование SELECT * перенесет всю эту информацию обратно в буферы СУБД (вытесняя другую полезную информацию из кеша). Затем все это будет отправлено клиенту, используя время в сети и память на клиенте для данных, которые являются избыточными.
Это также может вызвать функциональные проблемы, если клиент получает данные в виде перечислимого массива (например, PHP mysql_fetch_array ($ x, MYSQL_NUM)). Может быть, когда код был написан, «телефон» был третьим столбцом, возвращаемым SELECT *, но затем кто-то приходит и решает добавить адрес электронной почты в таблицу, помещенную перед «телефоном». Требуемое поле теперь перемещено в 4-й столбец.
источник
В любом случае есть причины. Я часто использую SELECT * в PostgreSQL, потому что есть много вещей, которые вы можете делать с помощью SELECT * в PostgreSQL, чего нельзя сделать с явным списком столбцов, особенно в хранимых процедурах. Точно так же в Informix команда SELECT * над унаследованным деревом таблиц может давать неровные строки, в то время как явный список столбцов не может, потому что также возвращаются дополнительные столбцы в дочерних таблицах.
Основная причина, по которой я делаю это в PostgreSQL, заключается в том, что он обеспечивает получение правильно сформированного типа, специфичного для таблицы. Это позволяет мне брать результаты и использовать их в качестве типа таблицы в PostgreSQL. Это также позволяет использовать в запросе гораздо больше параметров, чем при использовании жесткого списка столбцов.
С другой стороны, жесткий список столбцов дает вам возможность проверить на уровне приложения, что схемы db не изменились определенным образом, и это может быть полезно. (Я провожу такие проверки на другом уровне.)
Что касается производительности, я обычно использую представления и хранимые процедуры, возвращающие типы (а затем список столбцов внутри хранимой процедуры). Это дает мне контроль над возвращаемыми типами.
Но имейте в виду, что я использую SELECT * обычно для уровня абстракции, а не для базовых таблиц.
источник
Ссылка взята из этой статьи:
Без SELECT *: когда вы используете «SELECT *» в это время, вы выбираете больше столбцов из базы данных, и некоторые из этих столбцов могут не использоваться вашим приложением. Это приведет к дополнительным затратам и нагрузке на систему базы данных, и больше данных будет перемещаться по сети.
С помощью SELECT *: если у вас есть особые требования и создана динамическая среда, при добавлении или удалении столбца автоматически обрабатывается кодом приложения. В этом особом случае вам не нужно изменять код приложения и базы данных, и это автоматически повлияет на производственную среду. В этом случае вы можете использовать «ВЫБРАТЬ *».
источник
Просто чтобы добавить нюанс к обсуждению, которого я здесь не вижу: с точки зрения ввода-вывода, если вы используете базу данных с хранилищем, ориентированным на столбцы, вы можете делать НАМНОГО меньше операций ввода-вывода, если вы запрашиваете только определенные колонны. По мере перехода на твердотельные накопители преимущества могут быть немного меньше по сравнению с хранилищем, ориентированным на строки, но есть а) чтение только блоков, содержащих столбцы, которые вам нужны, б) сжатие, которое обычно значительно уменьшает размер данных на диске и, следовательно, объем данных, прочитанных с диска.
Если вы не знакомы с хранилищем, ориентированным на столбцы, одна реализация Postgres исходит из Citus Data, другая - Greenplum, третья - Paraccel, третья (грубо говоря) - Amazon Redshift. Для MySQL существует Infobright, почти не существующий InfiniDB. Другие коммерческие предложения включают Vertica от HP, Sybase IQ, Teradata ...
источник
равный
источник