1010using System . Threading . Tasks ;
1111using Microsoft . Extensions . Caching . Memory ;
1212using Npgsql ;
13+ using NpgsqlTypes ;
1314
1415namespace PlatformBenchmarks ;
1516
1617public sealed class RawDb
1718{
18- private readonly ConcurrentRandom _random ;
1919 private readonly MemoryCache _cache
2020 = new ( new MemoryCacheOptions { ExpirationScanFrequency = TimeSpan . FromMinutes ( 60 ) } ) ;
2121
2222 private readonly NpgsqlDataSource _dataSource ;
2323
24- public RawDb ( ConcurrentRandom random , AppSettings appSettings )
24+ public RawDb ( AppSettings appSettings )
2525 {
26- _random = random ;
27- _dataSource = NpgsqlDataSource . Create ( appSettings . ConnectionString ) ;
26+ _dataSource = new NpgsqlSlimDataSourceBuilder ( appSettings . ConnectionString ) . EnableArrays ( ) . Build ( ) ;
2827 }
2928
3029 public async Task < World > LoadSingleQueryRow ( )
@@ -42,10 +41,10 @@ public Task<CachedWorld[]> LoadCachedQueries(int count)
4241 var result = new CachedWorld [ count ] ;
4342 var cacheKeys = _cacheKeys ;
4443 var cache = _cache ;
45- var random = _random ;
44+
4645 for ( var i = 0 ; i < result . Length ; i ++ )
4746 {
48- var id = random . Next ( 1 , 10001 ) ;
47+ var id = Random . Shared . Next ( 1 , 10001 ) ;
4948 var key = cacheKeys [ id ] ;
5049 if ( cache . TryGetValue ( key , out var cached ) )
5150 {
@@ -76,7 +75,7 @@ static async Task<CachedWorld[]> LoadUncachedQueries(int id, int i, int count, R
7675 {
7776 result [ i ] = await rawdb . _cache . GetOrCreateAsync ( key , create ) ;
7877
79- id = rawdb . _random . Next ( 1 , 10001 ) ;
78+ id = Random . Shared . Next ( 1 , 10001 ) ;
8079 idParameter . TypedValue = id ;
8180 key = cacheKeys [ id ] ;
8281 }
@@ -109,30 +108,18 @@ public async Task<World[]> LoadMultipleQueriesRows(int count)
109108
110109 using var connection = await _dataSource . OpenConnectionAsync ( ) ;
111110
112- using var batch = new NpgsqlBatch ( connection )
113- {
114- // Inserts a PG Sync message between each statement in the batch, required for compliance with
115- // TechEmpower general test requirement 7
116- // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview
117- EnableErrorBarriers = true
118- } ;
119-
120- for ( var i = 0 ; i < count ; i ++ )
111+ // It is not acceptable to execute multiple SELECTs within a single complex query.
112+ // It is not acceptable to retrieve all required rows using a SELECT ... WHERE id IN (...) clause.
113+ // Pipelining of network traffic between the application and database is permitted.
114+
115+ var ( queryCmd , queryParameter ) = CreateReadCommand ( connection ) ;
116+ using ( queryCmd )
121117 {
122- batch . BatchCommands . Add ( new ( )
118+ for ( var i = 0 ; i < results . Length ; i ++ )
123119 {
124- CommandText = "SELECT id, randomnumber FROM world WHERE id = $1" ,
125- Parameters = { new NpgsqlParameter < int > { TypedValue = _random . Next ( 1 , 10001 ) } }
126- } ) ;
127- }
128-
129- using var reader = await batch . ExecuteReaderAsync ( ) ;
130-
131- for ( var i = 0 ; i < count ; i ++ )
132- {
133- await reader . ReadAsync ( ) ;
134- results [ i ] = new World { Id = reader . GetInt32 ( 0 ) , RandomNumber = reader . GetInt32 ( 1 ) } ;
135- await reader . NextResultAsync ( ) ;
120+ queryParameter . TypedValue = Random . Shared . Next ( 1 , 10001 ) ;
121+ results [ i ] = await ReadSingleRow ( queryCmd ) ;
122+ }
136123 }
137124
138125 return results ;
@@ -142,33 +129,44 @@ public async Task<World[]> LoadMultipleUpdatesRows(int count)
142129 {
143130 var results = new World [ count ] ;
144131
132+ var ids = new int [ count ] ;
133+ for ( var i = 0 ; i < count ; i ++ )
134+ {
135+ ids [ i ] = Random . Shared . Next ( 1 , 10001 ) ;
136+ }
137+ Array . Sort ( ids ) ;
138+
145139 using var connection = CreateConnection ( ) ;
146140 await connection . OpenAsync ( ) ;
147141
142+ // Each row must be selected randomly using one query in the same fashion as the single database query test
143+ // Use of IN clauses or similar means to consolidate multiple queries into one operation is not permitted.
144+ // Similarly, use of a batch or multiple SELECTs within a single statement are not permitted
148145 var ( queryCmd , queryParameter ) = CreateReadCommand ( connection ) ;
149146 using ( queryCmd )
150147 {
151148 for ( var i = 0 ; i < results . Length ; i ++ )
152149 {
150+ queryParameter . TypedValue = ids [ i ] ;
153151 results [ i ] = await ReadSingleRow ( queryCmd ) ;
154- queryParameter . TypedValue = _random . Next ( 1 , 10001 ) ;
155152 }
156153 }
157154
158- using ( var updateCmd = new NpgsqlCommand ( BatchUpdateString . Query ( count ) , connection ) )
155+ var numbers = new int [ count ] ;
156+ for ( var i = 0 ; i < count ; i ++ )
159157 {
160- for ( var i = 0 ; i < results . Length ; i ++ )
161- {
162- var randomNumber = _random . Next ( 1 , 10001 ) ;
158+ var randomNumber = Random . Shared . Next ( 1 , 10001 ) ;
159+ results [ i ] . RandomNumber = randomNumber ;
160+ numbers [ i ] = randomNumber ;
161+ }
163162
164- updateCmd . Parameters . Add ( new NpgsqlParameter < int > { TypedValue = results [ i ] . Id } ) ;
165- updateCmd . Parameters . Add ( new NpgsqlParameter < int > { TypedValue = randomNumber } ) ;
163+ var update = "UPDATE world w SET randomnumber = u.new_val FROM (SELECT unnest($1) as id, unnest($2) as new_val) u WHERE w.id = u.id" ;
166164
167- results [ i ] . RandomNumber = randomNumber ;
168- }
165+ using var updateCmd = new NpgsqlCommand ( update , connection ) ;
166+ updateCmd . Parameters . Add ( new NpgsqlParameter < int [ ] > { TypedValue = ids , NpgsqlDbType = NpgsqlDbType . Array | NpgsqlDbType . Integer } ) ;
167+ updateCmd . Parameters . Add ( new NpgsqlParameter < int [ ] > { TypedValue = numbers , NpgsqlDbType = NpgsqlDbType . Array | NpgsqlDbType . Integer } ) ;
169168
170- await updateCmd . ExecuteNonQueryAsync ( ) ;
171- }
169+ await updateCmd . ExecuteNonQueryAsync ( ) ;
172170
173171 return results ;
174172 }
@@ -203,7 +201,7 @@ public async Task<List<FortuneUtf8>> LoadFortunesRows()
203201 private ( NpgsqlCommand readCmd , NpgsqlParameter < int > idParameter ) CreateReadCommand ( NpgsqlConnection connection )
204202 {
205203 var cmd = new NpgsqlCommand ( "SELECT id, randomnumber FROM world WHERE id = $1" , connection ) ;
206- var parameter = new NpgsqlParameter < int > { TypedValue = _random . Next ( 1 , 10001 ) } ;
204+ var parameter = new NpgsqlParameter < int > { TypedValue = Random . Shared . Next ( 1 , 10001 ) } ;
207205
208206 cmd . Parameters . Add ( parameter ) ;
209207
0 commit comments