Pregunta

¿Por qué es malo usar '*' para construir una vista?

Suponga que tiene una combinación compleja y que todos los campos se pueden usar en alguna parte.

Entonces solo tiene que elegir los campos necesarios.

SELECT field1, field2 FROM aview WHERE ...

La vista " aview " podría ser SELECT table1. *, table2. * ... FROM table1 INNER JOIN table2 ...

Tenemos un problema si 2 campos tienen el mismo nombre en table1 y table2.

¿Es esta solo la razón por la cual usar '*' en una vista es malo?

Con '*', puede usar la vista en un contexto diferente porque la información está allí.

¿Qué me estoy perdiendo?

Saludos

¿Fue útil?

Solución

No creo que haya mucho en el software que sea '' simplemente malo '', pero hay muchas cosas que se usan de manera incorrecta :-)

El ejemplo que da es una razón por la cual * podría no darle lo que espera, y creo que hay otros. Por ejemplo, si las tablas subyacentes cambian, quizás se agreguen o eliminen columnas, una vista que use * continuará siendo válida, pero podría romper cualquier aplicación que la use. Si su vista había nombrado explícitamente las columnas, entonces había más posibilidades de que alguien descubriera el problema al hacer el cambio de esquema.

Por otro lado, en realidad es posible que quiera que su vista sea alegre aceptar todos los cambios en las tablas subyacentes, en cuyo caso un * haría sé justo lo que quieres.

Actualización: No sé si el OP tenía en mente un proveedor de base de datos específico, pero ahora está claro que mi último comentario no es válido para todos los tipos. Estoy en deuda con el usuario 12861 y Jonny Leeds por señalar esto, y lamento que me haya llevado más de 6 años editar mi respuesta.

Otros consejos

Aunque muchos de los comentarios aquí son muy buenos y hacen referencia a un problema común del uso de comodines en las consultas, como causar errores o resultados diferentes si cambian las tablas subyacentes, otro problema que no se ha cubierto es la optimización. Una consulta que extrae cada columna de una tabla tiende a no ser tan eficiente como una consulta que extrae solo las columnas que realmente necesita. De acuerdo, hay momentos en los que necesita cada columna y es un PIA importante tener que hacer referencia a todas ellas, especialmente en una tabla grande, pero si solo necesita un subconjunto, ¿por qué atascar su consulta con más columnas de las que necesita?

Otra razón por la cual " * " Es arriesgado, no solo en las vistas sino en las consultas, es que las columnas pueden cambiar el nombre o la posición en las tablas subyacentes. El uso de un comodín significa que su vista acomoda tales cambios fácilmente sin necesidad de cambiarlos. Pero si su aplicación hace referencia a columnas por posición en el conjunto de resultados, o si utiliza un lenguaje dinámico que devuelve conjuntos de resultados con el nombre de la columna, podría experimentar problemas que son difíciles de depurar.

Evito usar el comodín en todo momento. De esa manera, si una columna cambia de nombre, aparece un error en la vista o consulta de inmediato, y sé dónde solucionarlo. Si una columna cambia de posición en la tabla subyacente, especificar el orden de las columnas en la vista o consulta compensa esto.

Todas estas otras respuestas tienen buenos puntos, pero al menos en el servidor SQL también tienen algunos puntos incorrectos. Prueba esto:

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 no aprende sobre el " nuevo " columna cuando se agrega. Dependiendo de lo que desee, esto podría ser algo bueno o malo, pero de cualquier manera, probablemente no sea bueno depender de ello. Así que evitarlo parece una buena idea.

Para mí, este comportamiento extraño es la razón más convincente para evitar seleccionar * en las vistas.

Los comentarios me han enseñado que MySQL tiene un comportamiento similar y Oracle no (aprenderá sobre los cambios en la tabla). Esta inconsistencia para mí es una razón más para no usar select * en las vistas.

Usar '*' para cualquier producción es malo. Es ideal para consultas únicas, pero en el código de producción siempre debe ser lo más explícito posible.

Para vistas en particular, si las tablas subyacentes tienen columnas agregadas o eliminadas, la vista será incorrecta o rota hasta que se vuelva a compilar.

El uso de SELECT * dentro de la vista no genera una sobrecarga de rendimiento si las columnas no se usan fuera de la vista: el optimizador las optimizará; SELECT * FROM TheView quizás pueda desperdiciar ancho de banda, como cada vez que extrae más columnas a través de una conexión de red.

De hecho, he encontrado que las vistas que enlazan casi todas las columnas de varias tablas enormes en mi datawarehouse no han introducido ningún problema de rendimiento, incluso a través de que se solicitan relativamente pocas columnas desde fuera de la vista. El optimizador lo maneja bien y puede empujar los criterios de filtro externo hacia abajo en la vista muy bien.

Sin embargo, por todas las razones mencionadas anteriormente, rara vez uso SELECT * .

Tengo algunos procesos comerciales en los que se construyen varios CTE uno encima del otro, construyendo efectivamente columnas derivadas de columnas derivadas de columnas derivadas (que con suerte algún día se refactorizará a medida que la empresa racionalice y simplifique estos cálculos), y en ese caso, necesito que caigan todas las columnas cada vez, y uso SELECT * , pero SELECT * no se usa en la capa base, solo entre primer CTE y el último.

La situación en SQL Server es en realidad incluso peor que la respuesta de @ user12861 implica: si usa SELECT * en varias tablas, agregar columnas a una tabla referenciada al principio de la consulta en realidad hará que su ver para devolver los valores de las nuevas columnas bajo la apariencia de las columnas antiguas. Vea el siguiente ejemplo:

-- 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

Es porque no siempre necesita todas las variables, y también para asegurarse de que está pensando en lo que necesita específicamente.

No tiene sentido sacar todas las contraseñas hash de la base de datos cuando se crea una lista de usuarios en su sitio, por ejemplo, por lo que un select * sería improductivo.

Érase una vez, creé una vista contra una tabla en otra base de datos (en el mismo servidor) con

Select * From dbname..tablename

Entonces, un día, se agregó una columna a la tabla de destino. La vista comenzó a devolver resultados totalmente incorrectos hasta que se volvió a implementar.


Totalmente incorrecto: sin filas.

Esto estaba en SQL Server 2000.

Especulo que esto se debe a los valores de syscolumns que la vista había capturado, a pesar de que usé *.

Una consulta SQL es básicamente una unidad funcional diseñada por un programador para su uso en algún contexto. Para la estabilidad y la capacidad de soporte a largo plazo (posiblemente por alguien que no sea usted), todo en una unidad funcional debe estar allí para un propósito, y debe ser razonablemente evidente (o documentado) por qué está allí, especialmente cada elemento de datos.

Si tuviera que venir dentro de dos años con la necesidad o el deseo de alterar su consulta, esperaría asimilarla a fondo antes de confiar en que podría enredarla. Lo que significa que necesitaría entender por qué se llaman todas las columnas. (Esto es aún más evidente si está intentando reutilizar la consulta en más de un contexto. Lo cual es problemático en general, por razones similares.) Si tuviera que ver columnas en el resultado que no podría relacionar con algún propósito , Estaría bastante seguro de que no entendí lo que hizo, y por qué, y cuáles serían las consecuencias de cambiarlo.

Generalmente es una mala idea usar *. Algunos motores de certificación de código marcan esto como una advertencia y le recomiendan que consulte explícitamente solo las columnas necesarias. El uso de * puede conducir a piojos de rendimiento, ya que es posible que solo necesite algunas columnas y no todas. Pero, por otro lado, hay algunos casos en los que el uso de * es ideal. Imagine que, pase lo que pase, utilizando el ejemplo que proporcionó, para esta vista (vista) siempre necesitaría todas las columnas de estas tablas. En el futuro, cuando se agrega una columna, no necesitará modificar la vista. Esto puede ser bueno o malo dependiendo del caso con el que esté tratando.

Creo que depende del idioma que estés usando. Prefiero usar select * cuando el lenguaje o el controlador de DB devuelve un dict (Python, Perl, etc.) o una matriz asociativa (PHP) de los resultados. Hace que su código sea mucho más fácil de entender si se refiere a las columnas por su nombre en lugar de como un índice en una matriz.

Nadie más parece haberlo mencionado, pero dentro de SQL Server también puede configurar su vista con el atributo de enlace de esquema .

Esto evita modificaciones en cualquiera de las tablas base (incluida su eliminación) que afectarían la definición de la vista.

Esto puede ser útil para usted en algunas situaciones. Me doy cuenta de que no he respondido exactamente a su pregunta, pero pensé en resaltarla de todos modos.

Y si tiene uniones usando select * automáticamente significa que está devolviendo más datos de los que necesita a medida que se repiten los datos en los campos de unión. Esto es un desperdicio de base de datos y recursos de red.

Si eres lo suficientemente ingenuo como para usar vistas que llaman a otras vistas, el uso de select * puede hacer que tengan un rendimiento aún peor (esta es una técnica que es mala para el rendimiento por sí sola, llamar múltiples columnas que no necesitas lo hace mucho peor) ).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top