¿Cuál es el mejor tipo de datos SQL para almacenar cadenas JSON?

127

¿Cuál es el mejor tipo de datos SQL para almacenar cadenas JSON?

static List<ProductModel> CreateProductList()
{
    string json = @"[
        {
            ProductId: 1, 
            ProductCode: 'A', 
            Product: 'A'
        },
        {
            ProductId: 2, 
            ProductCode: 'B', 
            Product: 'B'
        }
    ]";

    IList<JToken> tokenList = JToken.Parse(json).ToList();
    List<ProductModel> productList = new List<ProductModel>();

    foreach (JToken token in tokenList)
    {
        productList.Add(JsonConvert.DeserializeObject<ProductModel>(token.ToString()));
    }

    return productList;
}

¿Qué tipo de datos SQL deberíamos usar para almacenar una cadena que contenga JSON?

  • NVARCHAR(255)?
  • TEXT?
  • VARBINARY(MAX)?
DatPT
fuente
1
Solo un poco de ruido aleatorio (el comentario, no los datos): es posible que también desee comprimirlo. En ese caso necesitas algo binario. Por otro lado: ¿por qué no simplemente diseñar tablas adecuadas para los datos?
The Nail
3
@The Nail: a veces, almacenar algo como JSON (o como un "documento") es adecuado para la necesidad. Al igual que para un motor de flujo de trabajo o gestión de documentos, etc., estoy haciendo esto en un proyecto actual, en realidad pasando del enfoque relacional al documento para el lado del comando de mi implementación de CQRS. Es muy rápido si usa un serializador como ServiceStack o JSON.Net.
swannee

Respuestas:

198

Ciertamente NO :

  • TEXT, NTEXT: esos tipos están en desuso a partir de SQL Server 2005 y no deben usarse para nuevos desarrollos. Use VARCHAR(MAX)o en su NVARCHAR(MAX)lugar

  • IMAGE, VARBINARY(MAX): IMAGEestá en desuso como TEXT/NTEXT, y realmente no tiene sentido almacenar una cadena de texto en una columna binaria ...

De modo que básicamente deja VARCHAR(x)o NVARCHAR(x): VARCHARalmacena cadenas no Unicode (1 byte por carácter) y NVARCHARalmacena todo en un modo Unicode de 2 bytes por carácter. Entonces, ¿necesitas Unicode? ¿Tiene potencialmente caracteres en árabe, hebreo, chino u otros caracteres no europeos occidentales? Entonces ve conNVARCHAR

Las (N)VARCHARcolumnas vienen en dos sabores: usted define una longitud máxima que resulta en 8000 bytes o menos ( VARCHARhasta 8000 caracteres, NVARCHARhasta 4000), o si eso no es suficiente, use las (N)VARCHAR(MAX)versiones, que almacenan hasta 2 GByte de datos.

Actualización: SQL Server 2016 tendrá soporte JSON nativo: se introducirá un nuevo JSONtipo de datos (basado en nvarchar), así como un FOR JSONcomando para convertir la salida de una consulta al formato JSON

Actualización n. ° 2: en el producto final, Microsoft no incluyó un JSONtipo de datos separado ; en cambio, hay una serie de funciones JSON (para agrupar las filas de la base de datos en JSON o analizar JSON en datos relacionales) que operan en columnas de tipoNVARCHAR(n)

marc_s
fuente
25
NVARCHAR debería ser la opción preferida ya que SQL Server 2016 lo usará para su blog
Loudenvier
@marc_s ¿Es correcta su declaración de "actualización"? No puedo encontrar ningún tipo de datos JSON oficial ...?
Nix
2
@Nix: Creo que al final, SQL Server admite funciones JSON que operan en NVARCHAR(n)tipos de datos
marc_s
2
Es posible que desee actualizar su respuesta para no indicar que hay un tipo de datos Json
Nix
1
varbinary (max) podría usarse cuando se usa compresión
Marat Gallyamov
31

Iré por nvarchar(max). Eso debería ajustarse al requisito.

Actualización: con SQL Server 2016 y Azure SQL, hay muchas capacidades JSON nativas adicionales. Esto podría impactar positivamente su diseño o enfoque. Puede leer esto para obtener más información: https://docs.microsoft.com/en-us/sql/relational-databases/json/json-data-sql-server

Kangkan
fuente
8
¿ Realmente necesita el almacenamiento Unicode de 2 bytes por carácter? En función de los datos - que sólo podría estar perdiendo el doble de bytes como sea necesario ... (pero si HACE necesidad Unicode - entonces ese es el único camino a seguir, estoy de acuerdo!)
marc_s
55
nvarchar: porque los datos no están definidos. Si creemos que el sistema no necesitará unicode, podemos guardar el cambio a varchar (max)
Kangkan
55
Además, el uso nvarcharevita los problemas de intercalación que eventualmente tendrá al usar varchar, pero será más lento en el rendimiento de la consulta que varchar. Gran pregunta de DBA con más información.
Scotty.NET
55
¿Cómo obtuvo esta pregunta tantos votos positivos? Entonces dice qué tipo de datos usar, está bien ... pero ni siquiera trata de explicar por qué esa sería la elección correcta.
stakx - ya no contribuye
1
Siempre puede usar varchar y escapar de cualquier carácter unicode. Este es un buen enfoque si solo tendrá caracteres unicode ocasionales en su texto, ya que ahorra espacio al usar un nvarchar
chrisb
3

Recomendaría usar nvarchar(max)si planea usar características JSON en SQL 2016 o Azure SQL.

Si no planea usar esas características, puede usarlas varbinary(max)combinadas con COMPRESS(y DECOMPRESS) funciones. Más información: https://blogs.msdn.microsoft.com/sqlserverstorageengine/2015/11/23/storing-json-in-sql-server/

Las funciones COMPRESS y DECOMPRESS usan compresión GZip estándar. Si su cliente puede manejar la compresión GZip (por ejemplo, un navegador que comprende el contenido gzip), puede devolver directamente el contenido comprimido. Tenga en cuenta que esto es una compensación de rendimiento / almacenamiento. Si consulta con frecuencia datos comprimidos, migra tiene un rendimiento más lento porque el texto debe descomprimirse cada vez.

Marat Gallyamov
fuente
¿Cuáles son las características de JSON en SQL 2016 ?
Kiquenet
0

nvarchar (max) es mejor para esto, también una cosa más que puedes hacer así.

public class TableName
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }
     
    public string FieldJson { get; set; }   //save json in this field and
      
    [NotMapped]
    public List<FieldList> FieldList  // get return list from this properity
    {
        get => !string.IsNullOrEmpty(FieldJson) ? JsonConvert.DeserializeObject<List<FieldList>>(FieldJson) : null; 
    }

   
}
Davinder Singh
fuente