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

StackOverflow https://stackoverflow.com/questions/262450

  •  06-07-2019
  •  | 
  •  

Вопрос

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

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

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

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 * может сделать их еще хуже (этот метод сам по себе плох для производительности, вызов нескольких столбцов, которые вам не нужны, делает его намного хуже).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top