Given two identical tables other than a column defined as either JSON or VARCHAR(MAX), reading the same data from the JSON column appears to be 5-6 times slower than from the VARCHAR column.
To reproduce
using System.Text.Json;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using Microsoft.Data.SqlClient;
BenchmarkRunner.Run<SqlJsonTest>();
[MemoryDiagnoser]
public class SqlJsonTest
{
private readonly SqlConnection _sqlConnection;
public SqlJsonTest()
{
_sqlConnection = new SqlConnection("Server=(local);Database=SqlJsonBenchmark;Trusted_Connection=True;TrustServerCertificate=true");
_sqlConnection.Open();
string[] tables =
[
"ItemJson",
"ItemVarchar"
];
foreach (string table in tables)
{
string tagsColumn = table.EndsWith("Varchar")
? "VARCHAR(MAX) COLLATE Latin1_General_100_BIN2_UTF8 NOT NULL"
: "JSON NOT NULL";
var createTableCommand = _sqlConnection.CreateCommand();
createTableCommand.CommandText = $"""
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.{table}') AND type in (N'U'))
DROP TABLE dbo.{table};
CREATE TABLE {table} (
Id INT IDENTITY(1,1) PRIMARY KEY,
Title VARCHAR(200) NOT NULL,
strings {tagsColumn}
);
""";
_ = createTableCommand.ExecuteNonQuery();
}
foreach (string table in tables)
{
for (int i = 0; i < 500; i++)
{
var insertCommand = _sqlConnection.CreateCommand();
insertCommand.CommandText = $"""
INSERT INTO {table} (Title, strings)
VALUES (@Title, @strings);
""";
_ = insertCommand.Parameters.AddWithValue("@Title", $"Entry {i}");
string[] tags = [.. Enumerable.Range(1, 20).Select(j => new string($"tag{j}"))];
_ = insertCommand.Parameters.AddWithValue("@strings", JsonSerializer.Serialize(tags));
_ = insertCommand.ExecuteNonQuery();
}
}
}
[Benchmark]
public Entry[] ReadEntriesJson()
{
var selectCommand = _sqlConnection.CreateCommand();
selectCommand.CommandText = $"SELECT Id, Title, strings FROM ItemJson";
using var reader = selectCommand.ExecuteReader();
var entries = new List<Entry>();
while (reader.Read())
{
int id = reader.GetInt32(0);
string title = reader.GetString(1);
var tagsJson = reader.GetSqlJson(2);
string[] tags = JsonSerializer.Deserialize<string[]>(tagsJson.Value) ?? [];
entries.Add(new Entry { Id = id, Title = title, Tags = tags });
}
return [.. entries];
}
[Benchmark(Baseline = true)]
public Entry[] ReadEntriesVarchar()
{
var selectCommand = _sqlConnection.CreateCommand();
selectCommand.CommandText = $"SELECT Id, Title, strings FROM ItemVarchar";
using var reader = selectCommand.ExecuteReader();
var entries = new List<Entry>();
while (reader.Read())
{
int id = reader.GetInt32(0);
string title = reader.GetString(1);
string tagsJson = reader.GetString(2);
string[] tags = JsonSerializer.Deserialize<string[]>(tagsJson) ?? [];
entries.Add(new Entry { Id = id, Title = title, Tags = tags });
}
return [.. entries];
}
}
public class Entry
{
public int Id { get; set; }
public required string Title { get; set; }
public required string[] Tags { get; set; }
}
Actual behaviour
// * Summary *
BenchmarkDotNet v0.15.2, Windows 11 (10.0.26120.4741)
Unknown processor
.NET SDK 10.0.100-preview.6.25358.103
[Host] : .NET 10.0.0 (10.0.25.35903), X64 RyuJIT AVX2
DefaultJob : .NET 10.0.0 (10.0.25.35903), X64 RyuJIT AVX2
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Allocated | Alloc Ratio |
|------------------- |-----------:|---------:|---------:|------:|--------:|--------:|--------:|----------:|------------:|
| ReadEntriesJson | 2,516.4 us | 30.39 us | 31.21 us | 5.82 | 0.13 | 58.5938 | 39.0625 | 1.11 MB | 1.04 |
| ReadEntriesVarchar | 432.8 us | 7.77 us | 8.32 us | 1.00 | 0.03 | 59.0820 | 38.5742 | 1.07 MB | 1.00 |
Expected behaviour
Similar, if not better, performance for reading JSON.
Further technical details
Microsoft.Data.SqlClient version: 6.1.0-preview2.25178.5
.NET target: 10.0.100-preview.6.25358.103
SQL Server version: SQL Server 2025 (17.0.800.3)
Operating system: Windows 11 (10.0.26120.4741)
Discussion
Is this perhaps due to the cost of parsing JSON every time a SqlJson instance is created?
|
// Ask JsonDocument to parse it for validity, or throw. |
|
// |
|
// Note that we do not support trailing commas or comments in the |
|
// JSON. |
|
// |
|
JsonDocument.Parse(jsonString).Dispose(); |
Given two identical tables other than a column defined as either JSON or VARCHAR(MAX), reading the same data from the JSON column appears to be 5-6 times slower than from the VARCHAR column.
To reproduce
Actual behaviour
Expected behaviour
Similar, if not better, performance for reading JSON.
Further technical details
Microsoft.Data.SqlClient version: 6.1.0-preview2.25178.5
.NET target: 10.0.100-preview.6.25358.103
SQL Server version: SQL Server 2025 (17.0.800.3)
Operating system: Windows 11 (10.0.26120.4741)
Discussion
Is this perhaps due to the cost of parsing JSON every time a
SqlJsoninstance is created?SqlClient/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlJson.cs
Lines 38 to 43 in 27aaa9e