Best Practices for Storing and Loading JSON Objects from a Large SQL Server Table Using .NET Core

 Best Practices for Storing and Loading JSON Objects from a Large SQL Server Table Using .NET Core


Introduction


JSON (JavaScript Object Notation) is widely used for storing structured data in SQL Server. However, when dealing with large tables, inefficient handling of JSON data can lead to performance bottlenecks, high storage costs, and slow queries.


In this article, we will cover best practices for saving and loading JSON objects from large SQL Server tables using .NET Core. We will focus on storage strategies, indexing, efficient querying, and optimized data retrieval using Entity Framework Core (EF Core) and Dapper.



---


1. Choosing the Right Storage Strategy


SQL Server supports JSON natively, but choosing the correct storage method depends on your use case.


Option 1: Store JSON as NVARCHAR(MAX) (Best for Flexibility & Simplicity)


✔ Ideal for semi-structured or frequently changing data.

✔ Suitable when you need to store the entire JSON object but rarely query individual fields.


CREATE TABLE Orders (

    OrderID INT IDENTITY PRIMARY KEY,

    CustomerID INT NOT NULL,

    OrderDate DATETIME DEFAULT GETDATE(),

    OrderDetails NVARCHAR(MAX) NULL -- JSON Data

);


Option 2: Store JSON as Normalized Relational Tables (Best for Query Performance & Indexing)


✔ Ideal when you frequently query JSON properties.

✔ Provides better indexing, filtering, and joins.


CREATE TABLE OrderItems (

    OrderItemID INT IDENTITY PRIMARY KEY,

    OrderID INT FOREIGN KEY REFERENCES Orders(OrderID),

    Product NVARCHAR(100),

    Price DECIMAL(10,2),

    Quantity INT

);


Hybrid Approach: Store JSON and Extract Key Fields into Columns


✔ Allows full JSON storage while making key fields indexable.

✔ Balances flexibility and performance.


ALTER TABLE Orders 

ADD FirstProduct AS JSON_VALUE(OrderDetails, '$.items[0].product') PERSISTED;


CREATE INDEX IX_FirstProduct ON Orders (FirstProduct);



---


2. Efficiently Saving JSON Data in .NET Core


Using Entity Framework Core (EF Core)


EF Core does not have native JSON support, but we can store and retrieve JSON using string properties.


Model Class


public class Order

{

    public int OrderID { get; set; }

    public int CustomerID { get; set; }

    public DateTime OrderDate { get; set; }

    public string OrderDetails { get; set; } // JSON stored as string

}


Saving JSON Data in EF Core


var order = new Order

{

    CustomerID = 1,

    OrderDetails = JsonConvert.SerializeObject(new

    {

        items = new[]

        {

            new { product = "Laptop", price = 1200, quantity = 1 },

            new { product = "Mouse", price = 25, quantity = 2 }

        }

    })

};


_dbContext.Orders.Add(order);

await _dbContext.SaveChangesAsync();



---


Using Dapper for High-Performance Inserts


Dapper is faster than EF Core for bulk operations.


using (var conn = new SqlConnection(connectionString))

{

    var sql = "INSERT INTO Orders (CustomerID, OrderDetails) VALUES (@CustomerID, @OrderDetails)";

    await conn.ExecuteAsync(sql, new

    {

        CustomerID = 1,

        OrderDetails = JsonConvert.SerializeObject(new

        {

            items = new[]

            {

                new { product = "Laptop", price = 1200, quantity = 1 },

                new { product = "Mouse", price = 25, quantity = 2 }

            }

        })

    });

}



---


3. Efficiently Loading JSON Data in .NET Core


Using EF Core


var order = await _dbContext.Orders

    .Where(o => o.OrderID == 1)

    .FirstOrDefaultAsync();


var orderDetails = JsonConvert.DeserializeObject<dynamic>(order.OrderDetails);

Console.WriteLine(orderDetails.items[0].product);



---


Using Dapper for Faster JSON Retrieval


using (var conn = new SqlConnection(connectionString))

{

    var order = await conn.QueryFirstOrDefaultAsync<string>(

        "SELECT OrderDetails FROM Orders WHERE OrderID = @id", new { id = 1 });


    var jsonData = JsonConvert.DeserializeObject<dynamic>(order);

    Console.WriteLine(jsonData.items[0].product);

}


✔ Dapper is faster than EF Core for simple queries.

✔ Less overhead compared to EF Core tracking.



---


4. Optimizing JSON Queries in SQL Server


Using JSON_VALUE() for Indexing & Filtering


Extract specific fields from JSON for indexed queries.


SELECT OrderID, JSON_VALUE(OrderDetails, '$.items[0].product') AS FirstProduct

FROM Orders

WHERE JSON_VALUE(OrderDetails, '$.items[0].product') = 'Laptop';



---


Using OPENJSON() for Complex Queries


Extracts nested JSON data into tabular format.


SELECT OrderID, Product, Price, Quantity

FROM Orders

CROSS APPLY OPENJSON(OrderDetails, '$.items')

WITH (

    Product NVARCHAR(100) '$.product',

    Price DECIMAL(10,2) '$.price',

    Quantity INT '$.quantity'

);



---


Indexing JSON Fields for Performance


ALTER TABLE Orders 

ADD FirstProduct AS JSON_VALUE(OrderDetails, '$.items[0].product') PERSISTED;


CREATE INDEX IX_FirstProduct ON Orders (FirstProduct);


✔ Indexes computed columns for fast lookups.

✔ Avoids scanning the entire JSON field.



---


5. Handling Large JSON Objects Efficiently


Using Compression for Large JSON Data


-- Compress JSON before inserting

DECLARE @Compressed VARBINARY(MAX);

SET @Compressed = COMPRESS(N'{"large_json_data": "..." }');


INSERT INTO Orders (CustomerID, OrderDetails) VALUES (1, @Compressed);


To retrieve and decompress:


SELECT OrderID, CAST(DECOMPRESS(OrderDetails) AS NVARCHAR(MAX)) AS OrderDetails

FROM Orders;


✔ Reduces storage size by up to 70%.

✔ Faster I/O operations for large JSON fields.



---


6. Avoiding Common Pitfalls


❌ Avoid storing too much JSON in a single row – Split large JSON objects into relational tables if necessary.


❌ Avoid frequent updates on JSON fields – Updates require rewriting the entire JSON field, leading to performance issues.


❌ Don’t overuse JSON functions in WHERE clauses – Instead, index computed columns for better performance.



---


Conclusion


Storing and loading JSON in SQL Server with .NET Core requires careful planning to ensure optimal performance.


Key Takeaways:


✔ Store JSON as NVARCHAR(MAX) for flexibility.

✔ Use JSON_VALUE() and OPENJSON() for efficient querying.

✔ Index computed columns for faster searches.

✔ Use Dapper for performance-critical operations.

✔ Compress JSON when dealing with very large objects.



By following these best practices, you can build scalable, high-performance applications that efficiently handle JSON data in large SQL Server tables.


Comments

Popular posts from this blog

Maxpooling vs minpooling vs average pooling

Understand the Softmax Function in Minutes

Percentiles, Deciles, and Quartiles