CodeGym /Cursos /SQL SELF /Optimización de funciones analíticas para grandes volúmen...

Optimización de funciones analíticas para grandes volúmenes de datos: indexación y particionado

SQL SELF
Nivel 60 , Lección 3
Disponible

Cuando tienes un montón de datos (como mensajes sobre deadlines en los chats de la empresa), las consultas para seleccionar y procesar empiezan a ir más lentas. Aquí tienes las razones principales:

  1. Falta de índices. Cuando PostgreSQL tiene que escanear toda tu tabla para ejecutar una consulta (esto se llama "Seq Scan" — escaneo secuencial), la consulta puede tardar bastante más.
  2. Consultas SQL ineficientes. Si tus consultas no están optimizadas, incluso con índices puedes tener problemas en producción. ¿Por ejemplo, te olvidaste de usar condiciones clave en WHERE? Prepárate para esperar un buen rato.
  3. Grandes volúmenes de datos en una sola tabla. Por ejemplo, si intentas analizar ventas de todos los años a la vez, ni los índices te van a salvar.

Pero tranqui, tenemos dos formas probadas para lidiar con esto: Indexación y Particionado.

Usando índices para acelerar consultas

Aquí tienes un ejemplo sencillo de cómo crear un índice:

CREATE INDEX idx_sales_date ON sales(transaction_date);
  • Aquí idx_sales_date es el nombre del índice (puedes llamarlo como quieras, pero mejor que tenga sentido).
  • ON sales(transaction_date) — indica para qué tabla y columna se crea el índice.

Este índice es especialmente útil si filtras mucho por el campo transaction_date.

Ejemplo de consulta que se beneficia de este índice:

SELECT *
FROM sales
WHERE transaction_date BETWEEN '2023-01-01' AND '2023-12-31';

Indexación de claves compuestas

Si tus consultas suelen usar varias columnas a la vez, como region y product_id, piensa en crear un índice compuesto:

CREATE INDEX idx_sales_region_product ON sales(region, product_id);

Ahora las consultas como esta van mucho más rápido:

SELECT *
FROM sales
WHERE region = 'North America' AND product_id = 42;

Usando índices únicos

Los índices únicos no solo aceleran la búsqueda, sino que también garantizan que los valores en la columna sean únicos. Por ejemplo:

CREATE UNIQUE INDEX idx_unique_customer_email ON customers(email);

Ahora no podrás meter dos clientes con el mismo correo por accidente.

Indexación para funciones analíticas

Algunas funciones de análisis de datos, como SUM, COUNT o AVG, pueden usar el índice para calcular más rápido. Mira este ejemplo:

CREATE INDEX idx_sales_amount ON sales(amount);

Consulta:

SELECT SUM(amount)
FROM sales 
WHERE transaction_date >= '2023-01-01';

irá más rápido gracias al índice.

Particionado de tablas para trabajar con grandes volúmenes de datos

El particionado de tablas es el proceso de dividir una tabla grande en partes lógicas más pequeñas llamadas particiones. Por ejemplo, puedes dividir la tabla sales en particiones por año: sales_2021, sales_2022, etc.

¿Te parece complicado? En realidad, PostgreSQL lo hace más fácil de lo que parece.

Tipos de particionado

  1. Particionado por rango (Range Partitioning). Los datos se dividen según un rango, por ejemplo, por fecha.
  2. Particionado por lista (List Partitioning). Los datos se dividen según valores exactos, por ejemplo, por regiones.
  3. Particionado por hash (Hash Partitioning). Usa una función hash para dividir los datos (se usa menos a mano).

Creando una tabla particionada

Vamos a crear una tabla de ventas particionada por año.

CREATE TABLE sales (
    id SERIAL PRIMARY KEY,
    transaction_date DATE NOT NULL,
    amount NUMERIC,
    region TEXT
) PARTITION BY RANGE (transaction_date);

Ahora creamos particiones para diferentes años:

CREATE TABLE sales_2021 PARTITION OF sales
FOR VALUES FROM ('2021-01-01') TO ('2022-01-01');

CREATE TABLE sales_2022 PARTITION OF sales
FOR VALUES FROM ('2022-01-01') TO ('2023-01-01');

Las consultas que filtran por fecha automáticamente solo trabajan con la partición necesaria. Puedes comprobarlo fácilmente con el comando EXPLAIN.

Ejemplo con particionado

Así sería una consulta para sumar ventas solo de 2021:

SELECT SUM(amount)
FROM sales
WHERE transaction_date BETWEEN '2021-01-01' AND '2021-12-31';

Como ves, PostgreSQL solo trabaja con la partición sales_2021 necesaria, y no escanea toda la tabla.

Ejemplo: optimización del cálculo de métricas por regiones

Supón que quieres calcular la suma total de ventas por regiones. Sin índices ni particiones, esto tarda una eternidad. Primero creamos un índice para la columna region:

CREATE INDEX idx_sales_region ON sales(region);

Tu consulta:

SELECT region, SUM(amount)
FROM sales
GROUP BY region;

Ahora el procesamiento va más rápido gracias al índice.

Ejemplo: particionado de datos temporales

Para datos temporales, como transacciones o logs, crea particiones por meses. Por ejemplo:

CREATE TABLE sales_monthly PARTITION BY RANGE (transaction_date);

CREATE TABLE sales_jan_2023 PARTITION OF sales_monthly
FOR VALUES FROM ('2023-01-01') TO ('2023-02-01');

Consulta:

SELECT SUM(amount)
FROM sales_monthly
WHERE transaction_date >= '2023-01-01' AND transaction_date < '2023-02-01';

irá más rápido porque PostgreSQL solo lee la partición sales_jan_2023.

Ejemplo: combinando indexación y particionado

Puedes combinar indexación y particionado para lograr el máximo rendimiento. Por ejemplo, puedes crear índices dentro de cada partición. Mira este ejemplo:

CREATE INDEX idx_sales_amount_jan_2023 ON sales_jan_2023(amount);

Cómo evitar errores típicos

Muchos problemas de rendimiento vienen de usar mal los índices y el particionado. Por ejemplo:

  • Tener demasiados índices puede hacer más lentas las operaciones de inserción.
  • Las particiones deben estar equilibradas; particiones demasiado pequeñas o demasiado grandes bajan el rendimiento.
  • Olvidar analizar el rendimiento (EXPLAIN ANALYZE) antes de optimizar — es como intentar arreglar el coche sin mirar debajo del capó.

Siempre revisa si tus optimizaciones realmente mejoran la velocidad, y no tengas miedo de experimentar.

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION