Saltar al pie de página
Iron Academy Logo
Problemas comunes de C#

Los peligros de nvarchar(max) en SQL para los desarrolladores de Entity Framework

Tim Corey
10m 27s

Al tratar con nvarchar en SQL, los desarrolladores a menudo ignoran cómo este tipo de datos afecta al rendimiento, especialmente cuando trabajan en C# con Entity Framework. En un vídeo específico de 10 minutos titulado "The Dangers of nvarchar(max) in SQL for Entity Framework Developers", Tim Corey explora el impacto del uso de nvarchar(max) como valor predeterminado para campos de cadena en una base de datos de SQL Server.

Este artículo es una explicación detallada del vídeo de Tim utilizando únicamente sus demostraciones y razonamientos, con ejemplos y comparaciones de rendimiento. Si confías en nvarchar(max) sin entender cómo funciona bajo el capó, esto te abrirá los ojos.

Comprensión del problema: comportamiento predeterminado en Entity Framework

Tim comienza describiendo un escenario común de Entity Framework en el que un desarrollador de C# define un modelo con campos como FirstName y LastName. Cuando la tabla se crea automáticamente en SQL Server mediante migraciones, el esquema generado establece esos campos de cadena en nvarchar(max) por defecto.

Como explica Tim, esto sucede porque Entity Framework no conoce el tamaño de cadena adecuado que debe asignar, por lo que elige la ruta segura: asignar la longitud máxima de forma predeterminada. Esto significa que cada columna nvarchar permite hasta 2^31-1 caracteres, con un tamaño máximo de almacenamiento en gigabytes.

Esta decisión parece cómoda, pero esconde peligrosos costes de rendimiento.

Ejemplo de configuración con dos tablas: nvarchar(max) vs Longitud fija

Para poner de relieve el problema, Tim crea dos tablas idénticas:

  • Usuarios: con nvarchar(50) para nombres y apellidos.

  • UsersToTheMax: con nvarchar(max) para los mismos campos.

En el minuto 2:39, Tim explica cómo rellenó ambas tablas con un millón de filas idénticas utilizando Dapper, asegurándose de que sólo difiere el tipo de datos nvarchar.

Esta configuración le permite realizar una comparación coherente entre una columna Unicode de longitud fija y una columna max de longitud variable.

Comparación de consultas y planes de ejecución

Tim utiliza la siguiente consulta SQL en ambas tablas:

SELECCIONAR * DE dbo.Users ORDENAR POR Apellido;
SELECCIONAR * DE dbo.UsersToTheMax ORDENAR POR Apellido;

En el minuto 3:34, habilita el plan de ejecución real para analizar lo que SQL Server hace internamente al ejecutar estas consultas.

Nota: Esta prueba no se refiere al tiempo total de ejecución en distintos equipos. Tim hace hincapié en la comparación de consultas en el mismo servidor con los mismos datos, para aislar la forma en que nvarchar(max) afecta al rendimiento.

Resultados impactantes

Los planes de ejecución revelan una diferencia importante:

  • La consulta sobre nvarchar(50) utiliza sólo el 2% del coste del lote.

  • La consulta sobre nvarchar(max) utiliza la friolera del 98% del coste.

Como dice Tim, esto significa que la consulta máxima es 50 veces más cara en términos de cómo la gestiona SQL Server, aunque las entradas de datos de columna sean las mismas y relativamente pequeñas.

En términos de tiempo de CPU:

  • La ordenación nvarchar(50) tarda 107 ms.

  • La ordenación nvarchar(max) tarda 339 ms.

Pero la mayor diferencia radica en una operación específica de paralelismo:

  • Duración fija: 0.43s

  • Duración máxima: 22.17s

Esto es más de 50 veces más lento, incluso con datos idénticos.

Diferencias en el consumo de memoria

Tim se sumerge en las concesiones de memoria: cuánta memoria asigna SQL Server a cada consulta:

  • nvarchar(50) consulta: 340MB

  • nvarchar(max) consulta: 641MB

Esto por sí solo es una señal de alarma, pero cuando se comprueban columnas sin caché, el impacto es aún más dramático:

  • Longitud fija en FirstName: 357MB

  • Longitud máxima en FirstName: 8.5 GB

Este aumento se produce porque SQL Server no sabe qué tamaño puede tener el valor nvarchar cuando se define como max, por lo que reserva un bloque de memoria más grande para acomodar el tamaño máximo.

¿Por qué nvarchar(max) es tan caro?

A las 9:15, Tim explica la razón subyacente. El tipo de datos nvarchar(max):

  • Admite hasta 2^31-1 caracteres Unicode y consume hasta 2 GB de espacio de almacenamiento.

  • Requiere que SQL Server almacene el valor fuera de la fila si no cabe, utilizando un puntero en lugar del almacenamiento directo en la fila.

  • No pueden indexarse del mismo modo que las columnas de longitud fija.

Como resultado:

  • No se puede indexar una columna nvarchar(max), lo que significa que SQL Server debe ordenar o filtrar todo el conjunto de datos sin optimización.

  • Esto afecta a operaciones como ORDER BY, WHERE o JOINs en campos nvarchar(max).

Este comportamiento conlleva un uso significativo de memoria, carga de la CPU y ralentizaciones, solo por elegir la longitud de datos de caracteres incorrecta.

Recomendación final de Tim

Como dice Tim para terminar:

"En sus consultas de Entity Framework, asegúrese de especificar el tamaño de todas las cadenas"

Defina siempre sus propiedades de cadena con un número máximo de caracteres, como nvarchar(100) o nvarchar(255), en función de los datos previstos. Este cambio menor garantiza:

  • Espacio de almacenamiento optimizado

  • Soporte para indexación

  • Coste de consulta reducido

  • Mayor coherencia en el rendimiento

Al establecer una longitud adecuada, conseguirá que el esquema de su base de datos sea más eficiente y evitará las trampas de las configuraciones perezosas por defecto.

Conclusión

El vídeo de Tim Corey ofrece una lección fundamental: el uso de nvarchar(max) como longitud predeterminada para los campos de cadena en SQL puede reducir el rendimiento sin que te des cuenta. SQL Server asignará memoria excesiva, omitirá índices y aumentará los costes de CPU, incluso para entradas de texto Unicode normales como nombres o direcciones.

¿Para qué sirve? Comprenda el tipo de datos nvarchar y evite max a menos que realmente lo necesite para campos que puedan almacenar documentos de gran tamaño o contenido de longitud variable.

Al especificar el tamaño de las cadenas, no sólo ahorra bytes y memoria, sino que también hace que su código de Entity Framework y SQL sea más eficiente, escalable y robusto. Siguiendo la guía de Tim, se asegurará de que su aplicación no sea lenta por diseño.

Para cualquiera que trabaje con bases de datos en .NET, se trata de una práctica recomendada que debería formar parte de su conjunto de herramientas estándar. Echa un vistazo al Channel de Tim para ver más vídeos relacionados con SQL.

Hero Worlddot related to Los peligros de nvarchar(max) en SQL para los desarrolladores de Entity Framework
Hero Affiliate related to Los peligros de nvarchar(max) en SQL para los desarrolladores de Entity Framework

Gana más compartiendo lo que te gusta

¿Creas contenidos para desarrolladores que trabajan con .NET, C#, Java, Python o Node.js? ¡Convierte tu experiencia en un ingreso extra!

Equipo de soporte de Iron

Estamos disponibles online las 24 horas, 5 días a la semana.
Chat
Email
Llámame