Выберите * vs select column

Если мне нужны только 2/3 столбца, и я запрашиваю SELECT * вместо предоставления этих столбцов в выбранном запросе, есть ли ухудшение производительности в отношении более/менее ввода-вывода или памяти?

Сетевые служебные данные могут присутствовать, если я выберу * без необходимости.

Но в какой-то операции выбора механизм базы данных всегда вытаскивает атомарный кортеж с диска или вытягивает только те столбцы, которые запрашиваются в операции выбора?

Если он всегда тянет кортеж, тогда накладные расходы ввода-вывода совпадают.

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

Так что, если это произойдет, выберите someColumn, у вас будет больше накладных расходов памяти, чем у select *

Ответ 1

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

Он всегда тянет кортеж, потому что (в каждой СУБД вендора, с которой я знаком) базовая структура хранения на диске для всего (включая данные таблиц) основана на определенных страницах ввода/вывода (например, в SQL Server каждая страница является 8 килобайт). И каждое чтение или запись ввода/вывода осуществляется по странице. То есть каждая запись или чтение является полной страницей данных.

Из-за этого базового структурного ограничения следствием является то, что каждая строка данных в базе данных всегда должна быть на одной и только одной странице. Он не может охватывать несколько страниц данных (за исключением особых вещей, таких как BLOB-объекты, где фактические данные BLOB-объектов хранятся в отдельных фрагментах страниц, а фактический столбец строки таблицы получает только указатель...). Но эти исключения являются только исключениями и обычно не применяются, за исключением особых случаев (для особых типов данных или определенных оптимизаций для особых обстоятельств).
Даже в этих особых случаях, как правило, в самой строке таблицы данных (которая содержит указатель на фактические данные для BLOB-объекта или чего-либо еще), они должны храниться на одной странице ввода-вывода...

ИСКЛЮЧЕНИЕ. Единственное место, где Select * - ОК, находится в подзапросе после предложения предиката Exists или Not Exists, как в:

   Select colA, colB
   From table1 t1
   Where Exists (Select * From Table2
                 Where column = t1.colA)

РЕДАКТИРОВАТЬ: Чтобы ответить на комментарий @Mike Sherer, да, это правда, как технически, с небольшим определением для вашего особого случая, и эстетически. Во-первых, даже когда запрашиваемый набор столбцов является подмножеством столбцов, хранящихся в каком-либо индексе, обработчик запросов должен извлечь все столбцы, хранящиеся в этом индексе, а не только те, которые были запрошены, по тем же причинам - ВСЕ ввод/вывод должны выполняться в страницы, а индексные данные хранятся на страницах ввода-вывода, как данные таблицы. Таким образом, если вы определите "кортеж" для страницы индекса как набор столбцов, хранящихся в индексе, утверждение все равно будет истинным.
и это утверждение эстетически верно, потому что дело в том, что он выбирает данные на основе того, что хранится на странице ввода-вывода, а не на том, что вы запрашиваете, и это верно, обращаетесь ли вы к странице ввода-вывода базовой таблицы или к индексу Страница ввода/вывода.

По другим причинам не использовать Select *, см. Почему SELECT * считается вредным? :

Ответ 2

Есть несколько причин, по которым вы никогда не должны (никогда) использовать SELECT * в производственном коде:

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

  • если вам нужно только 2/3 столбцов, вы выбираете 1/3 слишком много данных, которые нужно извлекать с диска и отправлять по сети.

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

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

Да, сначала требуется немного больше ввода (такие инструменты, как SQL Prompt для SQL Server, даже помогут вам там) - но это действительно один случай, когда существует правило без каких-либо исключений: никогда не используйте SELECT * в своем производственном коде. EVER.

Ответ 3

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

[править]: требуется доступ. Глупый мозг все еще просыпается.

Ответ 4

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

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

Ответ 5

Это сразу заставляет меня задуматься о таблице, которую я использовал, которая содержала столбец типа blob; он обычно содержит изображение в формате JPEG, несколько Mb в размере.

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

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

Ответ 6

Во время выбора SQL БД всегда будет ссылаться на метаданные для таблицы, независимо от того, выбрал ли она SELECT * для SELECT a, b, c... Почему? Безусловно, если информация о структуре и расположении таблицы в системе есть.

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

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

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

Единственный раз, когда эта обработка не выполняется, - это когда БД использует предварительно скомпилированный запрос или кэширует предыдущий запрос. Это аргумент для использования параметров привязки, а не буквального SQL. "SELECT * FROM TABLE WHERE key = 1" - это другой запрос, чем "SELECT * FROM TABLE WHERE key =?" и "1" привязан к вызову.

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

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

Если у вас есть:

CREATE TABLE customer (
    id INTEGER NOT NULL PRIMARY KEY,
    name VARCHAR(150) NOT NULL,
    city VARCHAR(30),
    state VARCHAR(30),
    zip VARCHAR(10));

CREATE INDEX k1_customer ON customer(id, name);

Затем, если вы выполните "SELECT id, имя FROM customer WHERE id = 1", очень вероятно, что вы DB вытащите эти данные из индекса, а не из таблиц.

Почему? Он, скорее всего, будет использовать индекс в любом случае, чтобы удовлетворить запрос (против сканирования таблицы), и даже если "имя" не используется в предложении where, этот индекс по-прежнему будет лучшим вариантом для запроса.

Теперь база данных содержит все данные, необходимые для удовлетворения запроса, поэтому нет причин попадать на страницы таблицы сами. Использование индекса приводит к меньшему объему трафика на диске, поскольку у вас более высокая плотность строк в индексе по сравнению с общей таблицей.

Это ручное волновое объяснение конкретной методики оптимизации, используемой некоторыми базами данных. У многих есть несколько методов оптимизации и настройки.

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

Ответ 7

Я думаю, что нет точного ответа на ваш вопрос, потому что вы размышляете о производительности и возможности поддерживать свои приложения. Select column более совершенен select *, но если вы разрабатываете ориентированную объектную систему, вам понравится использовать object.properties, и вам могут понадобиться свойства в любой части приложений, тогда вам понадобится написать больше методов для получения свойства в особых ситуациях, если вы не используете select * и заполните все свойства. Ваши приложения должны иметь хорошую производительность с помощью select *, и в некоторых случаях вам понадобится использовать столбец выбора для повышения производительности. Тогда у вас будет лучшее из двух миров, возможность писать и поддерживать приложения и производительность, когда вам нужна производительность.

Ответ 8

Принятый ответ здесь неверен. Я столкнулся с этим, когда другой вопрос был закрыт как дубликат этого (пока я все еще писал свой ответ - grr - следовательно, SQL ниже ссылается на другой вопрос).

Вы всегда должны использовать атрибут SELECT, атрибут.... NOT SELECT *

Это прежде всего для проблем с производительностью.

SELECT name FROM users WHERE name= 'John';

Не очень полезный пример. Вместо этого рассмотрим:

SELECT telephone FROM users WHERE name='John';

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

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

Это может также вызвать функциональные проблемы, если клиент извлекает данные в виде перечисляемого массива (например, PHP mysql_fetch_array ($ x, MYSQL_NUM)). Возможно, когда код был написан "телефон", это был третий столбец, который будет возвращен SELECT *, но затем кто-то приходит и решает добавить адрес электронной почты в таблицу, расположенную перед "телефоном". Желаемое поле теперь смещено в 4-й столбец.

Ответ 9

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

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

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

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

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

Ответ 10

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

Без SELECT *: Когда вы используете "SELECT *" в это время, вы выбираете больше столбцов из базы данных, и некоторые из этих столбцов могут не использоваться вашим приложением. Это создаст дополнительную стоимость и нагрузку на систему баз данных и больше путешествий данных по сети.

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

Ответ 11

Просто добавьте нюанс в дискуссию, которую я не вижу здесь: с точки зрения ввода-вывода, если вы используете базу данных с столбцом -ориентированное хранилище, вы можете сделать LOT меньше ввода-вывода, если вы запрашиваете только определенные столбцы. По мере перехода на SSD преимущества могут быть немного меньшими по сравнению с хранилищем, ориентированным на строки, но там: а) только чтение блоков, содержащих столбцы, которые вам небезразличны; b) сжатие, что обычно значительно уменьшает размер данных на диске, объем данных, считываемых с диска.

Если вы не знакомы с хранилищем, ориентированным на столбцы, одна реализация для Postgres поступает из Citus Data, другой - Greenplum, другой Paraccel, другой (свободно говорящий) - Amazon Redshift. Для MySQL там Infobright, теперь уже несуществующий InfiniDB. Другие коммерческие предложения включают Vertica от HP, Sybase IQ, Teradata...

Ответ 12

select * from table1 INTERSECT  select * from table2

равно

select distinct t1 from table1 where Exists (select t2 from table2 where table1.t1 = t2 )