Почему использование '*' для построения представления плохо?
Вопрос
Почему использование '*' для построения представления плохо?
Предположим, у вас есть сложное соединение и все поля могут где-то использоваться.
Затем вам просто нужно выбрать необходимые поля.
SELECT field1, field2 FROM aview WHERE ...
Представление «вид» может быть SELECT table1.*, table2.* ... FROM table1 INNER JOIN table2 ...
У нас проблема, если два поля имеют одинаковое имя в таблицах table1 и table2.
Является ли это единственной причиной того, что использование '*' в представлении плохо?
С помощью '*' вы можете использовать представление в другом контексте, поскольку информация там есть.
Что мне не хватает?
С уважением
Решение
Я не думаю, что в программном обеспечении есть что-то «просто плохое», но есть много вещей, которые используются не по назначению :-)
Пример, который вы приводите, является причиной, по которой * может не дать вам того, что вы ожидаете, и я думаю, что есть и другие.Например, если базовые таблицы изменяются, возможно, добавляются или удаляются столбцы, представление, использующее *, продолжит действовать, но может привести к поломке любых приложений, которые его используют.Если бы в вашем представлении столбцы были названы явно, было бы больше шансов, что кто-то заметит проблему при изменении схемы.
С другой стороны, вы могли бы на самом деле хотеть Ваше мнение, чтобы безумно принять все изменения в базовых таблицах, и в этом случае A * будет именно тем, что вы хотите.
Обновлять: Я не знаю, имел ли в виду ОП конкретного поставщика баз данных, но теперь ясно, что мое последнее замечание справедливо не для всех типов.Я в долгу перед пользователем 12861 и Джонни Лидсом за то, что они указали на это, и извините, что мне потребовалось более 6 лет, чтобы отредактировать свой ответ.
Другие советы
Хотя многие из комментариев здесь очень хороши и ссылаются на одну распространенную проблему использования подстановочных знаков в запросах, например возникновение ошибок или других результатов при изменении базовых таблиц, еще одна проблема, которая не была затронута, — это оптимизация.Запрос, который извлекает каждый столбец таблицы, как правило, не так эффективен, как запрос, который извлекает только те столбцы, которые вам действительно нужны.Конечно, бывают случаи, когда вам нужен каждый столбец, и это серьезная PIA, вынужденная ссылаться на них всех, особенно в большой таблице, но если вам нужно только подмножество, зачем загружать ваш запрос большим количеством столбцов, чем вам нужно.
Еще одна причина, почему»*
" рискованно не только в представлениях, но и в запросах, поскольку столбцы могут изменить имя или изменить положение в базовых таблицах.Использование подстановочного знака означает, что ваше представление легко вносит такие изменения без необходимости его изменения.Но если ваше приложение ссылается на столбцы по положению в наборе результатов или если вы используете динамический язык, который возвращает наборы результатов с ключом по имени столбца, вы можете столкнуться с проблемами, которые трудно отладить.
Я всегда избегаю использования подстановочного знака.Таким образом, если столбец меняет имя, я немедленно получаю ошибку в представлении или запросе и знаю, где ее исправить.Если столбец меняет положение в базовой таблице, это компенсируется указанием порядка столбцов в представлении или запросе.
У всех этих других ответов есть хорошие моменты, но, по крайней мере, на 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 * в представлениях.
Использование '*' для чего-либо производства – это плохо.Это отлично подходит для одноразовых запросов, но в рабочем коде вы всегда должны быть как можно более явными.
В частности, для представлений, если в базовых таблицах добавлены или удалены столбцы, представление будет либо неверным, либо сломанным, пока оно не будет перекомпилировано.
С использованием SELECT *
внутри представления не возникает большого снижения производительности, если столбцы не используются за пределами представления — оптимизатор оптимизирует их; SELECT * FROM TheView
возможно, может привести к потере пропускной способности, как и в любой другой раз, когда вы передаете больше столбцов через сетевое соединение.
Фактически, я обнаружил, что представления, которые связывают почти все столбцы из множества огромных таблиц в моем хранилище данных, вообще не вызывают каких-либо проблем с производительностью, даже несмотря на то, что относительно небольшое количество этих столбцов запрашивается извне представления.Оптимизатор хорошо с этим справляется и может очень хорошо перенести критерии внешнего фильтра в представление.
Однако по всем причинам, указанным выше, я очень редко использую SELECT *
.
У меня есть некоторые бизнес-процессы, в которых несколько CTE строятся друг на друге, эффективно создавая производные столбцы из производных столбцов из производных столбцов (которые, надеюсь, однажды будут реорганизованы по мере того, как бизнес рационализирует и упрощает эти вычисления), и в этом случае , мне нужно, чтобы все столбцы проходили каждый раз, и я использую SELECT *
- но SELECT *
не используется на базовом уровне, только между первым и последним CTE.
Ситуация с 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
Это потому, что вам не всегда нужна каждая переменная, а также для того, чтобы вы думали о том, что именно вам нужно.
Например, нет смысла получать все хешированные пароли из базы данных при создании списка пользователей на вашем сайте, поэтому выбор * будет непродуктивным.
Однажды я создал представление для таблицы в другой базе данных (на том же сервере) с помощью
Select * From dbname..tablename
Затем однажды в целевую таблицу был добавлен столбец.Представление начало возвращать совершенно неправильные результаты, пока оно не было повторно развернуто.
Совершенно неверно:никаких строк.
Это было на Sql Server 2000.
Я предполагаю, что это связано со значениями системных столбцов, которые зафиксировало представление, хотя я использовал *.
SQL-запрос — это, по сути, функциональная единица, разработанная программистом для использования в определенном контексте.Для долгосрочной стабильности и возможности поддержки (возможно, кем-то кроме вас) все в функциональном блоке должно быть предназначено для какой-то цели, и должно быть достаточно очевидно (или задокументировано), почему оно здесь, особенно каждый элемент данных.
Если бы через два года у меня возникла необходимость или желание изменить ваш запрос, я бы ожидал, что вникну в него довольно тщательно, прежде чем буду уверен, что смогу с ним возиться.Это означает, что мне нужно понять, почему вызываются все столбцы.(Это еще более очевидно, если вы пытаетесь повторно использовать запрос более чем в одном контексте.Что в целом проблематично по тем же причинам.) Если бы я увидел в выводе столбцы, которые я не мог бы связать с какой-либо целью, я был бы почти уверен, что не понимаю, что он делает и почему, и каковы будут последствия его изменения.
Обычно использовать *.Некоторые механизмы сертификации кода отмечают это как предупреждение и советуют явно указывать только необходимые столбцы.Использование * может привести к снижению производительности, поскольку вам могут понадобиться только некоторые столбцы, а не все.Но, с другой стороны, в некоторых случаях использование * идеально.Представьте, что несмотря ни на что, на примере, который вы привели, для этого представления (представления) вам всегда будут нужны все столбцы в этих таблицах.В будущем, когда столбец будет добавлен, вам не потребуется изменять представление.Это может быть хорошо или плохо в зависимости от случая, с которым вы имеете дело.
Я думаю, это зависит от языка, который вы используете.Я предпочитаю использовать select *, когда язык или драйвер БД возвращает результат (Python, Perl и т. д.) или ассоциативный массив (PHP).Ваш код становится намного проще для понимания, если вы ссылаетесь на столбцы по имени, а не на индекс в массиве.
Кажется, никто больше об этом не упомянул, но в SQL Server вы также можете настроить свое представление с помощью привязка схем атрибут.
Это предотвращает изменения любых базовых таблиц (в том числе их удаление), которые могут повлиять на определение представления.
Это может быть полезно для вас в некоторых ситуациях.Я понимаю, что не совсем ответил на ваш вопрос, но все же решил его подчеркнуть.
А если у вас есть объединения с использованием select * автоматически, это означает, что вы возвращаете больше данных, чем вам нужно, поскольку данные в полях соединения повторяются.Это приводит к расточительству ресурсов базы данных и сети.
Если вы достаточно наивны, чтобы использовать представления, которые вызывают другие представления, использование select * может сделать их еще хуже (этот метод сам по себе плох для производительности, вызов нескольких столбцов, которые вам не нужны, делает его намного хуже).