Tuple Layout13 temas

Tuple Layout

En la guía anterior vimos que la base de datos lee por páginas que agrupan varias filas. Esta guía baja un nivel: tuple layout es cómo se representa una fila (tupla) en bytes dentro de la página — no es solo sus valores uno tras otro, sino una estructura interna de tres secciones, como se aprecia en la imagen.


Estructura de una tupla

Cada fila dentro de una página se organiza en tres secciones consecutivas:

Header (Tuple Header)

Metadatos de la fila. Ocupa entre 4 y 24 bytes según el motor. Incluye:

  • MVCC info: información de control de concurrencia (transaction ID, visibility flags). PostgreSQL usa 4 campos: t_xmin, t_xmax, t_cid, t_ctid (~23 bytes).
  • Longitud de la tupla: tamaño total en bytes (útil para recorrer páginas).
  • Puntero al slot: relación con el slot array de la página.
Regla:

El header es el costo fijo de cada fila. Una tabla con filas muy chicas (ej: una columna booleana) paga más overhead proporcional que una tabla con filas grandes.

Null Bitmap

Mapa de bits que registra qué atributos contienen NULL: 1 = NULL (sin espacio en Data), 0 = valor presente. Cada columna nullable consume 1 bit, no un byte entero.

Para una tabla de 10 columnas nullable, el bitmap completo entra en 2 bytes. Sin el bitmap, cada NULL ocuparía 1–8 bytes enteros según el tipo.

Consejo:

Si una tabla tiene muchas columnas con NULL frecuente, el null bitmap ahorra espacio significativo. Por eso conviene evitar valores default como '' o 0 para representar ausencia de dato — el NULL explícito es más eficiente.

Data (Tuple Data)

Espacio físico donde se almacenan los valores de los atributos en orden. Se divide en dos categorías:

Atributos de longitud fija:

Ocupan siempre la misma cantidad de bytes. El motor conoce su offset exacto dentro del área de datos sin necesidad de leer metadatos adicionales.

Tipo Tamaño
INTEGER 4 bytes
BIGINT 8 bytes
FLOAT / DOUBLE 4 / 8 bytes
BOOLEAN 1 byte
DATE 4 bytes
TIMESTAMP 8 bytes

Atributos de longitud variable:

Ocupan espacio variable según el valor. El motor no sabe de antemano dónde termina uno y empieza el siguiente, así que necesita algún mecanismo para localizarlos.

Estrategias comunes:

  • Longitud inline: se almacena un prefijo de 2–4 bytes con el tamaño del valor antes del valor mismo.

Cuidado:

Los atributos variables con longitud inline agregan 2–4 bytes de overhead por valor. En tablas con muchos VARCHAR cortos, este overhead puede ser mayor al dato mismo.


Ejemplo concreto

Una tabla con esta definición:

CREATE TABLE usuarios (
    id        INTEGER,      -- fijo, 4 bytes
    nombre    VARCHAR(50),  -- variable
    activo    BOOLEAN,      -- fijo, 1 byte
    email     VARCHAR(100)  -- variable
);

Para una fila con valores: id=5, nombre='Ana', activo=true, email=NULL, la tupla en página se vería así:

Puntos clave:

  • email=NULL → el bit correspondiente en el null bitmap está en 1, y no se asigna espacio en el área de datos
  • nombre='Ana' → ocupa 3 bytes + 2 bytes de prefijo de longitud = 5 bytes en total
  • El motor sabe que id y activo son fijos, así que puede calcular sus offsets sin recorrer la tupla
  • Los atributos variables se leen en orden: el motor usa las longitudes inline para saber dónde empieza el siguiente

Qué conviene según el tipo de columna y sus valores

Recurso Ventaja Desventaja
Null bitmap Ahorra bytes enteros por NULL, cualquier combinación posible Agrega 1 bit por columna como overhead fijo, aunque no haya nulos
Atributos fijos Offset conocido, sin overhead de longitud Desperdicio si el valor es menor al tipo (ej: BIGINT para valores pequeños)
Longitud inline en variables Localización rápida de cada campo 2–4 bytes extra por valor variable
Valores grandes fuera de tupla No contaminan el resto de filas en la página Acceso adicional para leer el valor real

Casos de aplicación

Situación Recomendación
Tabla con muchas columnas nullable Usar NULL explícito, no valores placeholder
Columnas VARCHAR cortas (1–20 chars) Considerar TEXT fijo o rediseñar si el overhead de longitud es significativo
Columnas con valores grandes (JSON, logs) El motor maneja el desbordamiento automático, pero monitorear performance de lectura
Tabla con filas muy pequeñas (pocas columnas) El overhead del header (~23 bytes en PostgreSQL) puede dominar el tamaño de página

Autoevaluación: Tuple Layout

1/3