seleccionar * vs seleccionar columna

124

Si solo necesito 2/3 columnas y hago una consulta en SELECT *lugar de proporcionar esas columnas en la consulta de selección, ¿hay alguna degradación del rendimiento con respecto a más / menos E / S o memoria?

La sobrecarga de la red podría estar presente si selecciono * sin necesidad.

Pero en una operación de selección, ¿el motor de la base de datos siempre extrae tuplas atómicas del disco, o extrae solo las columnas solicitadas en la operación de selección?

Si siempre extrae una tupla, la sobrecarga de E / S es la misma.

Al mismo tiempo, puede haber un consumo de memoria para eliminar las columnas solicitadas de la tupla, si extrae una tupla.

Entonces, si ese es el caso, seleccione someColumn tendrá más sobrecarga de memoria que la de select *

Neel Basu
fuente
¿Hay un RDBMS específico sobre el que está preguntando? Es posible que la forma en que SELECTse ejecutan / procesen las consultas sea diferente de una base de datos a otra.
Lèse majesté
10
Como comentario aparte, en PostgreSQL, si dice CREATE VIEW foo_view AS SELECT * FROM foo;, luego agregue columnas a la tabla foo más adelante, esas columnas no aparecerán automáticamente en foo_view como se esperaba. En otras palabras, *en este contexto solo se expande una vez (en el momento de la creación de la vista), no según SELECT. Debido a las complicaciones derivadas de ALTER TABLE, diría que (en la práctica) *se considera perjudicial.
Joey Adams
@JoeyAdams: no solo PostgresQL, también es el comportamiento de Oracle.
APC
1
@OMG Ponies: No estaba al tanto de una publicación similar. Sin embargo, estos no son realmente similares. @ Lèse majesté: estoy hablando de RDBMS genérico. no sobre ningún proveedor específico @ Joey Adams: Hmm Sé que * no es seguro. solo quiero discutir los problemas de rendimiento con respecto.
Neel Basu
3
posible duplicado de ¿Por qué SELECT * se considera perjudicial?
Aaron Bertrand

Respuestas:

31

Siempre saca una tupla (excepto en los casos en que la tabla ha sido segmentada verticalmente, dividida en columnas), por lo tanto, para responder a la pregunta que hizo, no importa desde una perspectiva de rendimiento. Sin embargo, por muchas otras razones, (debajo) siempre debe seleccionar específicamente las columnas que desee, por nombre.

Siempre extrae una tupla porque (en todos los RDBMS de los proveedores con los que estoy familiarizado), la estructura de almacenamiento en disco subyacente para todo (incluidos los datos de la tabla) se basa en páginas de E / S definidas (en SQL Server, por ejemplo, cada página está 8 kilobytes). Y cada lectura o escritura de E / S es por página. Es decir, cada escritura o lectura es una página completa de datos.

Debido a esta restricción estructural subyacente, una consecuencia es que cada fila de datos en una base de datos debe estar siempre en una sola página. No puede abarcar varias páginas de datos (excepto para cosas especiales como blobs, donde los datos de blob reales se almacenan en fragmentos de página separados, y la columna de fila de la tabla real solo obtiene un puntero ...). Pero estas excepciones son solo eso, excepciones, y generalmente no se aplican excepto en casos especiales (para tipos especiales de datos, o ciertas optimizaciones para circunstancias especiales)
Incluso en estos casos especiales, generalmente, la fila real de datos de la tabla en sí (que contiene el puntero a los datos reales para el Blob, o lo que sea), debe almacenarse en una sola página IO ...

EXCEPCIÓN. El único lugar donde Select *está bien, es en la subconsulta después de una cláusula Existso Not Existspredicado, como en:

   Select colA, colB
   From table1 t1
   Where Exists (Select * From Table2
                 Where column = t1.colA)

EDITAR: Para abordar el comentario de @Mike Sherer, Sí, es cierto, tanto técnicamente, con un poco de definición para su caso especial, y estéticamente. Primero, incluso cuando el conjunto de columnas solicitadas es un subconjunto de las almacenadas en algún índice, el procesador de consultas debe buscar todas las columnas almacenadas en ese índice, no solo las solicitadas, por las mismas razones: TODAS las E / S deben realizarse en páginas, y los datos de índice se almacenan en páginas IO al igual que los datos de la tabla. Entonces, si define "tupla" para una página de índice como el conjunto de columnas almacenadas en el índice, la declaración sigue siendo cierta.
y la afirmación es verdadera desde el punto de vista estético porque el punto es que obtiene datos basados ​​en lo que está almacenado en la página de E / S, no en lo que solicita, y esto es cierto si está accediendo a la página de E / S de la tabla base o a un índice Página de E / S.

Para otras razones para no usar Select *, vea ¿Por qué se SELECT *considera dañino? :

Charles Bretana
fuente
"Siempre tira una tupla" ¿estás seguro? Hmm Ok, así que tenía razón. si ese es el caso select *, tendrá menos sobrecarga de memoria que la select columnmisma sobrecarga de E / S. entonces si dejamos la sobrecarga de la red. select *si menos gastos generales que el deselect column
Neel Basu
10
Esto no es verdad. Un ejemplo en la parte superior de mi cabeza es cuando solo desea el valor de una columna indexada en MySQL (por ejemplo, solo para verificar la existencia de filas), y está utilizando el motor de almacenamiento MyISAM, tomará los datos del ¡Archivo MYI, que podría estar en la memoria, y ni siquiera ir al disco!
Mike Sherov
Sí, si el conjunto de tuplas solicitado está en la memoria, no habrá E / S, pero ese es un caso especial. Entonces, ¿cuál es el verano? Si selecciono alguna columna indexada, ¿no se lee toda la tupla? de lo contrario se lee toda la tupla?
Neel Basu
No estoy exactamente seguro de cómo MySql realiza el almacenamiento en caché, pero en SQL Server y en Oracle, incluso cuando los datos están en la memoria caché, todavía accede a ellos usando la misma estructura de página que cuando accedes desde el disco. lo que significa que requeriría una E / S de memoria por página de datos ... exactamente lo mismo que requeriría del disco. (excepto que las E / S de memoria son mucho más rápidas que las E / S de disco, por supuesto). De hecho, ese es un objetivo del diseño de almacenamiento en caché, para que el proceso de acceso sea totalmente independiente de la ubicación de los datos.
Charles Bretana
2
¿Puedes explicar más el "por muchas otras razones"? Porque eso no me quedó claro. Si el rendimiento no importa, ¿por qué preocuparse por solicitar nombres de columna?
Dennis
111

Hay varias razones por las que nunca (nunca) debes usar SELECT *en el código de producción:

  • Como no le está dando a su base de datos ninguna pista sobre lo que desea, primero deberá verificar la definición de la tabla para determinar las columnas de esa tabla. Esa búsqueda costará algo de tiempo, no mucho en una sola consulta, pero se acumula con el tiempo

  • si solo necesita 2/3 de las columnas, está seleccionando 1/3 demasiados datos que deben recuperarse del disco y enviarse a través de la red

  • Si comienza a confiar en ciertos aspectos de los datos, por ejemplo, el orden de las columnas devueltas, podría obtener una desagradable sorpresa una vez que la tabla se reorganice y se agreguen nuevas columnas (o se eliminen las existentes)

  • en SQL Server (no estoy seguro acerca de otras bases de datos), si necesita un subconjunto de columnas, siempre existe la posibilidad de que un índice no agrupado cubra esa solicitud (contenga todas las columnas necesarias). Con un SELECT *, estás renunciando a esa posibilidad desde el primer momento. En este caso particular, los datos se recuperarían de las páginas de índice (si contienen todas las columnas necesarias) y, por lo tanto, la E / S de disco y la sobrecarga de memoria serían mucho menores en comparación con hacer una SELECT *....consulta.

Sí, inicialmente se necesita un poco más de escritura (herramientas como SQL Prompt para SQL Server incluso lo ayudarán allí), pero este es realmente un caso en el que hay una regla sin excepción: nunca use SELECT * en su código de producción. NUNCA.

marc_s
fuente
13
Si bien está de acuerdo con usted en la práctica, sin duda tiene razón en todos los casos cuando obtiene datos de columna de la tabla, ya que esta pregunta aborda), pero su énfasis en NUNCA me lleva a señalar que esta regla no es general para TODAS las consultas SQL. específicamente, su uso en una subconsulta después de un predicado EXISTE, (como en Where Exists (Select * From ...) el uso de Select *ciertamente no es un problema, y ​​en algunos círculos se considera una mejor práctica.
Charles Bretana
3
@Charles Bretana: sí, IF EXISTS(SELECT *...es un caso especial, ya que allí no se recuperan datos, pero es solo una verificación de existencia, el SELECT * no es un problema allí ...
marc_s 05 de
1
¿Qué pasa si estoy desarrollando una API que hace posible recuperar datos de una de mis tablas? Como no sabría en qué datos está interesado el usuario, ¿supongo que SELECT * sería aceptable?
Simon Bengtsson
1
@SimonBengtsson: Todavía argumentaría en contra de esto, ¿y si tiene algunos datos "administrativos" en columnas específicas en su tabla que no desea exponer al cliente? Yo siempre especificar explícitamente una lista de columnas a buscar
marc_s
1
Es verdad. ¿Qué pasa cuando se consulta una vista que se configuró específicamente para usarse con la API?
Simon Bengtsson
21

Usted debe siempre solamente selectlas columnas que en realidad se necesita. Nunca es menos eficiente seleccionar menos en lugar de más, y también se topa con menos efectos secundarios inesperados, como acceder a las columnas de resultados en el lado del cliente por índice, luego hacer que esos índices se vuelvan incorrectos al agregar una nueva columna a la tabla.

[editar]: significaba acceder. Estúpido cerebro aún despertando.

Donnie
fuente
3
+1 para un caso extremo que creo que no muchos pensarán a primera vista: índices en el lado del cliente y columnas agregadas / modificadas.
Tomas Aschan
1
Sí, pero ¿es común el uso de índices numéricos para las columnas? Siempre he accedido a datos de columna usando claves de cadena o nombres de propiedad si uso ORM.
Lèse majesté
11
vi esto hace mucho tiempo, el programador junior seleccionó * de una tabla e hizo suposiciones sobre el orden de las columnas; todo su código se rompió en cuanto alguien más cambió la mesa. Que divertido tuvimos.
Paul McKenzie
77
Probablemente sea una mala idea usar el orden de las columnas en general solo por el bien de la legibilidad del código, doblemente malo de usar SELECT *con él.
Lèse majesté
2
Wow, acceder a las columnas por índice en el código del cliente parece una idea fenomenalmente mala. Por lo demás, basándose en el orden en el que aparecen las columnas en un conjunto de resultados de ninguna manera se siente muy sucio a mí.
Matt Peterson el
7

A menos que esté almacenando grandes blobs, el rendimiento no es una preocupación. La gran razón para no usar SELECT * es que si usa filas devueltas como tuplas, las columnas vuelven en el orden que especifique el esquema, y ​​si eso cambia, tendrá que arreglar todo su código.

Por otro lado, si usa acceso de estilo diccionario, no importa en qué orden vuelvan las columnas porque siempre está accediendo a ellas por nombre.

gxti
fuente
6

Esto inmediatamente me hace pensar en una tabla que estaba usando que contenía una columna de tipo blob; generalmente contenía una imagen JPEG, de unos pocos Mbs de tamaño.

No hace falta decir que no hice SELECTesa columna a menos que realmente la necesitara. Tener esos datos flotando, especialmente cuando seleccioné varias filas, fue una molestia.

Sin embargo, admitiré que, de lo contrario, suelo consultar todas las columnas de una tabla.

Richard JP Le Guen
fuente
20
Las columnas LOB son siempre mi ejemplo favorito de los peligros de SELECT *. Estaba a punto de votarte hasta que leí el tercer párrafo. Tsk, tsk. ¿Qué sucede si algún otro desarrollador agrega un BLOB a una tabla que actualmente no tiene esa columna?
APC
1
@APC, desearía poder votar más tu comentario. ¡Piense en su pobre compañero de trabajo que solo quiere agregar una columna sin causar una gran crisis de rendimiento! Piensa en lo enojados que estarán cuando descubran después de unas horas tu selección inocente *.
Mike Sherov el
1
@ user256007, sí, incluso sin BLOB ... BLOB solo ilustra el ejemplo extremo. Verifique mi respuesta a Charles, ¡hay momentos en que seleccionar columnas específicas puede permitirle tomar los datos de la memoria sin siquiera ir al disco!
Mike Sherov
1
@ Richard, creo que son excelentes para cuando la optimización del rendimiento de la base de datos no es su principal preocupación, que es el 99% del tiempo. Al igual que con la mayoría de los frameworks, tienden a generalizar las cosas para permitir un desarrollo más rápido y sacrificar el rendimiento puro. Como dijo Knuth: "La optimización prematura es la raíz de todo mal". Cuando llegue al punto en el que deba preocuparse por el rendimiento de las columnas de selección frente a select *, (pregunte en Twitter acerca de RoR), puede preocuparse y optimizarlo. Si el marco no es lo suficientemente robusto como para soportar eso, entonces diría que está usando el marco incorrecto.
Mike Sherov
1
@ user256007 - la regla general es "no use SELECT * '. La respuesta de marc_s tiene todo el razonamiento de por qué este es el caso.
APC
6

Durante una selección de SQL, la base de datos siempre se referirá a los metadatos de la tabla, independientemente de si es SELECT * para SELECT a, b, c ... ¿Por qué? Porque ahí es donde está la información sobre la estructura y el diseño de la tabla en el sistema.

Tiene que leer esta información por dos razones. Uno, simplemente compilar la declaración. Debe asegurarse de especificar al menos una tabla existente. Además, la estructura de la base de datos puede haber cambiado desde la última vez que se ejecutó una declaración.

Ahora, obviamente, los metadatos de la base de datos se almacenan en caché en el sistema, pero aún es necesario procesarlo.

A continuación, los metadatos se utilizan para generar el plan de consulta. Esto sucede cada vez que se compila una declaración también. Nuevamente, esto se ejecuta contra metadatos almacenados en caché, pero siempre se hace.

El único momento en que este procesamiento no se realiza es cuando la base de datos está utilizando una consulta precompilada o ha almacenado en caché una consulta anterior. Este es el argumento para usar parámetros de enlace en lugar de SQL literal. "SELECT * FROM TABLE WHERE key = 1" es una consulta diferente a "SELECT * FROM TABLE WHERE key =?" y el "1" está vinculado a la llamada.

Las bases de datos dependen en gran medida del almacenamiento en caché de páginas para su trabajo. Muchos DB modernos son lo suficientemente pequeños como para caber completamente en la memoria (o, tal vez debería decir, la memoria moderna es lo suficientemente grande como para caber muchos DB). Luego, su costo de E / S principal en el back-end es el inicio de sesión y el vaciado de páginas.

Sin embargo, si todavía está presionando el disco para su base de datos, una optimización principal realizada por muchos sistemas es confiar en los datos en los índices, en lugar de las tablas en sí.

Si usted tiene:

CREATE TABLE customer (
    id INTEGER NOT NULL PRIMARY KEY,
    name VARCHAR(150) NOT NULL,
    city VARCHAR(30),
    state VARCHAR(30),
    zip VARCHAR(10));

CREATE INDEX k1_customer ON customer(id, name);

Entonces, si hace "SELECT id, name FROM customer WHERE id = 1", es muy probable que DB extraiga estos datos del índice, en lugar de las tablas.

¿Por qué? Es probable que use el índice de todos modos para satisfacer la consulta (frente a un escaneo de tabla), y aunque 'nombre' no se usa en la cláusula where, ese índice seguirá siendo la mejor opción para la consulta.

Ahora la base de datos tiene todos los datos que necesita para satisfacer la consulta, por lo que no hay razón para ir a las páginas de la tabla. El uso del índice da como resultado menos tráfico de disco ya que tiene una mayor densidad de filas en el índice en comparación con la tabla en general.

Esta es una explicación manual de una técnica de optimización específica utilizada por algunas bases de datos. Muchos tienen varias técnicas de optimización y ajuste.

Al final, SELECT * es útil para consultas dinámicas que tiene que escribir a mano, nunca lo usaría para "código real". La identificación de columnas individuales le da al DB más información que puede usar para optimizar la consulta, y le brinda un mejor control en su código contra cambios de esquema, etc.

Will Hartung
fuente
Will, he rechazado tu respuesta, solo porque usas NOT NULL junto con la CLAVE PRIMARIA. ¿Hay una buena razón para que escribas de esta manera?
Estudiante
4

Creo que no hay una respuesta exacta para su pregunta, porque tiene un rendimiento reflexivo y la facilidad de mantener sus aplicaciones. Select columnes más funcional select *, pero si está desarrollando un sistema de objetos orientado, le gustará usarlo object.propertiesy puede necesitar propiedades en cualquier parte de las aplicaciones, entonces necesitará escribir más métodos para obtener propiedades en situaciones especiales si no lo hace use select *y complete todas las propiedades. Sus aplicaciones deben tener un buen rendimiento utilizando select *y, en algunos casos, necesitará utilizar la columna de selección para mejorar el rendimiento. Entonces tendrá lo mejor de dos mundos, facilidad para escribir y mantener aplicaciones y rendimiento cuando lo necesite.

M.Torres
fuente
4

La respuesta aceptada aquí es incorrecta. Me encontré con esto cuando otra pregunta se cerró como un duplicado de esto (mientras todavía estaba escribiendo mi respuesta, grr, por lo tanto, el siguiente SQL hace referencia a la otra pregunta).

Siempre debe usar SELECT atributo, atributo ... NO SELECCIONAR *

Es principalmente por problemas de rendimiento.

SELECCIONE el nombre DE usuarios WHERE name = 'John';

No es un ejemplo muy útil. Considere en su lugar:

SELECT telephone FROM users WHERE name='John';

Si hay un índice en (nombre, teléfono), entonces la consulta se puede resolver sin tener que buscar los valores relevantes de la tabla; hay un índice de cobertura .

Además, suponga que la tabla tiene un BLOB que contiene una imagen del usuario, y un CV cargado, y una hoja de cálculo ... usando SELECT * extraerá toda esta información en los buffers DBMS (forzando otra información útil de la caché). Luego, todo se enviará al cliente utilizando el tiempo de actividad en la red y la memoria en el cliente para datos que son redundantes.

También puede causar problemas funcionales si el cliente recupera los datos como una matriz enumerada (como mysql_fetch_array de PHP ($ x, MYSQL_NUM)). Tal vez cuando el código fue escrito 'teléfono' fue la tercera columna devuelta por SELECT *, pero luego aparece alguien y decide agregar una dirección de correo electrónico a la mesa, colocada antes de 'teléfono'. El campo deseado ahora se desplaza a la cuarta columna.

symcbean
fuente
2

Hay razones para hacer las cosas de cualquier manera. Uso mucho SELECT * en PostgreSQL porque hay muchas cosas que puedes hacer con SELECT * en PostgreSQL que no puedes hacer con una lista explícita de columnas, particularmente cuando estás en procedimientos almacenados. De manera similar, en Informix, SELECT * sobre un árbol de tablas heredado puede proporcionar filas irregulares, mientras que una lista de columnas explícita no puede porque también se devuelven columnas adicionales en las tablas secundarias.

La razón principal por la que hago esto en PostgreSQL es que garantiza que obtenga un tipo bien formado específico para una tabla. Esto me permite tomar los resultados y usarlos como el tipo de tabla en PostgreSQL. Esto también permite muchas más opciones en la consulta que una lista de columnas rígidas.

Por otro lado, una lista de columnas rígidas le brinda una verificación a nivel de aplicación de que los esquemas db no han cambiado de cierta manera y esto puede ser útil. (Hago tales controles en otro nivel).

En cuanto al rendimiento, tiendo a usar VIEW y procedimientos almacenados que devuelven tipos (y luego una lista de columnas dentro del procedimiento almacenado). Esto me da control sobre qué tipos se devuelven.

Pero tenga en cuenta que estoy usando SELECT * generalmente contra una capa de abstracción en lugar de tablas base.

Chris Travers
fuente
2

Referencia tomada de este artículo:

Sin SELECT *: cuando utiliza "SELECT *" en ese momento, está seleccionando más columnas de la base de datos y es posible que su aplicación no utilice parte de esta columna. Esto creará un costo y carga adicionales en el sistema de base de datos y más viajes de datos a través de la red.

Con SELECT *: si tiene requisitos especiales y creó un entorno dinámico cuando la columna de agregar o eliminar se maneja automáticamente por código de aplicación. En este caso especial, no necesita cambiar el código de la aplicación y la base de datos y esto afectará automáticamente el entorno de producción. En este caso puede usar "SELECCIONAR *".

Anvesh
fuente
0

Solo para agregar un matiz a la discusión que no veo aquí: en términos de E / S, si está utilizando una base de datos con almacenamiento orientado a columnas puede hacer MUCHO menos E / S si solo consulta ciertas columnas A medida que avanzamos hacia los SSD, los beneficios pueden ser un poco más pequeños en comparación con el almacenamiento orientado a filas, pero hay a) solo leer los bloques que contienen columnas que le interesan b) compresión, que generalmente reduce en gran medida el tamaño de los datos en el disco y, por lo tanto, el volumen de datos leídos del disco.

Si no está familiarizado con el almacenamiento orientado a columnas, una implementación para Postgres proviene de Citus Data, otra es Greenplum, otra Paraccel, otra (en términos generales) es Amazon Redshift. Para MySQL está Infobright, el InfiniDB ahora casi desaparecido. Otras ofertas comerciales incluyen Vertica de HP, Sybase IQ, Teradata ...

Carnot Antonio Romero
fuente
-1
select * from table1 INTERSECT  select * from table2

igual

select distinct t1 from table1 where Exists (select t2 from table2 where table1.t1 = t2 )
mehdi sadeghi
fuente
¿Podría formatear su código resaltándolo y presionando Ctrl + K?
WhatsThePoint