@@ -20,30 +20,191 @@ Used API's are from:
2020
2121## Results
2222
23- Number of successful requests in 50 seconds (higher is better).
23+ Number of successful requests in 50 seconds ** (higher is better)** .
2424
25- | Records | Function | NpgsqlRest AOT (1 ) | NpgsqlRest JIT (2) | PostgREST | Ratio (AOT / PostgREST) | Ratio (JIT / PostgREST) |
25+ | Records | Function | AOT [ 1 ] ( ) | JIT [ 2 ] ( 2 ) | PostgREST | Ratio (AOT / PostgREST) | Ratio (JIT / PostgREST) |
2626| ------: | ---------: | ---------: | --------: | --------: | --------: | --------: |
27- | 10 | ` perf_test ` | 370,415 | 423,408 | 68,021 | 5.45 | 6.22 |
28- | 100 | ` perf_test ` | 352,021 | 400,924 | 59,749 | 5.89 | 6.71 |
29- | 10 | ` perf_test_arrays ` | 276,115 | 310,398 | 51,704 | 5.34 | 6.00 |
30- | 100 | ` perf_test_arrays ` | 275,891 | 289,838 | 49,760 | 5.54 | 5.82 |
31- | 10 | ` perf_test_record ` | 477,001 | 522,165 | 62,392 | 7.65 | 8.37 |
32- | 100 | ` perf_test_record ` | 480,127 | 493,580 | 64,619 | 7.43 | 7.64 |
33- | 10 | ` perf_test_record_arrays ` | 349,336 | 379,135 | 55,602 | 6.28 | 6.82 |
34- | 100 | ` perf_test_record_arrays ` | 356,748 | 362,237 | 51,401 | 6.94 | 7.05 |
35-
36- 1 ) NpgsqlRest AOT is ahead-of-time (AOT) compiled to native code. AOT has an average ** startup time of between 180 to 200 milliseconds.**
37- 2 ) NpgsqlRest JIT is a Just-In-Time (JIT) compilation of Common Intermediate Language (CIL). JIT has an average ** startup time of between 360 to 400 milliseconds.**
27+ | 10 | ` perf_test ` | 423,515 | 606,410 | 72,305 | 5.86 | 8.39 |
28+ | 100 | ` perf_test ` | 100,542 | 126,154 | 40,456 | 2.49 | 3.12 |
29+ | 10 | ` perf_test_arrays ` | 292,489 | 419707 | 55,331 | 5.29 | 7.59 |
30+ | 100 | ` perf_test_arrays ` | 68,316 | 80,906 | 32,418 | 2.10 | 2.50 |
31+ | 10 | ` perf_test_record ` | 482,936 | 657,250 | 61,825 | 7.81 | 10.63 |
32+ | 100 | ` perf_test_record ` | 203,461 | 223,474 | 36,642 | 5.55 | 6.10 |
33+ | 10 | ` perf_test_record_arrays ` | 380,624 | 474,948 | 50,579 | 7.53 | 9.39 |
34+ | 100 | ` perf_test_record_arrays ` | 112,542 | 116,399 | 32,619 | 3.45 | 3.57 |
3835
3936### Other Platforms
4037
41- | Records | Function | NpgsqlRest AOT | NpgsqlRest JIT | Django REST Framework 4.2.10 on Python 3.8 |
42- | ------: | ---------: | ---------: | --------: | --------: |
43- | 10 | ` perf_test ` | 370,415 | 423,408 | 11,476 |
44- | 100 | ` perf_test ` | 352,021 | 400,924 | 11,695 |
45- | 10 | ` perf_test_arrays ` | 276,115| 310,398 | 11,784 |
46- | 100 | ` perf_test_arrays ` | 275,891| 289,838 | 9,575 |
38+ | Records | Function | AOT (1) | JIT (2) | EF | ADO | Django |
39+ | ------: | ---------: | ---------: | --------: | --------: | --------: |
40+ | 10 | ` perf_test ` | 423,515 | 606,410 | 337,612 | 440,896 | 21,193 |
41+ | 100 | ` perf_test ` | 100,542 | 126,154 | 235,331 | 314,198 | 18,345 |
42+ | 10 | ` perf_test_arrays ` | 292,489 | 419,707 | 254,787 | 309,059 | 19,011 |
43+ | 100 | ` perf_test_arrays ` | 68,316 | 80,906 | 113,663 | 130,471 | 11,452 |
44+
45+ #### 1) AOT
46+
47+ NpgsqlRest .NET8 AOT build is ahead-of-time (AOT) compiled to native code. AOT has an average ** startup time of between 180 to 200 milliseconds.**
48+
49+ #### 2) JIT
50+
51+ NpgsqlRest JIT build is a Just-In-Time (JIT) compilation of Common Intermediate Language (CIL). JIT has an average ** startup time of between 360 to 400 milliseconds.**
52+
53+ #### 3) EF
54+
55+ .NET8 Npgsql.EntityFrameworkCore.PostgreSQL 8.0.2
56+
57+ ``` csharp
58+ var builder = WebApplication .CreateBuilder (args );
59+ AppContext .SetSwitch (" Npgsql.EnableLegacyTimestampBehavior" , true );
60+
61+ builder .Services .AddDbContext <DbContext >(options =>
62+ options .UseNpgsql (connectionString ));
63+
64+ var app = builder .Build ();
65+
66+
67+ app .MapPost (" /api/perf_test" , (DbContext dbContext , [FromBody ]Params p ) => dbContext .Database .SqlQuery <Table >(
68+ $" select id1, foo1, bar1, datetime1, id2, foo2, bar2, datetime2, long_foo_bar, is_foobar from perf_test(_records => {p ._records }, _text_param => {p ._text_param }, _int_param => {p ._int_param }, _ts_param => {p ._ts_param }, _bool_param => {p ._bool_param })" ));
69+
70+ app .MapPost (" /api/perf_test_arrays" , (DbContext dbContext , [FromBody ]Params p ) => dbContext .Database .SqlQuery <TableWithArrays >(
71+ $" select id1, foo1, bar1, datetime1, id2, foo2, bar2, datetime2, long_foo_bar, is_foobar from perf_test_arrays(_records => {p ._records }, _text_param => {p ._text_param }, _int_param => {p ._int_param }, _ts_param => {p ._ts_param }, _bool_param => {p ._bool_param })" ));
72+
73+ app .Run ();
74+ ```
75+
76+ #### 4) ADO
77+
78+ .NET8 Raw Data ADO Reader:
79+
80+ ``` csharp
81+ var builder = WebApplication .CreateBuilder (args );
82+ AppContext .SetSwitch (" Npgsql.EnableLegacyTimestampBehavior" , true );
83+
84+ var app = builder .Build ();
85+
86+
87+ app .MapPost (" /api/perf_test" , (DbContext dbContext , [FromBody ]Params p ) => Data .GetTableData (p ));
88+ app .MapPost (" /api/perf_test_arrays" , (DbContext dbContext , [FromBody ]Params p ) => Data .GetTableArrayData (p ));
89+
90+ app .Run ();
91+
92+ static class Data
93+ {
94+ public static async IAsyncEnumerable <Table > GetTableData (Params p )
95+ {
96+ using var connection = new NpgsqlConnection (connectionString );
97+ await connection .OpenAsync ();
98+
99+ using var command = connection .CreateCommand ();
100+ command .CommandText = $" select id1, foo1, bar1, datetime1, id2, foo2, bar2, datetime2, long_foo_bar, is_foobar from perf_test(@_records, @_text_param, @_int_param, @_ts_param, @_bool_param)" ;
101+
102+ command .Parameters .AddWithValue (" _records" , p ._records );
103+ command .Parameters .AddWithValue (" _text_param" , p ._text_param );
104+ command .Parameters .AddWithValue (" _int_param" , p ._int_param );
105+ command .Parameters .AddWithValue (" _ts_param" , p ._ts_param );
106+ command .Parameters .AddWithValue (" _bool_param" , p ._bool_param );
107+
108+ using var reader = await command .ExecuteReaderAsync ();
109+
110+ while (await reader .ReadAsync ())
111+ {
112+ yield return new Table
113+ {
114+ id1 = reader .GetInt32 (0 ),
115+ foo1 = reader .IsDBNull (1 ) ? null : reader .GetString (1 ),
116+ bar1 = reader .IsDBNull (2 ) ? null : reader .GetString (2 ),
117+ datetime1 = reader .GetDateTime (3 ),
118+ id2 = reader .GetInt32 (4 ),
119+ foo2 = reader .IsDBNull (5 ) ? null : reader .GetString (5 ),
120+ bar2 = reader .IsDBNull (6 ) ? null : reader .GetString (6 ),
121+ datetime2 = reader .GetDateTime (7 ),
122+ long_foo_bar = reader .IsDBNull (8 ) ? null : reader .GetString (8 ),
123+ is_foobar = reader .GetBoolean (9 )
124+ };
125+ }
126+ }
127+
128+ public static async IAsyncEnumerable <TableWithArrays > GetTableArrayData (Params p )
129+ {
130+ using var connection = new NpgsqlConnection (connectionString );
131+ await connection .OpenAsync ();
132+
133+ using var command = connection .CreateCommand ();
134+ command .CommandText = $" select id1, foo1, bar1, datetime1, id2, foo2, bar2, datetime2, long_foo_bar, is_foobar from perf_test_arrays(@_records, @_text_param, @_int_param, @_ts_param, @_bool_param)" ;
135+
136+ command .Parameters .AddWithValue (" _records" , p ._records );
137+ command .Parameters .AddWithValue (" _text_param" , p ._text_param );
138+ command .Parameters .AddWithValue (" _int_param" , p ._int_param );
139+ command .Parameters .AddWithValue (" _ts_param" , p ._ts_param );
140+ command .Parameters .AddWithValue (" _bool_param" , p ._bool_param );
141+
142+ using var reader = await command .ExecuteReaderAsync ();
143+ var result = new List <TableWithArrays >();
144+
145+ while (await reader .ReadAsync ())
146+ {
147+ yield return new TableWithArrays
148+ {
149+ id1 = reader .IsDBNull (0 ) ? null : (int [])reader .GetValue (0 ),
150+ foo1 = reader .IsDBNull (1 ) ? null : (string [])reader .GetValue (1 ),
151+ bar1 = reader .IsDBNull (2 ) ? null : (string [])reader .GetValue (2 ),
152+ datetime1 = reader .IsDBNull (3 ) ? null : (DateTime [])reader .GetValue (3 ),
153+ id2 = reader .IsDBNull (4 ) ? null : (int [])reader .GetValue (4 ),
154+ foo2 = reader .IsDBNull (5 ) ? null : (string [])reader .GetValue (5 ),
155+ bar2 = reader .IsDBNull (6 ) ? null : (string [])reader .GetValue (6 ),
156+ datetime2 = reader .IsDBNull (7 ) ? null : (DateTime [])reader .GetValue (7 ),
157+ long_foo_bar = reader .IsDBNull (8 ) ? null : (string [])reader .GetValue (8 ),
158+ is_foobar = reader .IsDBNull (9 ) ? null : (bool [])reader .GetValue (9 )
159+ };
160+ }
161+ }
162+ }
163+ ```
164+
165+ #### 5) Django
166+
167+ Django REST Framework 4.2.10 on Python 3.8
168+
169+ ``` py
170+ from rest_framework.views import APIView
171+ from rest_framework.response import Response
172+ from django.db import connection
173+
174+ class PerfTestView (APIView ):
175+ def post (self , request ):
176+ records = request.data.get(' _records' , 10 )
177+ text_param = request.data.get(' _text_param' , ' abcxyz' )
178+ int_param = request.data.get(' _int_param' , 999 )
179+ ts_param = request.data.get(' _ts_param' , ' 2024-01-01' )
180+ bool_param = request.data.get(' _bool_param' , True )
181+
182+ with connection.cursor() as cursor:
183+ cursor.execute(
184+ " select id1, foo1, bar1, datetime1, id2, foo2, bar2, datetime2, long_foo_bar, is_foobar from perf_test(_records => %s , _text_param => %s , _int_param => %s , _ts_param => %s , _bool_param => %s )" ,
185+ [records, text_param, int_param, ts_param, bool_param])
186+ data = cursor.fetchall()
187+
188+ columns = [col[0 ] for col in cursor.description]
189+ return Response([dict (zip (columns, row)) for row in data])
190+
191+ class PerfTestArrays (APIView ):
192+ def post (self , request ):
193+ records = request.data.get(' _records' , 10 )
194+ text_param = request.data.get(' _text_param' , ' abcxyz' )
195+ int_param = request.data.get(' _int_param' , 999 )
196+ ts_param = request.data.get(' _ts_param' , ' 2024-01-01' )
197+ bool_param = request.data.get(' _bool_param' , True )
198+
199+ with connection.cursor() as cursor:
200+ cursor.execute(
201+ " select id1, foo1, bar1, datetime1, id2, foo2, bar2, datetime2, long_foo_bar, is_foobar from perf_test_arrays(_records => %s , _text_param => %s , _int_param => %s , _ts_param => %s , _bool_param => %s )" ,
202+ [records, text_param, int_param, ts_param, bool_param])
203+ data = cursor.fetchall()
204+
205+ columns = [col[0 ] for col in cursor.description]
206+ return Response([dict (zip (columns, row)) for row in data])
207+ ```
47208
48209## Tests Functions
49210
0 commit comments