Почему использование '*' для создания представления плохо? - PullRequest
21 голосов
/ 04 ноября 2008

Почему использование '*' для создания плохого представления?

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

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

SELECT field1, field2 FROM aview WHERE ...

Вид "aview" может быть SELECT table1.*, table2.* ... FROM table1 INNER JOIN table2 ...

У нас есть проблема, если 2 поля имеют одинаковые имена в table1 и table2.

Является ли это единственной причиной, по которой использование '*' в представлении плохо?

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

Чего мне не хватает?

Привет

Ответы [ 14 ]

37 голосов
/ 04 ноября 2008

Я не думаю, что в программном обеспечении есть что-то «просто плохое», но есть много вещей, которые неправильно используются плохими способами: -)

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

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

Обновление: Я не знаю, имел ли в виду ОП конкретный поставщик базы данных, но теперь ясно, что мое последнее замечание относится не ко всем типам. Я признателен user12861 и Джонни Лидсу за указание на это, и мне жаль, что мне потребовалось более 6 лет, чтобы отредактировать свой ответ.

19 голосов
/ 04 ноября 2008

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

17 голосов
/ 04 ноября 2008

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

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

13 голосов
/ 04 ноября 2008

Все остальные ответы имеют хорошие моменты, но, по крайней мере, на сервере SQL они также имеют некоторые неправильные моменты. Попробуйте это:

create table temp (i int, j int)
go
create view vtemp as select * from temp
go
insert temp select 1, 1
go
alter table temp add k int
go
insert temp select 1, 1, 1
go
select * from vtemp

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

Для меня это странное поведение - самая веская причина избегать выбора * во взглядах.

Комментарии научили меня, что MySQL имеет похожее поведение, а Oracle - нет (он узнает об изменениях в таблице). Это несоответствие для меня - еще одна причина не использовать select * в представлениях.

11 голосов
/ 04 ноября 2008

Использование '*' для всего, что плохо, - производство. Это отлично подходит для одноразовых запросов, но в рабочем коде вы всегда должны быть максимально явными.

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

4 голосов
/ 16 октября 2015

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

-- create two tables
CREATE TABLE temp1 (ColumnA INT, ColumnB DATE, ColumnC DECIMAL(2,1))
CREATE TABLE temp2 (ColumnX INT, ColumnY DATE, ColumnZ DECIMAL(2,1))
GO


-- populate with dummy data
INSERT INTO temp1 (ColumnA, ColumnB, ColumnC) VALUES (1, '1/1/1900', 0.5)
INSERT INTO temp2 (ColumnX, ColumnY, ColumnZ) VALUES (1, '1/1/1900', 0.5)
GO


-- create a view with a pair of SELECT * statements
CREATE VIEW vwtemp AS 
SELECT *
FROM temp1 INNER JOIN temp2 ON 1=1
GO


-- SELECT showing the columns properly assigned
SELECT * FROM vwTemp 
GO


-- add a few columns to the first table referenced in the SELECT 
ALTER TABLE temp1 ADD ColumnD varchar(1)
ALTER TABLE temp1 ADD ColumnE varchar(1)
ALTER TABLE temp1 ADD ColumnF varchar(1)
GO


-- populate those columns with dummy data
UPDATE temp1 SET ColumnD = 'D', ColumnE = 'E', ColumnF = 'F'
GO


-- notice that the original columns have the wrong data in them now, causing any datatype-specific queries (e.g., arithmetic, dateadd, etc.) to fail
SELECT *
FROM vwtemp
GO

-- clean up
DROP VIEW vwTemp
DROP TABLE temp2
DROP TABLE temp1
4 голосов
/ 04 ноября 2008

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

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

Однако по всем приведенным выше причинам я очень редко использую SELECT *.

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

3 голосов
/ 06 ноября 2008

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

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

3 голосов
/ 04 ноября 2008

Давным-давно я создал представление для таблицы в другой базе данных (на том же сервере) с

Select * From dbname..tablename

Затем однажды в целевую таблицу был добавлен столбец. Представление начало возвращать совершенно неверные результаты, пока не было повторно развернуто.


Совершенно неверно: без строк.

Это было на Sql Server 2000.

Я предполагаю, что это из-за значений syscolumns, которые захватил вид, даже если я использовал *.

3 голосов
/ 04 ноября 2008

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

Нет смысла выводить все хешированные пароли из базы данных, например, при создании списка пользователей на вашем сайте, поэтому выбор * будет непродуктивным.

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