Skip to content

Fast & Furious (JSON Support)

Choose a tag to compare

@yv989c yv989c released this 07 Oct 03:56
· 19 commits to main since this release
4635414

Summary

QueryableValues achieves its performance by relying on parameterized T-SQL queries. This is achieved by taking advantage of the XML data type support in SQL Server, which is available in all the supported versions of SQL Server to date. JSON support was introduced in SQL Server 2016, and it provides better query performance when compared to its XML counterpart.

This version adds support for JSON as an alternative to XML. When available, it provides a significant performance boost on certain scenarios as shown in the benchmarks below.

JSON support is available when the following is true:

  • The SQL Server instance is 2016 and above.
  • The database has its compatibility level set to 130 or higher.

Configuration

By default, this version of QueryableValues automatically detects if JSON can be used, otherwise it falls back to XML. This behavior can be configured via the QueryableValuesConfigurator class:

QueryableValuesConfigurator
    .Configure()
    .Serialization(SerializationOptions.Auto);

The Configure method also allows you to specify the configuration on a per DbContext fashion:

QueryableValuesConfigurator
    .Configure<MyDbContext>()
    .Serialization(SerializationOptions.Auto);

You may want to use SerializationOptions.UseJson if you know that your environment does support JSON, or SerializationOptions.UseXml if it does not. By not using SerializationOptions.Auto you can avoid a one-time initial roundtrip that is done to detect JSON support (this only happens once per connection string).

Benchmarks

These benchmarks are using XML as the baseline for the Int32, String, and Guid data types. They consist of a query that does a JOIN between a table and a set of values via the AsQueryableValues extension method. The benchmarks can be found in the benchmarks directory of this repository.

The most dramatic performance gains can be observed on the Int32 data type, particularly between 1024 and 16384 values. At 16384 we can see that JSON is up to 13.25x faster than XML.

System

BenchmarkDotNet=v0.13.2, OS=Windows 11 (10.0.22621.521)
AMD Ryzen 9 6900HS Creator Edition, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.400
  [Host]     : .NET 6.0.8 (6.0.822.36306), X64 RyuJIT AVX2
  Job-CHWPLZ : .NET 6.0.8 (6.0.822.36306), X64 RyuJIT AVX2

Runtime=.NET 6.0  Server=True  InvocationCount=12  
IterationCount=10  RunStrategy=Monitoring  UnrollFactor=1  
WarmupCount=1  

SQL Server Instance (running on the same computer)

Microsoft SQL Server 2019 (RTM-CU12) (KB5004524) - 15.0.4153.1 (X64)   Jul 19 2021 15:37:34   Copyright (C) 2019 Microsoft Corporation  Express Edition (64-bit) on Windows 10 Pro 10.0 <X64> (Build 22621: ) (Hypervisor) 
Serializer Type No. of Values Mean Error StdDev Ratio RatioSD
XML Int32 2 898.4 μs 309.83 μs 204.93 μs 1.00 0.00
JSON Int32 2 727.2 μs 95.11 μs 62.91 μs 0.84 0.16
XML Int32 4 864.1 μs 67.88 μs 44.90 μs 1.00 0.00
JSON Int32 4 729.5 μs 56.51 μs 37.38 μs 0.85 0.07
XML Int32 8 897.2 μs 68.45 μs 45.27 μs 1.00 0.00
JSON Int32 8 733.9 μs 46.96 μs 31.06 μs 0.82 0.06
XML Int32 16 1,031.7 μs 358.94 μs 237.41 μs 1.00 0.00
JSON Int32 16 725.5 μs 34.74 μs 22.98 μs 0.73 0.12
XML Int32 32 1,042.6 μs 52.87 μs 34.97 μs 1.00 0.00
JSON Int32 32 732.8 μs 47.17 μs 31.20 μs 0.70 0.04
XML Int32 64 1,295.3 μs 81.40 μs 53.84 μs 1.00 0.00
JSON Int32 64 736.5 μs 47.40 μs 31.35 μs 0.57 0.03
XML Int32 128 1,845.9 μs 408.16 μs 269.98 μs 1.00 0.00
JSON Int32 128 785.5 μs 54.61 μs 36.12 μs 0.43 0.04
XML Int32 256 2,771.4 μs 370.15 μs 244.83 μs 1.00 0.00
JSON Int32 256 814.3 μs 46.68 μs 30.87 μs 0.30 0.03
XML Int32 512 4,887.4 μs 491.57 μs 325.14 μs 1.00 0.00
JSON Int32 512 1,038.1 μs 371.97 μs 246.03 μs 0.21 0.06
XML Int32 1024 8,213.6 μs 430.26 μs 284.59 μs 1.00 0.00
JSON Int32 1024 1,276.8 μs 72.12 μs 47.70 μs 0.16 0.01
XML Int32 2048 14,809.4 μs 420.00 μs 277.81 μs 1.00 0.00
JSON Int32 2048 1,817.0 μs 93.85 μs 62.08 μs 0.12 0.00
XML Int32 4096 27,859.6 μs 224.83 μs 148.71 μs 1.00 0.00
JSON Int32 4096 2,836.3 μs 282.18 μs 186.65 μs 0.10 0.01
XML Int32 8192 53,160.4 μs 623.33 μs 412.29 μs 1.00 0.00
JSON Int32 8192 4,769.1 μs 383.36 μs 253.57 μs 0.09 0.00
XML Int32 16384 106,420.7 μs 624.87 μs 413.31 μs 1.00 0.00
JSON Int32 16384 8,028.5 μs 439.35 μs 290.60 μs 0.08 0.00
XML Int32 32768 211,579.2 μs 4,253.48 μs 2,813.41 μs 1.00 0.00
JSON Int32 32768 45,521.2 μs 571.41 μs 377.95 μs 0.22 0.00
XML Int32 65536 415,989.6 μs 2,353.38 μs 1,556.62 μs 1.00 0.00
JSON Int32 65536 85,472.2 μs 696.38 μs 460.61 μs 0.21 0.00
XML Int32 131072 827,467.1 μs 2,622.26 μs 1,734.46 μs 1.00 0.00
JSON Int32 131072 172,388.8 μs 2,185.62 μs 1,445.65 μs 0.21 0.00
XML String 2 838.1 μs 38.12 μs 25.21 μs 1.00 0.00
JSON String 2 781.2 μs 107.94 μs 71.39 μs 0.93 0.10
XML String 4 850.8 μs 44.99 μs 29.76 μs 1.00 0.00
JSON String 4 740.0 μs 35.80 μs 23.68 μs 0.87 0.04
XML String 8 855.5 μs 54.26 μs 35.89 μs 1.00 0.00
JSON String 8 766.6 μs 47.56 μs 31.45 μs 0.90 0.05
XML String 16 870.5 μs 38.86 μs 25.70 μs 1.00 0.00
JSON String 16 788.9 μs 62.18 μs 41.13 μs 0.91 0.05
XML String 32 969.6 μs 75.21 μs 49.74 μs 1.00 0.00
JSON String 32 829.9 μs 43.18 μs 28.56 μs 0.86 0.05
XML String 64 1,132.2 μs 67.71 μs 44.79 μs 1.00 0.00
JSON String 64 919.4 μs 47.51 μs 31.43 μs 0.81 0.05
XML String 128 1,411.8 μs 111.00 μs 73.42 μs 1.00 0.00
JSON String 128 1,104.9 μs 55.01 μs 36.39 μs 0.78 0.02
XML String 256 2,195.5 μs 88.26 μs 58.38 μs 1.00 0.00
JSON String 256 1,592.6 μs 164.13 μs 108.56 μs 0.73 0.05
XML String 512 3,797.8 μs 369.74 μs 244.56 μs 1.00 0.00
JSON String 512 2,244.4 μs 152.95 μs 101.17 μs 0.59 0.05
XML String 1024 6,130.0 μs 458.77 μs 303.45 μs 1.00 0.00
JSON String 1024 4,436.5 μs 519.10 μs 343.35 μs 0.72 0.05
XML String 2048 10,652.8 μs 818.38 μs 541.31 μs 1.00 0.00
JSON String 2048 7,182.6 μs 863.99 μs 571.48 μs 0.68 0.06
XML String 4096 19,073.8 μs 913.31 μs 604.09 μs 1.00 0.00
JSON String 4096 12,094.1 μs 1,003.52 μs 663.77 μs 0.63 0.02
XML String 8192 36,900.7 μs 378.68 μs 250.47 μs 1.00 0.00
JSON String 8192 32,947.0 μs 1,761.03 μs 1,164.81 μs 0.89 0.03
XML String 16384 71,615.6 μs 584.28 μs 386.46 μs 1.00 0.00
JSON String 16384 59,320.7 μs 998.85 μs 660.68 μs 0.83 0.01
XML String 32768 137,495.2 μs 952.20 μs 629.82 μs 1.00 0.00
JSON String 32768 113,267.7 μs 930.92 μs 615.74 μs 0.82 0.01
XML String 65536 269,414.8 μs 6,212.20 μs 4,108.99 μs 1.00 0.00
JSON String 65536 223,019.1 μs 1,169.58 μs 773.60 μs 0.83 0.01
XML String 131072 533,535.1 μs 8,341.72 μs 5,517.53 μs 1.00 0.00
JSON String 131072 441,343.4 μs 4,939.26 μs 3,267.02 μs 0.83 0.00
XML Guid 2 889.5 μs 41.38 μs 27.37 μs 1.00 0.00
JSON Guid 2 842.8 μs 64.40 μs 42.60 μs 0.95 0.07
XML Guid 4 930.8 μs 64.83 μs 42.88 μs 1.00 0.00
JSON Guid 4 836.1 μs 55.92 μs 36.99 μs 0.90 0.06
XML Guid 8 947.8 μs 78.82 μs 52.14 μs 1.00 0.00
JSON Guid 8 847.8 μs 100.07 μs 66.19 μs 0.90 0.10
XML Guid 16 996.9 μs 76.10 μs 50.34 μs 1.00 0.00
JSON Guid 16 949.3 μs 265.27 μs 175.46 μs 0.95 0.17
XML Guid 32 1,042.2 μs 77.45 μs 51.23 μs 1.00 0.00
JSON Guid 32 869.2 μs 41.48 μs 27.44 μs 0.84 0.04
XML Guid 64 1,133.6 μs 53.92 μs 35.66 μs 1.00 0.00
JSON Guid 64 900.6 μs 58.49 μs 38.69 μs 0.80 0.04
XML Guid 128 1,338.3 μs 49.86 μs 32.98 μs 1.00 0.00
JSON Guid 128 1,035.6 μs 135.66 μs 89.73 μs 0.77 0.07
XML Guid 256 2,162.5 μs 438.75 μs 290.21 μs 1.00 0.00
JSON Guid 256 1,371.8 μs 373.14 μs 246.81 μs 0.64 0.13
XML Guid 512 3,241.5 μs 247.05 μs 163.41 μs 1.00 0.00
JSON Guid 512 1,622.7 μs 112.37 μs 74.33 μs 0.50 0.03
XML Guid 1024 4,897.7 μs 321.94 μs 212.94 μs 1.00 0.00
JSON Guid 1024 2,346.5 μs 146.43 μs 96.85 μs 0.48 0.03
XML Guid 2048 8,726.8 μs 365.20 μs 241.55 μs 1.00 0.00
JSON Guid 2048 3,954.9 μs 362.21 μs 239.58 μs 0.45 0.03
XML Guid 4096 15,770.8 μs 532.20 μs 352.01 μs 1.00 0.00
JSON Guid 4096 6,148.5 μs 464.99 μs 307.56 μs 0.39 0.02
XML Guid 8192 31,515.9 μs 502.29 μs 332.23 μs 1.00 0.00
JSON Guid 8192 19,518.6 μs 908.79 μs 601.11 μs 0.62 0.02
XML Guid 16384 58,049.5 μs 902.44 μs 596.91 μs 1.00 0.00
JSON Guid 16384 36,028.5 μs 488.03 μs 322.80 μs 0.62 0.01
XML Guid 32768 111,932.4 μs 1,103.80 μs 730.10 μs 1.00 0.00
JSON Guid 32768 67,418.6 μs 739.21 μs 488.94 μs 0.60 0.00
XML Guid 65536 218,151.9 μs 1,353.40 μs 895.19 μs 1.00 0.00
JSON Guid 65536 130,093.4 μs 899.34 μs 594.86 μs 0.60 0.00
XML Guid 131072 431,397.2 μs 3,221.56 μs 2,130.86 μs 1.00 0.00
JSON Guid 131072 253,950.0 μs 1,194.62 μs 790.17 μs 0.59 0.00

Conclusion

I am pretty happy with the results 🙂. Next stop? Add this same feature to BlazarTech.QueryableValues, which is being tracked by yv989c/BlazarTech.QueryableValues#19.

That's all for now. ✌️