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

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

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

Затем вам нужно выбрать нужные поля.

SELECT field1, field2 FROM aview WHERE ...

Представление "aview" может быть SELECT table1.*, table2.* ... FROM table1 INNER JOIN table2 ...

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

Это только причина, почему использование '*' в представлении плохо?

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

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

Привет

Ответ 1

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

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

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

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

Ответ 2

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

Ответ 3

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

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

Ответ 4

У этих других ответов есть хорошие моменты, но на 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 * в представлениях.

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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

Select * From dbname..tablename

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


Абсолютно неверно: нет строк.

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

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

Ответ 8

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

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

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

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

Ответ 9

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

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

Ответ 10

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

Ответ 11

Я думаю, это зависит от языка, который вы используете. Я предпочитаю использовать select *, когда язык или драйвер DB возвращают dict (Python, Perl и т.д.) Или ассоциативный массив (PHP) результатов. Это делает ваш код намного легче понять, если вы ссылаетесь на столбцы по имени, а не как индекс в массиве.

Ответ 12

Никто, похоже, не упомянул об этом, но в SQL Server вы также можете настроить свое представление с помощью атрибута schemabinding.

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

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

Ответ 13

Ситуация на SQL Server на самом деле даже хуже, чем ответ by @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

Ответ 14

И если у вас есть соединения с использованием select *, автоматически означает, что вы возвращаете больше данных, чем вам нужно, поскольку данные в полях объединения повторяются. Это расточительно для базы данных и сетевых ресурсов.

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