Cómo configurar índices y mantenimiento de la base de datos en MU Online
Crea los índices correctos en las tablas de MuOnline y arma una rutina de mantenimiento (rebuild, reorganize, update statistics) para que la base de datos siga rápida incluso con el servidor lleno durante meses.
Una base MuOnline recién restaurada es rápida. La misma base después de tres meses de servidor lleno —millones de guardados de posición, inventarios modificados todo el día, logs de eventos acumulados— se vuelve lenta si nadie cuida los índices. Las tablas se fragmentan, las estadísticas envejecen y
Una base MuOnline recién restaurada es rápida. La misma base después de tres meses de servidor lleno —millones de guardados de posición, inventarios modificados todo el día, logs de eventos acumulados— se vuelve lenta si nadie cuida los índices. Las tablas se fragmentan, las estadísticas envejecen y consultas que antes volaban empiezan a recorrer la tabla entera. El resultado es ese login que tarda y el guardado que se atrasa incluso con el VPS holgado de CPU. La solución tiene dos frentes: crear los índices correctos en las tablas que MU consulta a cada momento y armar una rutina de mantenimiento que reconstruya índices y actualice estadísticas automáticamente. Esta guía cubre ambos. Los nombres de tabla, columnas y límites numéricos aquí son ejemplos que varían según la versión del MuServer y del SQL: el método es el mismo.
Requisitos previos
- Base
MuOnlinerestaurada y en producción (o un clon de prueba para practicar); - SQL Server Management Studio (SSMS) y un login con permiso
db_ownerosysadmin; - Backup completo y reciente antes de tocar los índices;
- Una ventana de mantenimiento definida (horario de menor movimiento del servidor);
- Noción de qué consultas hace más tu servidor (login, ranking, guardado): eso guía qué índices crear.
Antes de crear cualquier índice, entiende las tablas centrales de la base MuOnline. Las más consultadas suelen ser:
| Tabla (ejemplo) | Consulta típica | Columna clave de búsqueda |
|---|---|---|
MEMB_INFO | Login por cuenta | memb___id (login) |
Character | Cargar personaje | Name, AccountID |
Guild / GuildMember | Armar el guild al loguear | G_Name, Name |
warehouse / Inventory | Baúl e ítems | AccountID / Name |
| Tablas de ranking/evento | Ranking del sitio | columnas de puntuación |
WHERE, JOIN y ORDER BY de las consultas más frecuentes, no todas las columnas.Paso 1 — Medir la fragmentación actual
Empieza diagnosticando. La consulta de abajo lista los índices de la base y cuánto está fragmentado cada uno: es lo que decide si vas a hacer rebuild, reorganize o nada:
USE MuOnline;
SELECT
OBJECT_NAME(ips.object_id) AS Tabla,
i.name AS Indice,
ips.avg_fragmentation_in_percent AS FragPct,
ips.page_count AS Paginas
FROM sys.dm_db_index_physical_stats(DB_ID('MuOnline'), NULL, NULL, NULL, 'LIMITED') ips
JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE ips.page_count > 100 -- ignorar índices minúsculos
AND i.name IS NOT NULL
ORDER BY ips.avg_fragmentation_in_percent DESC;
La columna FragPct guía la acción. Los índices con pocas páginas (tablas pequeñas) no valen el mantenimiento: la reconstrucción no cambia nada perceptible. Concéntrate en las tablas grandes y volátiles.
| Fragmentación (FragPct) | Acción recomendada |
|---|---|
| Por debajo de ~10% | No hacer nada |
| Entre ~10% y ~30% | REORGANIZE (ligero, online) |
| Por encima de ~30% | REBUILD (pesado, reconstruye) |
Paso 2 — Identificar índices que faltan
SQL Server registra sugerencias de índices que habrían ayudado a consultas recientes. Son un excelente punto de partida para saber dónde crearlos:
SELECT TOP 15
OBJECT_NAME(mid.object_id) AS Tabla,
migs.avg_user_impact AS ImpactoPct,
migs.user_seeks + migs.user_scans AS Usos,
mid.equality_columns AS ColunasIgualdade,
mid.inequality_columns AS ColunasDesigualdade,
mid.included_columns AS ColunasIncluidas
FROM sys.dm_db_missing_index_details mid
JOIN sys.dm_db_missing_index_groups mig ON mid.index_handle = mig.index_handle
JOIN sys.dm_db_missing_index_group_stats migs ON mig.index_group_handle = migs.group_handle
WHERE mid.database_id = DB_ID('MuOnline')
ORDER BY migs.avg_user_impact * (migs.user_seeks + migs.user_scans) DESC;
Prioriza las sugerencias con alto impacto Y muchos usos: un índice que ayudaría al 90% pero nunca se usa no vale el costo de escritura. Trata las sugerencias como una pista, no como una orden: SQL a veces sugiere índices superpuestos.
Paso 3 — Crear índices con criterio
Con el diagnóstico en mano, crea índices en las columnas que MU realmente busca. Ejemplos comunes (los nombres de tabla/columna varían según la versión):
-- Login: búsqueda por cuenta en MEMB_INFO
CREATE NONCLUSTERED INDEX IX_MEMB_INFO_id
ON MEMB_INFO (memb___id);
-- Cargar personajes de una cuenta
CREATE NONCLUSTERED INDEX IX_Character_Account
ON Character (AccountID)
INCLUDE (Name, cLevel, Class); -- las columnas incluidas evitan volver a la tabla
-- Buscar personaje por nombre (usado en comandos y ranking)
CREATE NONCLUSTERED INDEX IX_Character_Name
ON Character (Name);
-- Miembros de un guild
CREATE NONCLUSTERED INDEX IX_GuildMember_Guild
ON GuildMember (G_Name);
El INCLUDE es una técnica poderosa: guarda columnas extra en el índice para que la consulta responda sin volver a la tabla principal (un "covering index"). Úsalo en las columnas que la consulta devuelve pero no filtra.
SELECT i.name, c.name FROM sys.indexes i JOIN sys.index_columns ic ON i.object_id=ic.object_id AND i.index_id=ic.index_id JOIN sys.columns c ON ic.object_id=c.object_id AND ic.column_id=c.column_id WHERE i.object_id = OBJECT_ID('Character');Paso 4 — Reorganizar y reconstruir índices
Ahora el mantenimiento en sí. REORGANIZE desfragmenta suavemente y siempre es online (no bloquea). REBUILD reconstruye desde cero: más eficaz, pero más pesado y, en las ediciones Standard/Express, bloquea la tabla mientras corre.
-- REORGANIZE: fragmentación moderada (~10% a 30%)
ALTER INDEX IX_Character_Account ON Character REORGANIZE;
-- REBUILD: fragmentación alta (>30%)
ALTER INDEX IX_Character_Account ON Character REBUILD;
-- REBUILD de TODOS los índices de una tabla
ALTER INDEX ALL ON Character REBUILD;
-- REBUILD ONLINE (solo Enterprise/Developer; no bloquea la tabla)
ALTER INDEX ALL ON Character REBUILD WITH (ONLINE = ON);
Tras un REBUILD, las estadísticas de ese índice ya quedan actualizadas. Tras un REORGANIZE, no: por eso el siguiente paso (actualizar estadísticas) es parte obligatoria de la rutina.
Character con el servidor lleno congela el login y el guardado de todo el mundo. Hazlo siempre en una ventana de mantenimiento, con el servidor vacío o con aviso.Paso 5 — Actualizar estadísticas
Las estadísticas le dicen al optimizador cómo están distribuidos los datos. Si están viejas, llevan a SQL a planes malos incluso con índices perfectos. Actualízalas en la misma ventana de mantenimiento:
-- Actualizar estadísticas de toda la base
USE MuOnline;
EXEC sp_updatestats;
-- O de una tabla específica, con recorrido completo (más preciso)
UPDATE STATISTICS Character WITH FULLSCAN;
sp_updatestats es práctico para la rutina general; WITH FULLSCAN en una tabla crítica da la estadística más precisa al costo de leerlo todo. Combina: rutina general con sp_updatestats, más FULLSCAN en las dos o tres tablas más consultadas.
Paso 6 — Armar un script de mantenimiento inteligente
Ejecutar rebuild en todo, siempre, es un desperdicio y bloquea demasiado. Lo ideal es un script que decida por índice según la fragmentación. Este cursor hace exactamente eso:
-- Mantenimiento inteligente: reorganize o rebuild según la fragmentación
USE MuOnline;
DECLARE @tabela NVARCHAR(200), @indice NVARCHAR(200), @frag FLOAT, @sql NVARCHAR(MAX);
DECLARE cur CURSOR FOR
SELECT OBJECT_NAME(ips.object_id), i.name, ips.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID('MuOnline'), NULL, NULL, NULL, 'LIMITED') ips
JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE ips.page_count > 100 AND i.name IS NOT NULL
AND ips.avg_fragmentation_in_percent > 10;
OPEN cur;
FETCH NEXT FROM cur INTO @tabela, @indice, @frag;
WHILE @@FETCH_STATUS = 0
BEGIN
IF @frag > 30
SET @sql = 'ALTER INDEX [' + @indice + '] ON [' + @tabela + '] REBUILD;';
ELSE
SET @sql = 'ALTER INDEX [' + @indice + '] ON [' + @tabela + '] REORGANIZE;';
PRINT @sql; -- registra lo que se va a ejecutar
EXEC sp_executesql @sql;
FETCH NEXT FROM cur INTO @tabela, @indice, @frag;
END
CLOSE cur; DEALLOCATE cur;
-- Cierra con la actualización de estadísticas
EXEC sp_updatestats;
Este script solo toca lo que pasa del 10% de fragmentación, elige reorganize o rebuild por índice y finaliza actualizando estadísticas. Es la base de tu rutina automática.
Paso 7 — Agendar el mantenimiento con el SQL Server Agent
Pon el script a correr solo en la ventana de menor movimiento (la madrugada). En SSMS:
- Expande SQL Server Agent → Jobs, clic derecho → New Job...;
- Pestaña General: nombre
Manutencao Indices MuOnline; - Pestaña Steps → New...: type
Transact-SQL, databaseMuOnline, pega el script del paso anterior; - Pestaña Schedules → New...:
Recurring,Weekly, en un día y hora de bajo movimiento (ej.: domingo 05:00); - Pestaña Notifications: marca el email en caso de falla, si está configurado;
- OK para guardar.
.sql invocado por sqlcmd dentro de un .bat, agendado con el Programador de Tareas de Windows: el mismo principio de los backups automáticos.Paso 8 — Verificar la integridad de la base (DBCC CHECKDB)
El mantenimiento de índices no detecta corrupción. Ejecuta DBCC CHECKDB periódicamente para garantizar que la base está físicamente sana: de nada sirve un índice perfecto en una base corrupta:
-- Verificación completa de integridad (ejecutar en mantenimiento, es pesado)
DBCC CHECKDB('MuOnline') WITH NO_INFOMSGS, ALL_ERRORMSGS;
-- Esperado: "CHECKDB found 0 allocation errors and 0 consistency errors"
Si aparecen errores de consistencia, no te pongas a usar REPAIR_ALLOW_DATA_LOSS por impulso: puede borrar datos. Restaura primero desde un backup íntegro; la reparación destructiva es el último recurso.
Paso 9 — Controlar el crecimiento de las tablas de log
Muchas bases de MU acumulan tablas de log de eventos, cash, comandos, que solo crecen. Inflan la base, el mantenimiento y el backup. Define una política de purga:
-- Ejemplo: borrar logs de evento con más de 90 días (el nombre varía según la versión)
DELETE FROM T_Event_Log WHERE LogDate < DATEADD(DAY, -90, GETDATE());
Agrega una purga así a la rutina semanal (con cuidado y backup previo), para que la base no crezca indefinidamente solo por historial.
Errores comunes y soluciones
| Síntoma | Causa probable | Solución |
|---|---|---|
| Consultas lentas aun con CPU holgada | Índices fragmentados / estadísticas viejas | Ejecutar la rutina de rebuild/reorganize + sp_updatestats |
| El login se trabó durante la madrugada | REBUILD offline en el horario equivocado | Agendar para la ventana vacía o usar REBUILD ONLINE |
| La escritura (guardado) se volvió más lenta tras optimizar | Demasiados índices o duplicados | Eliminar índices redundantes; mantener solo los útiles |
| Sugerencias de índice en cero | SQL reinició recientemente | Recoger tras horas de carga real |
| El rebuild no mejoró nada | Índice pequeño / el problema es otro | Enfocar tablas grandes; investigar la consulta específica |
| La base crece sin parar | Tablas de log acumulándose | Política de purga periódica de los logs |
| Error de consistencia en CHECKDB | Corrupción física | Restaurar desde backup íntegro, no reparar de forma destructiva |
Lista de verificación de lanzamiento
- Backup completo hecho antes de tocar los índices
- Fragmentación actual medida con
dm_db_index_physical_stats - Índices ausentes sugeridos, recogidos tras carga real y evaluados por impacto y uso
- Índices creados en las columnas de login, carga de personaje, guild y ranking
- Índices duplicados/redundantes verificados y eliminados
- Script inteligente (reorganize vs rebuild por fragmentación) probado en el clon
- Job semanal de mantenimiento agendado en el SQL Server Agent (o .bat vía Programador en Express)
- Actualización de estadísticas incluida al final de la rutina
- DBCC CHECKDB agendado y devolviendo 0 errores
- Política de purga de las tablas de log definida
- Mantenimiento pesado confinado a la ventana de menor movimiento
- Ganancia de rendimiento validada comparando antes/después en una consulta real
Con índices bien elegidos y una rutina de mantenimiento corriendo sola cada semana, la base MuOnline se mantiene rápida mes tras mes, incluso con el servidor lleno y millones de operaciones acumuladas. Junto con el tuning de memoria y tempdb y una buena política de backup, cierras el trípode que sostiene un servidor estable y veloz desde el lanzamiento en adelante.
Preguntas frecuentes
¿Qué es un índice en SQL Server?
Es una estructura auxiliar que acelera las búsquedas, como el índice de un libro. En lugar de recorrer toda la tabla para encontrar una cuenta o un personaje, SQL va directo al registro. Sin un índice adecuado, cada login lee la tabla entera, lo que se vuelve lento a medida que crece la base.
¿Tener demasiados índices es malo?
Sí. Cada índice acelera la lectura pero pesa en la escritura, porque toda inserción o actualización necesita mantener todos los índices. En una base de MU, que escribe mucho (guardado de posición, inventario), los índices en exceso o duplicados estorban. Crea solo los que realmente ayudan a consultas frecuentes.
¿Rebuild o reorganize, cuál usar?
Depende de la fragmentación. Como regla práctica, por debajo de ~10% no hagas nada, entre ~10% y 30% usa REORGANIZE (más ligero, online), por encima de 30% usa REBUILD (más pesado, reconstruye el índice). Los límites exactos varían según la versión y el tamaño de la tabla.
¿Con qué frecuencia ejecutar el mantenimiento de índices?
Para servidores activos, una rutina semanal en horario de bajo movimiento suele bastar, sumada a una actualización de estadísticas más frecuente. Las tablas muy volátiles pueden requerir mantenimiento más seguido. Lo ideal varía según el volumen de escritura del servidor.
¿El mantenimiento de índices puede tumbar el servidor?
El REBUILD offline bloquea la tabla durante la operación, lo que puede trabar el login y el guardado si se ejecuta en el pico. Hazlo en una ventana de mantenimiento, con el servidor vacío o avisado, o usa REBUILD con la opción ONLINE en las ediciones que lo soportan.