Skip to content
IRC-CodingIRC-Coding
Índices de base de datosOptimización de performanceB-Tree HashFulltext IndexClustered IndexAlgoritmosFundamentosBase de datos

Índices de Base de Datos & Optimización de Performance

Guía de índices de base de datos: B-Tree, Hash, Fulltext, Clustered. Ejemplos prácticos y mejores prácticas para MySQL y PostgreSQL.

S

schutzgeist

8 min read
Índices de Base de Datos & Optimización de Performance

Índices de Base de Datos y Optimización de Rendimiento: B-Tree, Hash, Fulltext y Clustered

Este artículo es una guía completa sobre índices de base de datos y optimización de rendimiento, incluyendo índices B-Tree, Hash, Fulltext y Clustered con ejemplos prácticos.

Resumen Ejecutivo

Los índices de base de datos aceleran significativamente las consultas al proporcionar acceso rápido a los datos. Cada tipo de índice está optimizado para casos de uso diferentes.

Descripción Técnica Concisa

Los índices de base de datos son estructuras de datos especializadas que mejoran la velocidad de las operaciones de recuperación de datos en tablas. Funcionan de manera similar al índice de un libro.

Tipos de índices y sus características:

Índice B-Tree

  • Estructura: Árbol equilibrado con valores ordenados
  • Uso: Búsquedas de igualdad, búsquedas por rango, ordenamiento
  • Rendimiento: O(log n) para operaciones de búsqueda
  • Ejemplos: Claves primarias, claves foráneas, índices estándar

Índice Hash

  • Estructura: Tabla hash con direcciones directas
  • Uso: Solo búsquedas de igualdad (=)
  • Rendimiento: O(1) para coincidencias exactas
  • Ejemplos: Tablas en memoria, búsquedas exactas

Índice Fulltext

  • Estructura: Índice invertido para búsqueda de texto
  • Uso: Búsqueda de texto completo, búsqueda por palabras clave
  • Rendimiento: Algoritmos de búsqueda de texto optimizados
  • Ejemplos: Búsqueda de documentos, búsqueda de contenido

Índice Clustered

  • Estructura: Ordenamiento físico de la tabla
  • Uso: Clave primaria, búsquedas por rango frecuentes
  • Rendimiento: Rápido para acceso a clave primaria
  • Ejemplos: Series de tiempo, datos de logs

Puntos Clave para Estudio

  • Índice B-Tree: Árbol equilibrado para búsqueda de igualdad y rango
  • Índice Hash: Direccionamiento directo para coincidencias exactas
  • Índice Fulltext: Búsqueda de texto con raíces y relevancia
  • Índice Clustered: Almacenamiento físico de datos según índice
  • Rendimiento: Optimización de consultas mediante índices
  • Compensaciones: Espacio de almacenamiento versus velocidad
  • Relevancia profesional: Importante para administración y optimización de bases de datos

Componentes Clave

  1. Estructura del índice: Árbol, Hash, Índice invertido
  2. Tipo de índice: B-Tree, Hash, Fulltext, Clustered
  3. Tipo de consulta: Igualdad, Rango, Texto completo
  4. Métricas de rendimiento: Tiempo de lectura, tiempo de escritura, memoria
  5. Estrategia de índice: Una columna, múltiples columnas, Covering
  6. Optimización: Análisis EXPLAIN, ajuste de índices
  7. Mantenimiento: Reconstrucción, fragmentación, estadísticas

Ejemplos Prácticos

1. Ejemplos de Índice B-Tree

-- Crear índice B-Tree en MySQL
CREATE INDEX idx_kunden_name ON kunden(name);
CREATE INDEX idx_bestellungen_datum ON bestellungen(bestelldatum);

-- Índice B-Tree de múltiples columnas
CREATE INDEX idx_kunden_stadt_name ON kunden(stadt, name);

-- Índice B-Tree único
CREATE UNIQUE INDEX idx_email_unique ON kunden(email);

-- Consulta con uso de índice B-Tree
EXPLAIN SELECT * FROM kunden WHERE name = 'Mustermann';
EXPLAIN SELECT * FROM bestellungen WHERE bestelldatum BETWEEN '2024-01-01' AND '2024-12-31';

-- Comparación de rendimiento
-- Sin índice: Full Table Scan
SELECT * FROM grosse_tabelle WHERE spalte_x = 'wert';

-- Con índice B-Tree: Index Seek
SELECT * FROM grosse_tabelle WHERE spalte_x = 'wert';

2. Ejemplos de Índice Hash

-- Crear índice Hash en MySQL (solo con Motor MEMORY)
CREATE TABLE user_sessions (
    session_id VARCHAR(255) PRIMARY KEY,
    user_id INT,
    created_at TIMESTAMP,
    data TEXT,
    INDEX ((session_id)) USING HASH
) ENGINE=MEMORY;

-- Índice Hash en PostgreSQL
CREATE INDEX idx_hash_email ON benutzer USING HASH (email);

-- Consulta con índice Hash (solo igualdad)
SELECT * FROM benutzer WHERE email = 'user@example.com';

-- Índice Hash NO se usa para:
SELECT * FROM benutzer WHERE email LIKE 'user%';  -- Búsqueda por rango
SELECT * FROM benutzer WHERE email > 'a';        -- Operación de comparación

3. Ejemplos de Índice Fulltext

-- Índice Fulltext en MySQL
CREATE TABLE artikel (
    id INT PRIMARY KEY,
    titel VARCHAR(255),
    inhalt TEXT,
    FULLTEXT KEY ft_inhalt (titel, inhalt)
);

-- Búsqueda Fulltext
SELECT titel, inhalt 
FROM artikel 
WHERE MATCH(titel, inhalt) AGAINST('datenbank performance' IN NATURAL LANGUAGE MODE);

-- Con puntuación de relevancia
SELECT titel, 
       MATCH(titel, inhalt) AGAINST('datenbank performance' IN NATURAL LANGUAGE MODE) AS score
FROM artikel 
WHERE MATCH(titel, inhalt) AGAINST('datenbank performance' IN NATURAL LANGUAGE MODE)
ORDER BY score DESC;

-- Modo Boolean para búsquedas complejas
SELECT titel, inhalt
FROM artikel 
WHERE MATCH(titel, inhalt) AGAINST('+datenbank +performance -mysql' IN BOOLEAN MODE);

-- Índice Fulltext en PostgreSQL
CREATE TABLE dokumente (
    id SERIAL PRIMARY KEY,
    titel VARCHAR(255),
    inhalt TEXT
);

-- Índice Fulltext con tsvector
ALTER TABLE dokumente ADD COLUMN searchable_text tsvector;
UPDATE dokumente SET searchable_text = to_tsvector('german', titel || ' ' || inhalt);
CREATE INDEX idx_fulltext ON dokumente USING GIN(searchable_text);

-- Búsqueda Fulltext en PostgreSQL
SELECT titel, ts_rank(searchable_text, plainto_tsquery('german', 'datenbank performance')) AS rank
FROM dokumente 
WHERE searchable_text @@ plainto_tsquery('german', 'datenbank performance')
ORDER BY rank DESC;

4. Ejemplos de Índice Clustered

-- Índice Clustered en SQL Server
CREATE TABLE log_daten (
    log_id INT IDENTITY(1,1),
    zeitstempel DATETIME NOT NULL,
    nachricht VARCHAR(1000),
    level VARCHAR(10)
);

-- Índice Clustered en timestamp (ordenamiento físico)
CREATE CLUSTERED INDEX idx_log_zeitstempel ON log_daten(zeitstempel);

-- Índice Clustered en PostgreSQL (CLUSTER)
CREATE TABLE messwerte (
    id SERIAL PRIMARY KEY,
    sensor_id INT,
    zeitpunkt TIMESTAMP NOT NULL,
    wert DECIMAL(10,4)
);

-- Índice Clustered en clave primaria (estándar)
CREATE INDEX idx_messwerte_zeitpunkt ON messwerte(zeitpunkt);

-- Agrupar tabla según índice
CLUSTER messwerte USING idx_messwerte_zeitpunkt;

-- Índice Clustered en MySQL InnoDB (automático en clave primaria)
CREATE TABLE transaktionen (
    id BIGINT PRIMARY KEY,  -- Automáticamente clustered
    konto_id INT,
    betrag DECIMAL(12,2),
    datum DATETIME,
    INDEX idx_konto_datum (konto_id, datum)  -- Secondary Index
);

5. Análisis de Rendimiento con EXPLAIN

-- Análisis EXPLAIN en MySQL
EXPLAIN FORMAT=JSON
SELECT k.name, b.bestelldatum, b.gesamtbetrag
FROM kunden k
JOIN bestellungen b ON k.id = b.kunden_id
WHERE k.stadt = 'Berlin'
  AND b.bestelldatum >= '2024-01-01'
ORDER BY b.gesamtbetrag DESC;

-- EXPLAIN ANALYZE en PostgreSQL
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT k.name, b.bestelldatum, b.gesamtbetrag
FROM kunden k
JOIN bestellungen b ON k.id = b.kunden_id
WHERE k.stadt = 'Berlin'
  AND b.bestelldatum >= '2024-01-01'
ORDER BY b.gesamtbetrag DESC;

-- Verificar uso de índices
-- MySQL: SHOW INDEX FROM tabla;
SHOW INDEX FROM kunden;

-- PostgreSQL: \d tabla
-- o vista pg_indexes
SELECT indexname, indexdef 
FROM pg_indexes 
WHERE tablename = 'kunden';

6. Optimización de Índices y Mejores Prácticas

-- Índice Covering (todas las columnas necesarias en el índice)
CREATE INDEX idx_kunden_covering ON kunden(stadt, name, id);

-- Consulta que usa solo el índice (Index-Only Scan)
SELECT id, name FROM kunden WHERE stadt = 'Berlin';

-- Índice Partial (solo para parte de los datos)
CREATE INDEX idx_aktive_kunden ON kunden(id) WHERE status = 'aktiv';

-- Índice basado en función (PostgreSQL)
CREATE INDEX idx_kunden_name_lower ON kunden(LOWER(name));

-- Consulta que usa índice basado en función
SELECT * FROM kunden WHERE LOWER(name) = 'mustermann';

-- Índice compuesto con orden correcto de columnas
CREATE INDEX idx_bestellungen_optimal ON bestellungen(kunden_id, bestelldatum, status);

-- Buena consulta (usa índice completamente)
SELECT * FROM bestellungen 
WHERE kunden_id = 123 
  AND bestelldatum >= '2024-01-01' 
  AND status = 'completed';

-- Mala consulta (no puede usar índice completamente)
SELECT * FROM bestellungen 
WHERE status = 'completed' 
  AND bestelldatum >= '2024-01-01';  -- Columna principal no en WHERE

7. Mantenimiento y monitoreo de índices

-- Actualizar estadísticas de índices
-- MySQL
ANALYZE TABLE kunden;

-- PostgreSQL
ANALYZE kunden;

-- Verificar fragmentación de índices
-- SQL Server
SELECT * FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID('kunden'), NULL, NULL, 'DETAILED');

-- PostgreSQL
SELECT schemaname, tablename, attname, n_distinct, correlation 
FROM pg_stats 
WHERE tablename = 'kunden';

-- Reconstruir índices cuando hay fragmentación
-- SQL Server
ALTER INDEX ALL ON kunden REBUILD;

-- MySQL (InnoDB)
ANALYZE TABLE kunden;  -- Actualizar estadísticas
OPTIMIZE TABLE kunden;  -- Optimizar tabla

-- PostgreSQL
REINDEX INDEX idx_kunden_name;

Comparativa de rendimiento según tipo de índice

Tipo de índiceTipo de búsquedaRendimientoMemoriaUso
B-TreeIgualdad, rangoO(log n)MedioÍndices estándar
HashSolo igualdadO(1)BajoTablas en memoria
FulltextBúsqueda de textoVariableAltoBúsqueda textual
ClusteredClave primariaO(log n)TablaAccesos frecuentes

Estrategias de indexación

Índice de una sola columna

-- Índice simple sobre una columna
CREATE INDEX idx_kunden_email ON kunden(email);

Índice compuesto

-- Índice composite con orden óptimo de columnas
CREATE INDEX idx_kunden_stadt_name ON kunden(stadt, name);

Índice cubriente

-- El índice contiene todas las columnas necesarias
CREATE INDEX idx_bestellungen_covering ON bestellungen(kunden_id, bestelldatum, gesamtbetrag);

Índice parcial

-- Índice solo para parte de los datos
CREATE INDEX idx_aktive_kunden ON kunden(id) WHERE status = 'aktiv';

Índice basado en función

-- Índice sobre valores calculados
CREATE INDEX idx_kunden_name_lower ON kunden(LOWER(name));

Optimización de consultas

Maximizar el uso de índices

-- BUENAS consultas (utilizan índices)
SELECT * FROM kunden WHERE stadt = 'Berlin';                    -- Índice de una columna
SELECT * FROM bestellungen WHERE kunden_id = 123 AND datum > '2024-01-01'; -- Índice compuesto
SELECT * FROM artikel WHERE MATCH(titel) AGAINST('suchbegriff');    -- Índice Fulltext

-- MALAS consultas (no utilizan índices)
SELECT * FROM kunden WHERE LOWER(name) = 'mustermann';           -- Sin índice basado en función
SELECT * FROM bestellungen WHERE YEAR(datum) = 2024;            -- Función en columna
SELECT * FROM kunden WHERE name LIKE '%mustermann%';             -- Comodín al inicio

Análisis con EXPLAIN

-- MySQL
EXPLAIN SELECT * FROM kunden WHERE stadt = 'Berlin';

-- Columnas importantes:
-- type: ALL (malo), ref, range, index (bueno)
-- key: Índice utilizado
-- rows: Número estimado de filas
-- Extra: Using index (bueno), Using filesort (malo)

-- PostgreSQL
EXPLAIN ANALYZE SELECT * FROM kunden WHERE stadt = 'Berlin';

-- Información relevante:
-- Seq Scan vs Index Scan
-- Index-Only Scan (muy bueno)
-- Tiempo real de ejecución

Ventajas y desventajas

Ventajas de los índices

  • Rendimiento: Consultas drásticamente más rápidas
  • Ordenamiento: ORDER BY sin necesidad de ordenamiento adicional
  • Unicidad: Los índices UNIQUE garantizan integridad de datos
  • Joins: Los índices de clave foránea aceleran los JOINs

Desventajas

  • Espacio: Los índices requieren almacenamiento adicional
  • Escritura: INSERT/UPDATE/DELETE se vuelven más lentos
  • Mantenimiento: Los índices deben ser mantenidos
  • Sobrecarga: Demasiados índices pueden ser contraproducentes

Mejores prácticas

Cuándo crear índices

  • Cláusulas WHERE frecuentes
  • Condiciones de JOIN
  • Cláusulas ORDER BY
  • Cláusulas GROUP BY
  • Restricciones UNIQUE

Cuándo evitar índices

  • Columnas raramente utilizadas
  • Tablas con pocas filas
  • Columnas con alta cardinalidad pero baja selectividad
  • Operaciones frecuentes de UPDATE/DELETE

Diseño de índices

  • Orden de columnas: Selectividad descendente
  • Amplitud del índice: Lo más estrecho posible
  • Índice cubriente: Incluir todas las columnas necesarias
  • Índice parcial: Solo para datos relevantes

Preguntas frecuentes de examen

  1. ¿Cuál es la diferencia entre un índice B-Tree e índice Hash? B-Tree soporta búsqueda de igualdad y rango, Hash solo igualdad.

  2. ¿Cuándo se utiliza un índice Fulltext? Para búsqueda textual en campos de texto grandes con formas de raíces y valoración de relevancia.

  3. ¡Explica Clustered vs Non-Clustered Index! Clustered: Almacenamiento físico de datos, Non-Clustered: Estructura de índice separada.

  4. ¿Cómo se verifica el uso de índices? Con EXPLAIN/EXPLAIN ANALYZE para analizar el plan de consulta.

Fuentes principales

  1. https://dev.mysql.com/doc/refman/8.0/en/mysql-indexes.html
  2. https://www.postgresql.org/docs/current/indexes.html
  3. https://docs.microsoft.com/en-us/sql/relational-databases/indexes/indexes

Lecturas recomendadas: Bases de datos

Keine Bücher für Kategorie "datenbanken" gefunden.

Volver al blog
Share:

Entradas relacionadas