En SQL Server 2012 (o cualquier versión desde 2005), el uso SELECT *...
es solo un posible problema de rendimiento en la instrucción SELECT de nivel superior de una consulta.
Por lo tanto, NO es un problema en Vistas (*), en subconsultas, en cláusulas EXIST, en CTE, ni en SELECT COUNT(*)..
etc., etc. Tenga en cuenta que esto probablemente también sea cierto para Oracle y DB2, y tal vez PostGres (no estoy seguro) , pero es muy probable que todavía sea un problema en muchos casos para MySql.
Para entender por qué (y por qué todavía puede ser un problema en un SELECT de nivel superior), es útil comprender por qué alguna vez fue un problema, ya que el uso SELECT *..
significa " devolver TODAS las columnas ". En general, esto devolverá muchos más datos de los que realmente desea, lo que obviamente puede dar lugar a muchas más E / S, tanto de disco como de red.
Lo que es menos obvio es que esto también restringe los índices y planes de consulta que puede usar un optimizador de SQL, porque sabe que finalmente debe devolver todas las columnas de datos. Si puede saber de antemano que solo desea ciertas columnas, entonces a menudo puede usar planes de consulta más eficientes aprovechando los índices que solo tienen esas columnas. Afortunadamente, hay una manera de saber esto con anticipación, que es para que usted especifique explícitamente las columnas que desea en la lista de columnas. Pero cuando usas "*", estás renunciando a esto a favor de "solo dame todo, descubriré lo que necesito".
Sí, también hay un uso adicional de CPU y memoria para procesar cada columna, pero casi siempre es menor en comparación con estas dos cosas: el disco adicional significativo y el ancho de banda de red requerido para las columnas que no necesita, y tener que usar menos plan de consulta optimizado porque tiene que incluir cada columna.
Entonces, ¿qué cambió? Básicamente, los optimizadores de SQL incorporaron con éxito una característica llamada "Optimización de columna" que solo significa que ahora pueden averiguar en las subconsultas de nivel inferior si alguna vez va a utilizar una columna en los niveles superiores de la consulta.
El resultado de esto es que ya no importa si usa 'SELECCIONAR * ...' en los niveles inferior / interno de una consulta. En cambio, lo que realmente importa es lo que está en la lista de columnas del SELECT de nivel superior. A menos que lo use SELECT *..
en la parte superior, una vez más, debe suponer que desea TODAS las columnas y, por lo tanto, no puede emplear las optimizaciones de columna de manera efectiva.
(* - tenga en cuenta que hay un problema de enlace menor y diferente en las Vistas *
donde no siempre registran el cambio en las listas de columnas cuando se usa "*". Hay otras formas de abordar esto y no afecta el rendimiento).
Se permite su uso físico y problemático
select * from table
, sin embargo, es una mala idea. ¿Por qué?En primer lugar, encontrará que está devolviendo columnas que no necesita (recursos pesados).
En segundo lugar, tomará más tiempo en una tabla grande que nombrar las columnas porque cuando selecciona *, en realidad está seleccionando los nombres de columna de la base de datos y diciendo "dame los datos que están asociados con columnas que tienen nombres en esta otra lista ". Si bien esto es rápido para el programador, imagine hacer esta búsqueda en la computadora de un banco que podría tener literalmente cientos de miles de búsquedas en un minuto.
En tercer lugar, hacer esto realmente hace que sea más difícil para el desarrollador. ¿Con qué frecuencia necesita cambiar de SSMS a VS para obtener todos los nombres de columna?
En cuarto lugar, es una señal de programación perezosa y no creo que ningún desarrollador quiera esa reputación.
fuente
Puede ser un problema si coloca el
Select * ...
código en un programa, porque, como se señaló anteriormente, la base de datos puede cambiar con el tiempo y tener más columnas de las que esperaba cuando escribió la consulta. Esto puede conducir a la falla del programa (el mejor de los casos) o el programa podría seguir su camino feliz y corromper algunos datos porque está buscando valores de campo que no se escribieron para manejar. En resumen, el código de producción SIEMPRE debe especificar los campos que se devolverán enSELECT
.Dicho esto, tengo menos problemas cuando
Select *
es parte de unaEXISTS
cláusula, ya que todo lo que se devolverá al programa es un booleano que indica el éxito o el fracaso de la selección. Otros pueden estar en desacuerdo con esta postura y respeto su opinión al respecto. PUEDE ser un poco menos eficiente codificarSelect *
que codificar 'Seleccionar 1' en unaEXISTS
cláusula, pero no creo que haya ningún peligro de corrupción de datos, de cualquier manera.fuente
Muchas respuestas por qué
select *
está mal, así que lo cubriré cuando sienta que es correcto o al menos correcto.1) En EXISTS, el contenido de la parte SELECT de la consulta se ignora, por lo que incluso puede escribir
SELECT 1/0
y no generará errores.EXISTS
solo verifica que algunos datos regresarían y devuelve un valor booleano basado en eso.2) Esto podría iniciar una tormenta de fuego, pero me gusta usar los
select *
desencadenantes de mi tabla de historial. Porselect *
, evita que la tabla principal obtenga una nueva columna sin agregar la columna a la tabla del historial, ya que genera un error inmediatamente cuando se inserta / actualiza / elimina en la tabla principal. Esto ha impedido en numerosas ocasiones que los desarrolladores agreguen columnas y olviden agregarlo a la tabla del historial.fuente
SELECT 1
porque obviamente notifica a los futuros mantenedores de código de su intención. No es un requisito , pero si lo veo... WHERE EXISTS (SELECT 1 ...)
, obviamente se anuncia como una prueba de verdad.SELECT 1
según el mito de que el rendimiento sería mejor queSELECT *
. Sin embargo, ambas opciones son perfectamente aceptables. No hay diferencia en el rendimiento debido a la forma en que el optimizador maneja EXISTS. Tampoco hay diferencia en la legibilidad debido a la palabra "EXISTE" que anuncia claramente una prueba de verdad.Column8
a la tabla principal olvidando la tabla de historial. El desarrollador escribe un montón de código relacionado con la Columna 8. Luego agregaColumn9
a la tabla principal; esta vez recordando agregar también a la historia. Más tarde, cuando realiza las pruebas, se da cuenta de que olvidó agregarColumn9
al historial (gracias a su técnica de detección de errores) y lo agrega rápidamente. Ahora el disparador parece funcionar, pero los datos en las columnas 8 y 9 están mezclados en el historial. : S