Tengo una tabla PostgreSQL. select *
es muy lento, mientras que select id
es agradable y rápido. Creo que puede ser que el tamaño de la fila sea muy grande y que lleve un tiempo transportarlo, o puede ser otro factor.
Necesito todos los campos (o casi todos), por lo que seleccionar solo un subconjunto no es una solución rápida. Seleccionar los campos que quiero todavía es lento.
Aquí está mi esquema de tabla menos los nombres:
integer | not null default nextval('core_page_id_seq'::regclass)
character varying(255) | not null
character varying(64) | not null
text | default '{}'::text
character varying(255) |
integer | not null default 0
text | default '{}'::text
text |
timestamp with time zone |
integer |
timestamp with time zone |
integer |
El tamaño del campo de texto puede ser de cualquier tamaño. Pero aún así, no más de unos pocos kilobytes en el peor de los casos.
Preguntas
- ¿Hay algo en esto que grite "loco ineficiente"?
- ¿Hay alguna manera de medir el tamaño de página en la línea de comandos de Postgres para ayudarme a depurar esto?
length(*)
lugar de sololength(field)
? Sé que son caracteres, no bytes, pero solo necesito un valor aproximado.Respuestas:
Q2:
way to measure page size
PostgreSQL proporciona una serie de funciones de tamaño de objeto de base de datos . Empaqué los más interesantes en esta consulta y agregué algunas funciones de acceso a estadísticas en la parte inferior. (El módulo adicional pgstattuple proporciona aún más funciones útiles).
Esto mostrará que los diferentes métodos para medir el "tamaño de una fila" conducen a resultados muy diferentes. Todo depende de lo que quieras medir, exactamente.
Esta consulta requiere Postgres 9.3 o posterior . Para versiones anteriores ver más abajo.
Usar una
VALUES
expresión en unaLATERAL
subconsulta para evitar deletrear cálculos para cada filaReemplace
public.tbl
(dos veces) con el nombre de la tabla opcionalmente calificado por el esquema para obtener una vista compacta de las estadísticas recopiladas sobre el tamaño de sus filas. Puede envolver esto en una función plpgsql para uso repetido, entregar el nombre de la tabla como parámetro y usarEXECUTE
...Resultado:
Para versiones anteriores (Postgres 9.2 o anterior):
Mismo resultado.
Q1:
anything inefficient?
Puede optimizar el orden de las columnas para guardar algunos bytes por fila, actualmente desperdiciados en el relleno de alineación:
Esto ahorra entre 8 y 18 bytes por fila. Lo llamo "columna tetris" . Detalles:
Considere también:
fuente
, unnest(val) / ct
por, (LEAST(unnest(val), unnest(val) * ct)) / (ct - 1 + sign(ct))
y no se lanzará. La justificación es que, cuandoct
sea0
,val
será reemplazado por0
yct
será reemplazado por1
.Es fácil obtener una aproximación del tamaño de una fila, incluidos los contenidos editados de TOAST , al consultar la longitud de la representación de TEXTO de toda la fila:
Esta es una aproximación cercana al número de bytes que se recuperarán del lado del cliente al ejecutar:
... suponiendo que la persona que llama de la consulta solicita resultados en formato de texto, que es lo que hacen la mayoría de los programas (el formato binario es posible, pero no vale la pena en la mayoría de los casos).
Se podría aplicar la misma técnica para ubicar las
N
filas "más grandes en el texto" detablename
:fuente
Hay algunas cosas que podrían estar sucediendo. En general, dudo que la longitud sea el problema proximal. Sospecho que en cambio tienes un problema relacionado con la longitud.
Dices que los campos de texto pueden llegar a unos pocos k. Una fila no puede superar los 8k en el almacenamiento principal, y es probable que sus campos de texto más grandes se TOSTEN o se hayan movido del almacenamiento principal a un almacenamiento extendido en archivos separados. Esto hace que su almacenamiento principal sea más rápido (por lo que seleccionar id en realidad es más rápido porque tiene menos páginas de disco para acceder) pero select * se vuelve más lento porque hay más E / S aleatorias.
Si el tamaño total de las filas sigue siendo muy inferior a 8k, podría intentar alterar la configuración de almacenamiento. Sin embargo, advierto que puede hacer que sucedan cosas malas al insertar un atributo de gran tamaño en el almacenamiento principal, por lo que es mejor no tocar esto si no es necesario y, si lo hace, establezca los límites apropiados a través de las restricciones de verificación. Por lo tanto, el transporte no es lo único probable. Puede estar recopilando muchos, muchos campos que requieren lecturas aleatorias. Un gran número de lecturas aleatorias también puede causar errores de caché, y una gran cantidad de memoria requerida puede requerir que las cosas se materialicen en el disco y un gran número de filas anchas, si hay una unión (y hay una si TOAST está involucrado) puede requerir costosos patrones de unión, etc.
Lo primero que consideraría hacer es seleccionar menos filas y ver si eso ayuda. Si eso funciona, podría intentar agregar más RAM al servidor también, pero comenzaría y vería dónde comienza a disminuir el rendimiento debido a los cambios en el plan y las fallas de caché primero.
fuente
Uso de las funciones de tamaño de objeto de base de datos mencionadas anteriormente:
fuente