выберите * против выбора столбца - PullRequest
115 голосов
/ 05 июля 2010

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

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

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

Если он всегда тянет кортеж, то затраты на ввод / вывод одинаковы.

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

Так что, если это так, у selectColumn будет больше памяти, чем у select *

Ответы [ 12 ]

105 голосов
/ 05 июля 2010

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

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

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

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

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

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

25 голосов
/ 05 июля 2010

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

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

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

EXCEPTION.Единственное место, где Select * в порядке, находится в подзапросе после предложения предиката Exists или Not Exists, например:

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

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

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

20 голосов
/ 05 июля 2010

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

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

7 голосов
/ 05 июля 2010

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

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

6 голосов
/ 05 июля 2010

Во время выбора 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», очень вероятно, чтоваша БД будет получать эти данные из индекса, а не из таблиц.

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

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

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

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

6 голосов
/ 05 июля 2010

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

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

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

4 голосов
/ 06 марта 2013

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

Вы должны всегдаиспользуйте атрибут SELECT, атрибут .... НЕ ВЫБРАН *

Это в первую очередь из-за проблем с производительностью.

ВЫБРАТЬ имя из пользователей, ГДЕ имя = 'Джон';

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

SELECT telephone FROM users WHERE name='John';

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

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

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

4 голосов
/ 05 июля 2010

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

2 голосов
/ 07 февраля 2016

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

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

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

2 голосов
/ 07 марта 2013

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...