varias - ventajas de usar vistas en sql
¿Por qué usar ''*'' para construir una vista es malo? (14)
¿Por qué usar ''*'' para construir una vista es malo?
Supongamos que tiene una unión compleja y todos los campos se pueden usar en alguna parte.
Entonces solo tienes que elegir los campos necesarios.
SELECT field1, field2 FROM aview WHERE ...
La vista "a vista" 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 la única razón por la que 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
É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 objetivo. La vista comenzó a devolver resultados totalmente incorrectos hasta que se redistribuyó.
Totalmente incorrecto: sin filas.
Esto fue en Sql Server 2000.
Supongo que esto se debe a los valores de syscolumns que capturó la vista, aunque utilicé *.
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 las tablas subyacentes cambian, otro problema que no se ha cubierto es la optimización. Una consulta que extrae todas las columnas de una tabla tiende a no ser tan eficiente como una consulta que solo extrae las columnas que realmente necesita. Por supuesto, hay momentos en los que necesita cada columna y es un importante PIA tener que hacer referencia a todos, especialmente en una gran tabla, pero si solo necesita un subconjunto, por qué empantanar su consulta con más columnas de las que necesita.
Creo que depende del idioma que estés usando. Prefiero usar select * cuando el lenguaje o el controlador DB devuelven 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 nombre en lugar de como un índice en una matriz.
El uso de SELECT *
dentro de la vista no implica una gran sobrecarga de rendimiento si las columnas no se utilizan fuera de la vista: el optimizador las optimizará; SELECT * FROM TheView
puede perder ancho de banda, al igual que cada vez que extraes más columnas a través de una conexión de red.
De hecho, he encontrado que las vistas que unen casi todas las columnas de una serie de tablas enormes en mi datawarehouse no han presentado ningún problema de rendimiento, incluso si se solicitan relativamente pocas columnas desde fuera de la vista. El optimizador maneja bien y es capaz de llevar los criterios de filtro externo a la vista muy bien.
Sin embargo, por todas las razones expuestas anteriormente, muy rara vez uso SELECT *
.
Tengo algunos procesos de negocios donde se construyen varios CTE uno encima del otro, construyendo columnas derivadas de columnas derivadas de columnas derivadas (que, con un poco de suerte, se refactorizarán una vez que la empresa racionalice y simplifique estos cálculos), y en ese caso , Necesito todas las columnas para pasar cada vez, y uso SELECT *
- pero SELECT *
no se usa en la capa base, solo entre el primer CTE y el último.
En general, es una mala idea usar *. Algunos motores de certificación de código marcan esto como una advertencia y le aconsejan que se refiera explícitamente solo a 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, sin importar qué, utilizando el ejemplo que proporcionó, para esta vista (a vista) siempre necesite todas las columnas en estas tablas. En el futuro, cuando se agregue una columna, no necesitarás modificar la vista. Esto puede ser bueno o malo dependiendo del caso con el que estés tratando.
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 al crear una lista de usuarios en su sitio, por ejemplo, por lo que un select * sería improductivo.
Otra razón por la cual " *
" es arriesgado, no solo en vistas sino en consultas, es que las columnas pueden cambiar de nombre o cambiar de posición en las tablas subyacentes. El uso de un comodín significa que su vista se adapta fácilmente a dichos cambios sin necesidad de cambiarlos. Pero si su aplicación hace referencia a columnas por posición en el conjunto de resultados, o si usa un lenguaje dinámico que devuelve conjuntos de resultados codificados por nombre de columna, puede experimentar problemas que son difíciles de depurar.
Evito usar el comodín en todo momento. De esta forma, si una columna cambia de nombre, aparece un error en la vista o en la 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 lo compensa.
Usar ''*'' para cualquier producción es malo. Es ideal para consultas puntuales, pero en el código de producción siempre debe ser lo más explícito posible.
Para las vistas en particular, si las tablas subyacentes tienen columnas añadidas o eliminadas, la vista se equivocará o se romperá hasta que se vuelva a compilar.
Nadie más parece haberlo mencionado, pero dentro de SQL Server también puede configurar su vista con el atributo schemabinding .
Esto evita modificaciones a cualquiera de las tablas base (incluida su eliminación) que afectarían la definición de la vista.
Esto puede ser útil para algunas situaciones. Me doy cuenta de que no he respondido exactamente su pregunta, pero pensé que la destacaría de todos modos.
Todas estas otras respuestas tienen buenos puntos, pero en el servidor SQL al menos también tienen algunos puntos equivocados. 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 conoce la columna "nueva" cuando se agrega. Dependiendo de lo que quieras, 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 (que aprenderá sobre los cambios en la tabla). Esta incoherencia para mí es una razón más para no usar select * en vistas.
Una consulta SQL es básicamente una unidad funcional diseñada por un programador para su uso en algún contexto. Para la estabilidad a largo plazo y la compatibilidad (posiblemente por alguien que no sea usted), todo en una unidad funcional debe estar ahí 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 asimilarlo bastante bien antes de tener la confianza de poder meterme con él. Lo que significa que necesitaría entender por qué se llaman todas las columnas. (Esto es aún más cierto si intenta 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 pudiera relacionar con algún propósito , Estaría bastante seguro de que no entendía lo que hacía, y por qué, y cuáles serían las consecuencias de cambiarlo.
Y si tiene combinaciones 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 recursos de base de datos y de red.
Si eres lo suficientemente ingenuo como para usar vistas que llaman a otras vistas, usar select * puede hacer que tengan peores desempeños (esta técnica es mala para el rendimiento en sí misma, llamar a varias columnas que no necesitas lo empeora).
No creo que haya mucho en el software que sea "simplemente malo", pero hay muchas cosas que se usan de forma incorrecta :-)
El ejemplo que das es una razón por la que * quizás no te dé lo que esperas, y creo que hay otros. Por ejemplo, si cambian las tablas subyacentes, es posible que 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 las columnas explícitamente, había más posibilidades de que alguien detectara el problema al hacer el cambio del esquema.
Por otro lado, es posible que desee que su vista acepte alegremente todos los cambios en las tablas subyacentes, en cuyo caso un * sería exactamente lo que desea.
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 última observación no es válida para todos los tipos. Estoy en deuda con user12861 y Jonny Leeds por señalar esto, y siento que han tardado más de 6 años en editar mi respuesta.
La situación en SQL Server es incluso peor de lo que implica la respuesta de @ user12861: si usa SELECT *
en varias tablas, agregar columnas a una tabla referenciada al principio de la consulta hará que su vista devuelva los valores de las nuevas columnas en el disfraz de las viejas columnas. Vea el ejemplo a continuación:
-- 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