¿Por qué SELECT * es mucho más rápido que seleccionar todas las columnas (en un orden de columnas diferente) por nombre?

12

En una tabla con las columnas a, b, c, d, e, f, g, h, i, j, k obtengo:

select * from misty order by a limit 25;
Time: 302.068 ms

Y:

select c,b,j,k,a,d,i,g,f,e,h from misty order by a limit 25;
Time: 1258.451 ms

¿Hay alguna manera de hacer la selección por columna tan rápido?

Actualizar:

No hay índice en una tabla, uno recién creado

Aquí está el EXPLICAR ANÁLISIS, no parece demasiado útil:

explain analyze select * from misty order by a limit 25;

Limit  (cost=43994.40..43994.46 rows=25 width=190) (actual time=404.958..404.971 rows=25 loops=1)
->  Sort  (cost=43994.40..45731.11 rows=694686 width=190) (actual time=404.957..404.963 rows=25 loops=1)
     Sort Key: a
     Sort Method: top-N heapsort  Memory: 28kB
     ->  Seq Scan on misty  (cost=0.00..24390.86 rows=694686 width=190) (actual time=0.013..170.945 rows=694686 loops=1)
Total runtime: 405.019 ms
(6 rows)

Y:

explain analyze select c,b,j,k,a,d,i,g,f,e,h from misty order by a limit 25;

Limit  (cost=43994.40..43994.46 rows=25 width=190) (actual time=1371.735..1371.745 rows=25 loops=1)
->  Sort  (cost=43994.40..45731.11 rows=694686 width=190) (actual time=1371.733..1371.736 rows=25 loops=1)
     Sort Key: a
     Sort Method: top-N heapsort  Memory: 28kB
     ->  Seq Scan on misty  (cost=0.00..24390.86 rows=694686 width=190) (actual time=0.015..516.355 rows=694686 loops=1)
Total runtime: 1371.797 ms
(6 rows)
Evgeny
fuente
¿Está la columna indexada? ¿Puedes publicar explicar analizar?
user_0
1
Debe tener cuidado al hacer dos selecciones seguidas y comparar los tiempos. Los datos en caché en la segunda consulta pueden explicar la diferencia en los tiempos.
Walter Mitty
1
También veo diferencias, aunque no tan pronunciadas. Mi tabla tiene filas = 514431 ancho = 215, y obtengo aproximadamente 1.5 segundos para el select *caso y aproximadamente 2.2 segundos para la selección con columnas enumeradas en un orden diferente .
Colin 't Hart
Si enumero todas las columnas en el mismo orden que se define en la tabla, obtengo aproximadamente las mismas veces que si lo hiciera select *.
Colin 't Hart
2
El título es engañoso. La pregunta realmente es por qué la duración de una clasificación depende del orden de las columnas de salida.
Daniel Vérité

Respuestas:

12

Esto fue publicado en la lista de correo pgsql-hackers y traté de responder brevemente allí. Parece que si la lista de destino (columnas especificadas) coincide exactamente con el descriptor de tupla de la relación, es decir, tanto en número de columnas como en orden, entonces el escaneo subyacente puede devolver una tupla que es directamente consumible por el nodo Ordenar adjunto. Por otro lado, si la lista de destino no coincide (ya sea en orden o el número de columnas especificadas), el escaneo devuelve una forma de las tuplas que requiere el paso de preparación de datos de Sort para realizar un trabajo adicional (convertir de un formato de tupla interno a el formato directamente consumible por el código de clasificación).

Por cierto, '*' se transforma internamente en una lista que (intuitivamente) coincide con el descriptor de tupla de la relación.

EDITAR: Si observa los últimos tiempos reales de la Exploración de Seq de EXPLAIN ANALYZE, puede ver que es más que los anteriores. Eso sucedió porque la exploración realizó un paso adicional de proyección (es decir, convertir la tupla de montón en un formato de valores internos [], nulos []). Y como eso sucedió, el nodo de clasificación superior tuvo que hacer un trabajo adicional en su inicialización de datos, el de convertirlo nuevamente al formato de tupla que el paso de clasificación real comprende. Eso es evidente por el costo de inicio de Sort. Eso no sucede en el primer caso. Es decir, tanto el escaneo devuelve la tupla como está y el paso de inicialización del tipo simplemente lo copia.

amitlan
fuente
@ Colin'tHart, espero que tenga sentido.
amitlan
Si. Hubiera esperado que fuera posible omitir ese paso o hacerlo más corto usando un poco de "combinación de puntero", pero esa es una discusión para los hackers pgsql.
Colin 't Hart
Puede haber algunas mejoras en el horizonte con la reciente reactivación del trabajo de ordenación de columnas lógicas.
amitlan
¡Ya estaba pensando en eso y esperaba que sí!
Colin 't Hart
Estimado señor, si solo necesito algunas columnas en lugar de todas, ¿cuál será más rápido? seleccione * o seleccione algunas_de_columnas? Muchas gracias.
sgon00