Si estás aquí es porque alguien te ha dicho que tu SQL Server «tiene que estar bien configurado» y has ido a buscar las recomendaciones oficiales de Microsoft. Las has aplicado, has dejado el MAXDOP en 8, has subido el cost threshold a 50 y te has quedado tan tranquilo. Y aquí viene el problema: puede que hayas configurado mal tu servidor justo por seguir un estándar al pie de la letra.

En este post quiero defender una idea que llevo años repitiendo a compañeros y clientes: las best practices de SQL Server no son una lista de valores que copias y pegas; son un punto de partida que hay que ajustar a tu servidor concreto. Vamos al lío.

Qué son las best practices en SQL Server

Las best practices en SQL Server son un conjunto de recomendaciones de configuración (parámetros de instancia, memoria, paralelismo, tempdb, mantenimiento) orientadas a garantizar rendimiento, estabilidad y previsibilidad. Microsoft publica guías oficiales para muchos de estos parámetros y son una referencia excelente. Pero son eso: una referencia genérica para «un servidor cualquiera», no para tu servidor.

El matiz importa, y hay un agravante: muchos de esos umbrales por defecto llevan años —a veces décadas— sin cambiar y se han quedado obsoletos frente al hardware actual. Por eso, para ajustar bien tu instancia no basta con la documentación oficial: hay que recurrir a información experta de la comunidad —blogs de referencia, MVPs, gente que prueba estas configuraciones en producción a diario— que mantiene el criterio actualizado.

Por qué el valor por defecto casi nunca es el correcto

Tomemos el ejemplo más clásico: el cost threshold for parallelism. El valor por defecto sigue siendo 5, un número de los años 90 hoy ridículamente bajo: hace que consultas triviales se paralelicen sin necesidad, generando overhead de CPU y contención. Todo el mundo coincide en subirlo, pero ahí acaba el consenso: el rango recomendado va de 20 a 50 o más, según el coste real de tus consultas.

Lo puedes comprobar antes de tocar nada:

-- Revisar la configuración actual de paralelismo
SELECT
    name,
    value_in_use,
    description
FROM sys.configurations
WHERE name IN ('cost threshold for parallelism', 'max degree of parallelism')
ORDER BY name;

Y si quieres saber qué cost threshold tiene sentido, mira el coste estimado de los planes que se ejecutan en tu instancia:

-- Analizar el costo estimado del subárbol de los planes en caché para ajustar el umbral de costo para el paralelismo
SELECT TOP 50
    qs.execution_count,
    CONVERT(DECIMAL(18, 2), qp.query_plan.value(
        '(//StmtSimple/@StatementSubTreeCost)[1]', 'float')) AS estimated_cost,
    SUBSTRING(st.text, (qs.statement_start_offset / 2) + 1, 100) AS query_snippet
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp
ORDER BY qs.execution_count DESC;

El MAXDOP no se configura mirando una tabla

El MAXDOP es el otro gran ejemplo. La guía de Microsoft te da una tabla según los procesadores lógicos por nodo NUMA: con un único nodo de más de 8 cores, déjalo en 8; con varios nodos, no superes los cores de un nodo. Está bien como regla general, pero esa tabla no sabe que tu carga es OLTP pura, ni que tienes 50 instancias virtualizadas, ni que tu aplicación lanza miles de consultas pequeñas concurrentes donde paralelizar solo hace daño.

Para ajustarlo de verdad necesitas tu topología:

-- Contar los procesadores lógicos por nodo NUMA para determinar el valor de MAXDOP
SELECT
    parent_node_id AS numa_node,
    COUNT(*) AS logical_processors
FROM sys.dm_os_schedulers
WHERE status = 'VISIBLE ONLINE'
    AND scheduler_id < 255
GROUP BY parent_node_id
ORDER BY parent_node_id;

Con ese dato y el tipo de carga decides. En OLTP suelo arrancar con un MAXDOP moderado (4 es buen punto de partida), validar con evidencia real (CPU, waits, duración) y ajustar solo si puedo demostrar mejora. Ojo: cambiar MAXDOP «porque hay esperas CXPACKET» es uno de los errores más repetidos. Esas esperas significan que hay paralelismo, no que sea malo.

La memoria: ni por defecto, ni a ojo

El max server memory por defecto es prácticamente infinito (2147483647 MB), así que SQL Server intentará comerse toda la RAM. En un servidor dedicado casi pasa, pero si conviven el SO, un agente de backup y otra instancia, estás pidiendo problemas. No hay número mágico: depende de la RAM total, de cuántas instancias conviven y de si usas columnstore o In-Memory OLTP.

-- Review configured max server memory
SELECT
    name,
    value_in_use AS configured_mb
FROM sys.configurations
WHERE name = 'max server memory (MB)';

¿Y en Azure SQL es lo mismo?

No exactamente, y aquí mucha gente se confunde. En Azure SQL Managed Instance y Azure SQL Database Microsoft fija el MAXDOP por defecto en 8, no en 0. La memoria la gestiona la plataforma según el tier, así que no toqueas max server memory. Pero ese 8 sigue siendo discutible según tu carga: en Managed Instance lo ajustas a nivel de instancia o de base de datos, y en Azure SQL Database mediante database scoped configurations. En ninguna te libras de revisar la configuración; solo cambian las palancas. Aplicar la receta de on-premises a Azure SQL sin pensar es otro error clásico.

El problema real: configurar bien no escala

Hasta aquí la parte buena: con estos scripts y un poco de criterio puedes auditar una instancia. Si tienes una sola y eres un DBA con experiencia, no necesitas mucho más.

El problema aparece cuando la realidad se multiplica. Con 5, 10 o 50 instancias, cada una con su hardware y su carga, revisar a mano cada parámetro contra las best practices se vuelve inviable. Y hay limitaciones de fondo:

  • No tienes una foto global: revisar instancia por instancia no te da una vista comparativa de quién está mal configurado y por qué.
  • No sabes el impacto real: una tabla de Microsoft te dice «8», pero no si en tu servidor ese valor te perjudica frente a otra alternativa.
  • Rastrear el criterio actualizado es trabajo manual constante: sabes que el default está obsoleto, pero ir a blogs y MVPs a ver qué valor tiene sentido para cada parámetro y cada instancia exige tiempo y un nivel de experiencia que no todo el equipo tiene.

Cómo lo resuelve Coyote Monitor

Aquí es donde entra el panel de Best Practices de Coyote Monitor. En lugar de ejecutar scripts manuales en cada instancia y cruzar a ojo la guía genérica con lo que recomiendan los expertos, Coyote Monitor evalúa automáticamente la configuración de todas tus instancias de SQL Server y Managed Instance y te indica las configuraciones recomendadas según el contexto de cada servidor. Tienes la foto completa de un vistazo, sin recordar de memoria qué valor lleva cada parámetro en cada máquina.

En resumen

Las best practices de SQL Server son imprescindibles como punto de partida, pero el estándar de Microsoft está pensado para «cualquier servidor», no para el tuyo, y muchos de sus umbrales llevan años sin actualizarse. Cada parámetro —cost threshold, MAXDOP, memoria— exige analizar tu hardware y tu carga, y a menudo cruzar la documentación oficial con criterio experto de la comunidad. A mano es viable en una instancia; en un parque de servidores, necesitas que algo lo analice por ti.

Si gestionas más de un SQL Server o Managed Instance y quieres ver cómo Coyote Monitor evalúa tu configuración contra las best practices automáticamente, pruébalo gratis 30 días: https://coyotemonitor.com/prueba-gratuita/

Preguntas frecuentes (FAQs)

¿Cuáles son las best practices más importantes en SQL Server?

Las más críticas son la configuración del MAXDOP, el cost threshold for parallelism y el max server memory. Los valores por defecto de Microsoft son un punto de partida genérico, no una configuración óptima para tu servidor: hay que ajustarlos al hardware real, al tipo de carga (OLTP, OLAP, mixto) y al número de instancias que conviven en la misma máquina.

¿Cuál es el valor recomendado de MAXDOP en SQL Server?

Depende de la topología del servidor y del tipo de carga. Microsoft recomienda no superar los cores de un nodo NUMA, pero en entornos OLTP con muchas consultas pequeñas concurrentes suele ser mejor empezar con un valor moderado como 4 y validar con métricas reales. Las esperas CXPACKET por sí solas no justifican bajar el MAXDOP.

¿Qué valor debería tener el cost threshold for parallelism?

El valor por defecto (5) está obsoleto desde los años 90 y permite que consultas triviales se ejecuten en paralelo sin necesidad. El rango recomendado por la comunidad experta oscila entre 20 y 50 o más, según el coste estimado de los planes que realmente se ejecutan en tu instancia.

¿Las best practices de SQL Server on-premises aplican igual en Azure SQL?

No exactamente. En Azure SQL Managed Instance y Azure SQL Database la memoria la gestiona la plataforma, por lo que no se configura max server memory. El MAXDOP por defecto es 8 (no 0 como en on-premises) y se ajusta mediante database scoped configurations. Las palancas cambian, pero la necesidad de revisar y ajustar la configuración no desaparece.

¿Cómo sé si mi SQL Server está bien configurado según las best practices?

Puedes auditar los parámetros clave con consultas a sys.configurations y cruzar los valores con las recomendaciones de Microsoft y de la comunidad experta. Si gestionas varias instancias, hacerlo a mano no escala: herramientas como Coyote Monitor evalúan automáticamente la configuración de todas tus instancias y muestran qué parámetros necesitan revisión en un solo panel.