@@ -35,59 +35,128 @@ const bench = async (client, q, time) => {
3535 }
3636}
3737
38+ // Pipeline mode benchmark - sends N queries concurrently
39+ const benchPipeline = async ( client , q , time , batchSize = 100 ) => {
40+ const start = performance . now ( )
41+ let count = 0
42+ // eslint-disable-next-line no-constant-condition
43+ while ( true ) {
44+ const promises = [ ]
45+ for ( let i = 0 ; i < batchSize ; i ++ ) {
46+ promises . push (
47+ client . query ( {
48+ text : q . text ,
49+ values : q . values ,
50+ rowMode : 'array' ,
51+ } )
52+ )
53+ }
54+ await Promise . all ( promises )
55+ count += batchSize
56+ if ( performance . now ( ) - start > time ) {
57+ return count
58+ }
59+ }
60+ }
61+
3862const run = async ( ) => {
63+ const seconds = 5
64+
65+ console . log ( '=' . repeat ( 60 ) )
66+ console . log ( 'STANDARD MODE BENCHMARK' )
67+ console . log ( '=' . repeat ( 60 ) )
68+
3969 const client = new pg . Client ( )
4070 await client . connect ( )
41- console . log ( 'start' )
4271 await client . query ( 'CREATE TEMP TABLE foobar(name TEXT, age NUMERIC)' )
4372 await client . query ( 'CREATE TEMP TABLE buf(name TEXT, data BYTEA)' )
4473 await bench ( client , params , 1000 )
45- console . log ( 'warmup done' )
46- const seconds = 5
74+ console . log ( 'warmup done\n' )
4775
48- for ( let i = 0 ; i < 4 ; i ++ ) {
49- let queries = await bench ( client , params , seconds * 1000 )
50- console . log ( '' )
51- console . log ( 'param queries:' , queries )
52- console . log ( 'qps' , queries / seconds )
53- console . log ( 'on my laptop best so far seen 987 qps' )
54-
55- queries = await bench ( client , { ...params , name : 'params' } , seconds * 1000 )
56- console . log ( '' )
57- console . log ( 'named queries:' , queries )
58- console . log ( 'qps' , queries / seconds )
59- console . log ( 'on my laptop best so far seen 937 qps' )
60-
61- console . log ( '' )
62- queries = await bench ( client , seq , seconds * 1000 )
63- console . log ( 'sequence queries:' , queries )
64- console . log ( 'qps' , queries / seconds )
65- console . log ( 'on my laptop best so far seen 2725 qps' )
66-
67- console . log ( '' )
68- queries = await bench ( client , insert , seconds * 1000 )
69- console . log ( 'insert queries:' , queries )
70- console . log ( 'qps' , queries / seconds )
71- console . log ( 'on my laptop best so far seen 27383 qps' )
72-
73- console . log ( '' )
74- console . log ( 'Warming up bytea test' )
75- await client . query ( {
76- text : 'INSERT INTO buf(name, data) VALUES ($1, $2)' ,
77- values : [ 'test' , Buffer . allocUnsafe ( 104857600 ) ] ,
78- } )
79- console . log ( 'bytea warmup done' )
80- const start = performance . now ( )
81- const results = await client . query ( 'SELECT * FROM buf' )
82- const time = performance . now ( ) - start
83- console . log ( 'bytea time:' , time , 'ms' )
84- console . log ( 'bytea length:' , results . rows [ 0 ] . data . byteLength , 'bytes' )
85- console . log ( 'on my laptop best so far seen 1407ms and 104857600 bytes' )
86- await new Promise ( ( resolve ) => setTimeout ( resolve , 250 ) )
87- }
76+ let queries = await bench ( client , params , seconds * 1000 )
77+ console . log ( 'param queries:' , queries )
78+ console . log ( 'qps:' , ( queries / seconds ) . toFixed ( 0 ) )
79+
80+ queries = await bench ( client , { ...params , name : 'params' } , seconds * 1000 )
81+ console . log ( '\nnamed queries:' , queries )
82+ console . log ( 'qps:' , ( queries / seconds ) . toFixed ( 0 ) )
83+
84+ queries = await bench ( client , seq , seconds * 1000 )
85+ console . log ( '\nsequence queries:' , queries )
86+ console . log ( 'qps:' , ( queries / seconds ) . toFixed ( 0 ) )
87+
88+ queries = await bench ( client , insert , seconds * 1000 )
89+ console . log ( '\ninsert queries:' , queries )
90+ console . log ( 'qps:' , ( queries / seconds ) . toFixed ( 0 ) )
8891
8992 await client . end ( )
90- await client . end ( )
93+
94+ console . log ( '\n' )
95+ console . log ( '=' . repeat ( 60 ) )
96+ console . log ( 'PIPELINE MODE BENCHMARK' )
97+ console . log ( '=' . repeat ( 60 ) )
98+
99+ const pipelineClient = new pg . Client ( { pipelineMode : true } )
100+ await pipelineClient . connect ( )
101+ await pipelineClient . query ( 'CREATE TEMP TABLE foobar(name TEXT, age NUMERIC)' )
102+ await benchPipeline ( pipelineClient , params , 1000 )
103+ console . log ( 'warmup done\n' )
104+
105+ queries = await benchPipeline ( pipelineClient , params , seconds * 1000 )
106+ console . log ( 'param queries:' , queries )
107+ console . log ( 'qps:' , ( queries / seconds ) . toFixed ( 0 ) )
108+
109+ queries = await benchPipeline ( pipelineClient , { ...params , name : 'params' } , seconds * 1000 )
110+ console . log ( '\nnamed queries:' , queries )
111+ console . log ( 'qps:' , ( queries / seconds ) . toFixed ( 0 ) )
112+
113+ queries = await benchPipeline ( pipelineClient , seq , seconds * 1000 )
114+ console . log ( '\nsequence queries:' , queries )
115+ console . log ( 'qps:' , ( queries / seconds ) . toFixed ( 0 ) )
116+
117+ queries = await benchPipeline ( pipelineClient , insert , seconds * 1000 )
118+ console . log ( '\ninsert queries:' , queries )
119+ console . log ( 'qps:' , ( queries / seconds ) . toFixed ( 0 ) )
120+
121+ await pipelineClient . end ( )
122+
123+ console . log ( '\n' )
124+ console . log ( '=' . repeat ( 60 ) )
125+ console . log ( 'COMPARISON: Sequential vs Pipeline (same workload)' )
126+ console . log ( '=' . repeat ( 60 ) )
127+
128+ // Direct comparison: 1000 queries
129+ const numQueries = 1000
130+
131+ const seqClient = new pg . Client ( )
132+ await seqClient . connect ( )
133+
134+ console . log ( `\nRunning ${ numQueries } sequential queries...` )
135+ let start = performance . now ( )
136+ for ( let i = 0 ; i < numQueries ; i ++ ) {
137+ await seqClient . query ( 'SELECT $1::int as i' , [ i ] )
138+ }
139+ const seqTime = performance . now ( ) - start
140+ console . log ( `Sequential: ${ seqTime . toFixed ( 0 ) } ms (${ ( ( numQueries / seqTime ) * 1000 ) . toFixed ( 0 ) } qps)` )
141+
142+ await seqClient . end ( )
143+
144+ const pipClient = new pg . Client ( { pipelineMode : true } )
145+ await pipClient . connect ( )
146+
147+ console . log ( `Running ${ numQueries } pipeline queries...` )
148+ start = performance . now ( )
149+ const promises = [ ]
150+ for ( let i = 0 ; i < numQueries ; i ++ ) {
151+ promises . push ( pipClient . query ( 'SELECT $1::int as i' , [ i ] ) )
152+ }
153+ await Promise . all ( promises )
154+ const pipTime = performance . now ( ) - start
155+ console . log ( `Pipeline: ${ pipTime . toFixed ( 0 ) } ms (${ ( ( numQueries / pipTime ) * 1000 ) . toFixed ( 0 ) } qps)` )
156+
157+ console . log ( `\nSpeedup: ${ ( seqTime / pipTime ) . toFixed ( 2 ) } x faster` )
158+
159+ await pipClient . end ( )
91160}
92161
93162run ( ) . catch ( ( e ) => console . error ( e ) || process . exit ( - 1 ) )
0 commit comments