2010-07-05 28 views
103

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

La sobrecarga de red puede estar presente si selecciono * sin necesidad.

embargo, en una operación de selección, ¿el motor de base de datos tire siempre tupla atómica desde el disco, o tiene Tire solamente aquellas columnas solicitadas en la operación de selección?

Si siempre tira de una tupla entonces I/O de arriba es el mismo.

Al mismo tiempo, podría haber un consumo de memoria para despojar a las columnas solicitadas de la tupla, si se tira de una tupla.

Así que si ese es el caso, seleccione someColumn tendrá más sobrecarga de memoria que la de seleccionar *

+0

¿Hay un RDBMS específico que usted está preguntando acerca de? Es posible que la forma en que se ejecutan o procesen las consultas 'SELECT' sea diferente de la base de datos a la base de datos. –

+10

Como nota aparte, en PostgreSQL, si dices 'CREATE VIEW foo_view AS SELECT * FROM foo;', luego agregas columnas a la tabla foo más adelante, esas columnas no se mostrarán automáticamente en foo_view como se esperaba. En otras palabras, el '*' en este contexto solo se expande una vez (en el tiempo de creación de la vista), no por SELECCIONAR. Debido a las complicaciones que surgen de ALTER TABLE, diría que (en la práctica) '*' se considera dañino. –

+0

@JoeyAdams: no solo PostgresQL, este es también el comportamiento de Oracle. – APC

Respuesta

20

Siempre tira de una tupla (excepto en los casos en que la tabla se ha segmentado verticalmente, dividida en columnas), por lo tanto, para responder a la pregunta, no importa desde el punto de vista del rendimiento. Sin embargo, por muchas otras razones, (a continuación) siempre debe seleccionar específicamente aquellas columnas que desee, por su nombre.

Siempre tira de una tupla, porque (en cada vendedores RDBMS estoy familiarizado con la estructura de almacenamiento subyacente en el disco para todo (incluyendo datos de la tabla) se basa en definida E/S Páginas (en SQL Servidor para, por ejemplo, cada página es de 8 kilobytes. Y cada E/S de lectura o escritura 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 siempre debe estar en una y solo una página. No puede abarcar varias páginas de datos (excepto para elementos especiales como blobs, donde los datos de blobs reales se almacenan en fragmentos de páginas separados, y la tabla real) r a continuación, la columna 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 de datos de la tabla misma (que contiene el puntero a los datos reales del 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 sub-consulta después de una cláusula Exists o Not Exists predicado, como en:

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

EDIT: Para abordar comentario @ Mike Sherer, sí es cierto, tanto a nivel técnico, la un poco de definición para su caso especial, y estéticamente. En primer lugar, incluso cuando el conjunto de columnas solicitadas sea un subconjunto de las almacenadas en algún índice, el procesador de consultas debe obtener cada columna almacenada en ese índice, no solo las solicitadas, por las mismas razones: TODAS las E/S deben ser hecho en páginas, y los datos de índice se almacenan en IO Pages al igual que los datos de la tabla. Por lo tanto, si define "tupla" para una página de índice como el conjunto de columnas almacenadas en el índice, la instrucción sigue siendo verdadera.
y la afirmación es cierta estéticamente porque el punto es que obtiene datos basados ​​en lo que está almacenado en la página de E/S, no en lo que usted solicita, y esto es verdadero si está accediendo a la página de E/S de la tabla base o una página de E/S de índice.

Por otras razones para no usar Select *, ver Why is SELECT * considered harmful?:

+0

" Siempre tira de una tupla "¿estás seguro? Hmm Bien, estaba en lo cierto. si ese es el caso, 'select *' tendrá menos sobrecarga de memoria que 'select column' pero la misma sobrecarga de E/S así que si dejamos la sobrecarga de red.' select * 'si hay menos sobrecarga que' select column' –

+8

Esto NO es cierto. Un ejemplo en mi cabeza es cuando solo quieres el valor de una columna indexada en MySQL (por ejemplo, solo para verificar la existencia de filas), y estás usando el motor de almacenamiento MyISAM, tomará los datos desde el archivo MYI, que podría estar en la memoria, ¡y ni siquiera ir al disco! –

+0

Ya, si el conjunto solicitado de tuplas está en la memoria, no habrá E/S, pero ese es un caso especial. Entonces, ¿qué es el verano? Selecciono algunos Colum indexados n entonces toda la tupla no se lee? de lo contrario, se lee la tupla completa? –

18

Debe siempre sólo select las columnas que en realidad se necesita. Nunca es menos eficiente seleccionar menos en lugar de más, y también tiene menos efectos secundarios inesperados, como acceder a las columnas de resultados en el lado del cliente por índice, y luego hacer que esos índices se vuelvan incorrectos agregando una nueva columna a la tabla.

[Editar]: Significa el acceso. Cerebro estúpido aún despertando.

+2

+1 para un caso límite que creo que no muchos pensarán a primera vista: índices en el lado del cliente y columnas añadidas/cambiadas. –

+0

Sí, pero ¿es el uso de índices numéricos para las columnas tan comunes? Siempre he accedido a datos de columna usando claves de cadena o nombres de propiedad si uso ORM. –

+10

vio 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ó tan pronto como alguien más cambió la mesa. Qué diversión tuvimos –

6

Esto hace que inmediatamente me pienso en una mesa que estaba usando, que contenía una columna de tipo blob; por lo general, contenía una imagen JPEG, unos pocos Mb s de tamaño.

No hace falta decir que no SELECT esa columna a menos que yo realmente lo necesite. Tener esa información flotando, especialmente cuando seleccioné varias filas, fue solo una molestia.

Sin embargo, tengo que admitir que de otro modo por lo general de consulta para todas las columnas de una tabla.

+20

Las columnas LOB son siempre mi ejemplo favorito de los peligros de SELECT *. Así que estaba por 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 dicha columna? – APC

+0

@APC - Esto es cierto, pero es una confesión; Sé que debería saber mejor: '(¿Puedes perdonarme si no uso '*' - De hecho, enumero las columnas? –

+1

@APC, me gustaría poder votar más tu comentario. Piensa en tu pobre compañero de trabajo que solo quiere para agregar una columna sin causar un gran colapso del rendimiento! Piense en lo enojados que estarán cuando descubran después de unas horas que su aspecto inocente selecciona *. –

97

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

  • ya que no se está dando a su la base de datos da alguna pista sobre lo que quiere, primero deberá verificar la definición de la tabla para determinar las columnas en esa tabla. Esa búsqueda costará algo de tiempo, no mucho en una sola consulta, pero se suma a lo largo del tiempo

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

  • si comienza a confiar en ciertos aspectos de los datos, por ejemplo el orden de las columnas devueltas, puede obtener una desagradable sorpresa una vez que la tabla se reorganiza y se agregan nuevas columnas (o se eliminan 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 (contiene todas las columnas necesarias). Con un SELECT *, está 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ía mucho menor en comparación con la consulta SELECT *.....

Sí, se necesita un poco más a escribir inicialmente (herramientas como SQL Prompt para SQL Server incluso le ayudan allí) - pero esto es realmente un caso en el que hay una regla sin excepción alguna: ni se te ocurra utilizar SELECT * en tu código de producción. SIEMPRE.

+0

Solo me preocupa la memoria y la sobrecarga de E/S. Ya he mencionado que 'select *' tendrá más sobrecarga de red. según su segundo punto. querías decir operación selectiva, no hagas tuplas atómicas. más bien, solo extrae las columnas solicitadas de los discos. , por lo que habrá una sobrecarga de memoria en 'seleccionar columna' para verificar qué datos de la celda extraer. hasta donde yo sé Los datos siempre se almacenan en el disco como tuplas. no estoy seguro de cómo seleccionar lo tira. entonces 'select *' no requerirá una verificación a través de la estructura de datos de la tabla –

+12

mientras que está de acuerdo con usted en la práctica, sin duda es correcto en todos los casos al obtener datos de columna de la tabla, como se aborda en esta pregunta), énfasis en NUNCA sin embargo, me lleva a señalar que estas reglas no son generales para TODAS las consultas Sql ... específicamente, es uso en una subconsulta después de un predicado EXISTS, (como en 'Donde Existe (Seleccione * De ... ') el uso de' Seleccionar * 'ciertamente no es un problema, y ​​en algunos círculos se considera una mejor práctica. –

+1

@Charles Bretana: sí, el' IF EXISTS (SELECT * ... 'es un caso especial, ya que allí, no se recuperaron datos realmente, pero es solo un cheque de existencia, el SELECCIONAR * no es un problema allí ... –

6

Durante una selección de SQL, el DB siempre se referirá a los metadatos de la tabla, independientemente de si es SELECCIONAR * para SELECCIONAR 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 una tabla existente como mínimo. 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 DB se almacenan en caché en el sistema, pero aún es el procesamiento lo que debe hacerse.

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. De nuevo, esto se ejecuta en contra de metadatos en caché, pero siempre está hecho.

La única vez que no se realiza este proceso es cuando el DB está utilizando una consulta precompilada, o ha guardado en caché una consulta previa. 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 de "SELECT * FROM TABLE WHERE key =?" y el "1" está vinculado a la llamada.

Las bases de datos se basan en gran medida en el almacenamiento en caché de la página 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 en muchos DB). Entonces su costo primario de E/S en el back-end es el inicio de sesión y las descargas de página.

Sin embargo, si todavía está golpeando el disco para su base de datos, una optimización principal realizada por muchos sistemas es confiar en los datos en í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 "SELECT ID, el nombre del Cliente donde id = 1", es muy probable que DB se tire estos datos del índice, más que de las mesas.

¿Por qué? Es probable que use el índice de todos modos para satisfacer la consulta (frente a una exploración de tabla), y aunque "nombre" no se use 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 golpear las páginas de la tabla. Al utilizar el índice, se obtiene un menor tráfico de disco, ya que tiene una mayor densidad de filas en el índice que en la tabla en general.

Esta es una explicación ondulada a mano 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, SELECCIONAR * es útil para las consultas dinámicas que debe 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 da un mejor control en su código contra cambios de esquema, etc.

+0

Will, he votado negativamente tu respuesta, solo porque usas NOT NULL junto con la PRIMARY KEY. ¿Hay alguna buena razón para que escribas de esta manera? – Learner

+0

@Learner Esa no es una razón válida para rechazar ... – Clint

4

Creo que no hay una respuesta exacta para su pregunta, porque tiene ponderando el rendimiento y la facilidad de mantener sus aplicaciones. Select column es más performático de select *, pero si está desarrollando un sistema de objetos orientados, entonces le gustará usar object.properties y puede necesitar propiedades en cualquier parte de las aplicaciones, entonces necesitará escribir más métodos para obtener propiedades en situaciones especiales si no use select * y rellene todas las propiedades. Sus aplicaciones deben tener un buen rendimiento usando 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 necesite rendimiento.

7

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

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

3

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

Siempre debe usar el atributo SELECT, atribuir .... NO SELECT *

Es principalmente para problemas de rendimiento.

SELECCIONE nombre FROM usuarios WHERE name = 'John';

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

SELECT telephone FROM users WHERE name='John'; 

Si hay un índice en (nombre, teléfono) a continuación, la consulta se puede resolver sin tener que buscar los valores relevantes de la mesa - hay un cubriendo índice.

Además, supongamos que la tabla tiene un BLOB que contiene una imagen del usuario, y un CV cargado, y una hoja de cálculo ... utilizando SELECT * devolverá toda esta información a los búferes DBMS (forzando otra información útil desde el caché). Luego 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 un conjunto enumerado (como el mysql_fetch_array de PHP ($ x, MYSQL_NUM)). Tal vez cuando se escribió el código "teléfono", SELECT * devolvió la tercera columna, 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 desplazó a la 4ª columna.

2

Hay razones para hacer las cosas de cualquier manera. Utilizo mucho SELECT * en PostgreSQL porque hay muchas cosas que puede hacer con SELECT * en PostgreSQL que no puede hacer con una lista explícita de columnas, particularmente cuando se trata de procedimientos almacenados. De forma similar, en Informix, SELECCIONAR * sobre un árbol de tablas heredado puede proporcionarle filas irregulares, mientras que una lista de columnas explícita no puede hacerlo porque también se devuelven columnas adicionales en 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 proporciona una verificación a nivel de aplicación de que los esquemas de db no han cambiado de ciertas maneras y esto puede ser útil. (Hago tales comprobaciones 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 * por lo general contra una capa de abstracción en lugar de tablas base.

2

Reference taken from this article:

Sin SELECT *: Cuando se utiliza”SELECT *” en ese momento va a seleccionar más columnas de la base de datos y algunas de esta columna no puede ser utilizado por la aplicación. Esto creará un costo adicional y una carga en el sistema de base de datos y más viajes de datos a través de la red.

con SELECT *: Si usted tiene requisitos especiales y ha creado entorno dinámico al añadir o eliminar columna de manejar automáticamente por código de la aplicación. En este caso especial, no es necesario cambiar el código de la aplicación y la base de datos, y esto afectará automáticamente al entorno de producción. En este caso, puede usar "SELECT *".

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 column-oriented storage puede hacer MUCHO menos E/S si solo consulta ciertas columnas A medida que nos movemos a SSD, los beneficios pueden ser un poco más pequeños que los de almacenamiento orientado a filas, pero a) solo lee los bloques que contienen columnas que le interesan b) la compresión, que generalmente reduce en gran medida el tamaño de los datos en el disco y, por lo tanto, 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 de Paraccel, otra (de manera general) es Amazon Redshift. Para MySQL está Infobright, el InfiniDB ahora casi extinto. Otras ofertas comerciales incluyen Vertica de HP, Sybase IQ, Teradata ...

-1
select * from table1 INTERSECT select * from table2 

igual

select distinct t1 from table1 where Exists (select t2 from table2 where table1.t1 = t2) 
+0

¿Podría formatear su código resaltándolo y presionando Ctrl + K? – WhatsThePoint

Cuestiones relacionadas