Jaki jest najlepszy typ danych SQL do przechowywania ciągu JSON?

127

Jaki jest najlepszy typ danych SQL do przechowywania ciągu 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;
}

Którego typu danych SQL powinniśmy użyć do przechowywania takiego ciągu zawierającego JSON?

  • NVARCHAR(255)?
  • TEXT?
  • VARBINARY(MAX)?
DatPT
źródło
1
Tylko losowy szum (komentarz, nie dane): Możesz też chcieć go skompresować. W takim przypadku potrzebujesz czegoś binarnego. Z drugiej strony: dlaczego po prostu nie zaprojektować odpowiednich tabel dla danych?
The Nail
3
@ The Nail: Czasami przechowywanie czegoś w formacie JSON (lub jako „dokument”) jest odpowiednie dla potrzeb. Podobnie jak w przypadku silnika przepływu pracy lub zarządzania dokumentami itp. Robię to na bieżącym projekcie, właściwie przechodząc od podejścia relacyjnego do podejścia do dokumentów po stronie poleceń mojej implementacji CQRS. Jest bardzo szybki, jeśli używasz serializatora, takiego jak ServiceStack lub JSON.Net.
swannee

Odpowiedzi:

198

Z pewnością NIE :

  • TEXT, NTEXT: te typy są przestarzałe od wersji SQL Server 2005 i nie powinny być używane w nowych programach. Użyj VARCHAR(MAX)lub NVARCHAR(MAX)zamiast

  • IMAGE, VARBINARY(MAX): IMAGEjest przestarzałe, podobnie jak TEXT/NTEXTi naprawdę nie ma sensu przechowywać ciągu tekstowego w kolumnie binarnej ....

Więc zasadniczo pozostawia VARCHAR(x)lub NVARCHAR(x): VARCHARprzechowuje ciągi znaków innych niż Unicode (1 bajt na znak) i NVARCHARprzechowuje wszystko w trybie Unicode 2-bajtowym na znak. Czy potrzebujesz Unicode? Czy masz w swoich ciągach znaków arabski, hebrajski, chiński lub inne znaki spoza Europy Zachodniej? Następnie idź zNVARCHAR

Te (N)VARCHARkolumny są w dwóch smakach: albo zdefiniować maksymalną długość, że wyniki w 8000 bajtów lub mniej ( VARCHARdo 8000 znaków, NVARCHARaż do 4000), a jeśli to nie wystarczy, należy wybrać (N)VARCHAR(MAX)wersje, które pomieszczą do 2 GB danych.

Aktualizacja: SQL Server 2016 będzie miał natywną obsługę JSON - zostanie wprowadzony nowy JSONtyp danych (na którym jest oparty nvarchar), a także FOR JSONpolecenie konwertowania danych wyjściowych z zapytania do formatu JSON

Aktualizacja # 2: w produkcie końcowym Microsoft nie uwzględnił osobnego JSONtypu danych - zamiast tego istnieje szereg funkcji JSON (do pakowania wierszy bazy danych w JSON lub do parsowania JSON w dane relacyjne), które działają na kolumnach typuNVARCHAR(n)

marc_s
źródło
25
NVARCHAR powinien być preferowanym wyborem, ponieważ serwer sql 2016 będzie go używać do natywnej obsługi formatu
Loudenvier
@marc_s Czy Twoje oświadczenie dotyczące aktualizacji jest prawidłowe? Nie mogę znaleźć żadnych oficjalnych typów danych JSON ...?
Nix
2
@Nix: Myślę, że ostatecznie SQL Server obsługuje funkcje JSON, które działają na NVARCHAR(n)typach danych
marc_s
2
Możesz zaktualizować swoją odpowiedź, aby nie podawała, że ​​istnieje typ danych Json
Nix
1
varbinary (max) może być używany podczas kompresji
Marat Gallyamov
31

Pójdę po nvarchar(max). To powinno pasować do wymagań.

Aktualizacja: w SQL Server 2016 i Azure SQL jest wiele dodatkowych natywnych możliwości JSON. Może to pozytywnie wpłynąć na Twój projekt lub podejście. Możesz przeczytać to więcej: https://docs.microsoft.com/en-us/sql/relational-databases/json/json-data-sql-server

Kangkan
źródło
8
Czy naprawdę potrzebujesz 2-bajtowego magazynu Unicode na znak? W zależności od danych - może to być po prostu tracić dwa razy tyle bajtów, ile potrzeba ... (ale jeśli NIE POTRZEBUJESZ Unicode - to jest to jedyna droga, zgadzam się!)
marc_s
5
nvarchar - ponieważ dane nie są zdefiniowane. Jeśli uznamy, że system nie będzie potrzebował Unicode, możemy zaoszczędzić przechodząc do varchar (max)
Kangkan
5
Ponadto użycie nvarcharpozwala uniknąć problemów z sortowaniem, które ostatecznie pojawią się podczas używania varchar, ale będzie wolniejsze w wykonywaniu zapytań niż varchar. Świetne pytanie DBA z dalszymi informacjami.
Scotty.NET
5
Jak to pytanie zyskało tyle pozytywnych głosów? Mówi więc, jakiego typu danych użyć, dobrze ... ale nawet nie próbuje wyjaśnić, dlaczego byłby to właściwy wybór.
stakx - nie publikuje już
1
Zawsze możesz użyć varchar i uciec przed wszystkimi znakami Unicode. Jest to dobre podejście, jeśli w tekście będziesz mieć tylko sporadyczne znaki Unicode, ponieważ oszczędza to miejsce przy użyciu nvarchar
chrisb
3

Polecam, nvarchar(max)jeśli planujesz używać funkcji JSON w SQL 2016 lub Azure SQL.

Jeśli nie planujesz korzystać z tych funkcji, możesz użyć varbinary(max)kombinacji z funkcjami COMPRESS(i DECOMPRESS). Więcej informacji: https://blogs.msdn.microsoft.com/sqlserverstorageengine/2015/11/23/storing-json-in-sql-server/

Funkcje COMPRESS i DECOMPRESS używają standardowej kompresji GZip. Jeśli twój klient obsługuje kompresję GZip (np. Przeglądarka, która rozumie zawartość gzip), możesz bezpośrednio zwrócić skompresowaną zawartość. Zauważ, że jest to kompromis między wydajnością a pamięcią masową. Jeśli często wysyłasz zapytania do skompresowanych danych, uzyskasz wolniejszą wydajność, ponieważ tekst musi być dekompresowany za każdym razem.

Marat Gallyamov
źródło
jakie są funkcje JSON w SQL 2016 ?
Kiquenet
0

nvarchar (max) jest do tego lepsze, a także jeszcze jedna rzecz, którą możesz zrobić w ten sposób.

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
źródło