2008-11-04 12 views
19

¿Por qué está usando '*' para crear una vista incorrecta?¿Por qué usar '*' para construir una vista es malo?

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

Luego 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 tabla1 y tabla2.

¿Es esta la única razón por la que utilizar '*' 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

Respuesta

33

no creo que haya mucho en el software que es "simplemente malo", pero hay un montón de cosas que es maltratado de malas maneras :-)

El ejemplo que dan es una razón por la cual podría no dar * eres 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 en realidad quieren el fin de alegremente aceptar todos los cambios en las tablas subyacentes, en cuyo caso sería un * ser justo lo que quieres.

Actualización: No sé si el PO tenía un proveedor de base de datos específica en mente, pero ahora está claro que mi última observación no es cierto 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.

+1

Por favor, compruebe mi otro comentario, en SQL Server todos los cambios no son necesariamente aceptadas. – user12861

+0

Además, el código que utiliza la vista no debe usar *, por lo que puede ser bastante razonable usar * en la vista, y la carga estará en el código que utiliza la vista para asegurarse de que no esté usando *. –

+3

El comentario al final es completamente incorrecto (al menos en el servidor sql) - sucede lo contrario: los cambios en las tablas subyacentes se ignoran silenciosamente. Esto es lo que @ user12861 menciona. En el servidor sql, cualquier vista que use select * deberá descartarse y volverse a crear cuando la tabla de subyacencia cambie, de lo contrario, silenciosamente, no se mostrarán todas las columnas. Esta es una forma bastante mala de falla, ya que es poco probable que se recoja en un entorno de desarrollo en el que se está reconstruyendo su base de datos desde cero con regularidad. También es muy fácil olvidarse de colocar y reconstruir todas las vistas en una tabla cuando agrega una columna –

3

Se debe a que no siempre se necesita cada variable y también para asegurarse de que usted está pensando acerca de lo que necesita específicamente.

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

3

Había una vez, creé una vista en contra de una tabla en otra base de datos (en el mismo servidor) con

Select * From dbname..tablename 

Entonces, un día, se añadió una columna a la tabla targetted. La vista comenzó a devolver resultados totalmente incorrectos hasta que se redistribuyó.


Totalmente incorrecto: sin filas.

Esto estaba en Sql Server 2000.

Supongo que esto se debe a los valores de syscolumns que la vista había capturado, aunque utilicé *.

11

Usar '*' para cualquier cosa 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 agregadas o eliminadas, la vista se equivocará o se romperá hasta que se vuelva a compilar.

15

Otro motivo por el que "*" 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.

+2

Lea mi otra respuesta, los cambios en las tablas subyacentes no siempre se reflejan, al menos en el servidor SQL. – user12861

18

Aunque muchos de los comentarios aquí son muy buenos y hacen referencia a un problema común del uso de comodines en 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.

+0

¡Excelentes puntos! –

+0

Esta es mi razón principal para no usar SELECT *. Las otras razones son principalmente relevantes si haces otras cosas que son peligrosas, como SELECCIONAR * con un JOIN o referenciar columnas por índice en lugar de por nombre. Duh, POR SUPUESTO esas son combinaciones peligrosas. Pero por sí mismo, seleccionar * no es malo. –

+0

Acepto que generalmente no es peligroso. Frecuentemente uso SELECT * cuando realizo verificaciones de datos en un db. Sin embargo, tiendo a evitar el uso de SELECT * cuando escribo el código de producción para evitar enfrentar los problemas ilustrados anteriormente y para continuar aplicando buenos hábitos de programación. –

2

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.

3

El uso de SELECT * dentro de la vista no supone una sobrecarga de rendimiento si las columnas no se utilizan fuera de la vista; el optimizador las optimizará; SELECT * FROM TheView puede desperdiciar 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 gran cantidad de tablas en mi datawarehouse no han presentado ningún problema de rendimiento, incluso a través de pocas columnas solicitadas 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 todos los motivos indicados anteriormente, muy rara vez uso SELECT *.

Tengo algunos procesos comerciales donde se construyen varios CTE uno encima del otro, construyendo columnas derivadas de columnas derivadas de columnas derivadas (que algún día se refactorizarán porque el negocio racionaliza y simplifica 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 el primer CTE y el último.

2

Creo que depende del idioma que utilice. 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.

+1

Si se modifica el orden del campo, la matriz asociativa continúa funcionando. –

13

Todas estas otras respuestas tienen buenos puntos, pero en el servidor SQL al menos también tienen algunos puntos erróneos. 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 se entera de la columna "nuevo" 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.

+1

Mismo comportamiento en MySQL: la nueva columna no se convierte en parte de la vista. Aparentemente, el comodín se convierte en una lista de columnas en el momento en que se crea la vista. Cambiar el nombre de una columna en la tabla base hace que la vista no se pueda usar. –

+3

Oracle no funciona así. La vista se invalidaría con el cambio de tabla y se volvería a compilar en el siguiente acceso con la nueva columna. –

2

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

Esto evita modificaciones en cualquiera de las tablas base (incluso las descarta) 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.

3

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 llegase dentro de dos años con la necesidad o el deseo de alterar su consulta, esperaría asimilarlo bastante 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.

+0

Excelente punto y uno que no había pensado antes en esos términos. – HLGEM

+0

Esto solo muestra que es difícil cambiar la consulta '*' -ed a una consulta con un nombre explícito; no dice nada por qué la consulta '*' -ed es incorrecta. OMI, no hay nada intrínsecamente malo sobre la consulta '*' -ed; solo significa que no necesitas ser demasiado refinado. –

+0

No estoy seguro de qué significa "demasiado detallado" en el contexto de la determinación de dependencia. A menos que haya decidido que las dependencias no son importantes. – dkretz

1

Y si tiene uniones utilizando 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 usted es tan ingenuo como para usar las vistas que llaman a otros puntos de vista, el uso de select * puede que sean aún peores intérpretes (Esta es la técnica que es malo para el rendimiento por sí solo, llamando columnas Mulitple que no necesita hace que sea mucho peor).

2

La situación en SQL Server es 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 hará que su vista devuelva los valores de la nuevas columnas bajo el disfraz de las viejas columnas.Véase 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 
Cuestiones relacionadas