Skip to content

Benchmarks

There are two sets of micro-benchmarks: one testing round trip time for both PGlite and wa-sqlite, and another one based on the SQLite speed test which was ported for the wa-sqlite benchmarks.

We also have a set of native baseline results comparing native SQLite (via the Node better-sqlite3 package) to full Postgres.

Comparing Postgres to SQLite is challenging, as they are quite different databases, particularly when you take into account the complexities of WASM. Therefore, these benchmarks provide a view of performance only as a starting point to investigate the difference between the two, and the improvements we can make going forward.

Another consideration when analysing the speed, is the performance of the various different VFS implementations providing persistance to both PGlite and wa-sqlite.

The key findings are:

  1. wa-sqlite is faster than PGlite when run purely in memory. This is to be expected as it's a simpler database with fewer features; it's designed to go fast. Having said that, PGlite is not slow; it's well within the range you would expect when comparing native SQLite to Postgres.

  2. For single row CRUD inserts and updates, PGlite is faster then wa-sqlite. This is likely due to PGlite using the Postgres WAL, whereas wa-sqlite is only using the SQLite rollback journal mode and not a WAL.

  3. An fsync or flush to the underlying storage can be quite slow, particularly in the browser with IndexedDB for PGlite, or OPFS for wa-sqlite. Both offer some level of "relaxed durability" that can be used to accelerate these queries, and this mode is likely suitable for many embedded use cases.

We plan to continue to use these micro-benchmarks to feed back into the development of PGlite, and update them, and the findings, as we move forward.

These results below were run on an M2 Macbook Air.

Round-trip-time benchmarks

These tests run a series of inserts/updates/deletes to find the average time to execute the type of CRUD operations that are regularly used in an app.

Values are average ms - lower is better.

TestPGlite MemoryPGlite IDBPGlite IDB
relaxed durability
PGlite OPFS AHPPGlite OPFS AHP
relaxed durability
SQLite MemorySQLite IDBSQLite IDB
relaxed durability
SQLite IDB BatchAtomicSQLite IDB BatchAtomic
relaxed durability
SQLite OPFSSQLite OPFS AHP
Test 1: insert small row0.05821.0410.0853.9460.0790.0832.9482.8131.6271.32115.53519.816
Test 2: select small row0.08814.490.1080.1260.0820.0420.6730.7440.4230.4580.8190.03
Test 3: update small row0.07314.5180.0740.0760.0710.0360.5240.5380.4670.5461.1850.016
Test 4: delete small row0.14523.7460.1423.9490.150.12.1962.1111.1180.99915.95420.04
Test 5: insert 1kb row0.07523.6790.083.9630.1150.042.7013.2471.3941.1616.07219.934
Test 6: select 1kb row0.1414.7520.170.1920.1310.0340.5050.4750.3340.350.8010.071
Test 7: update 1kb row0.123.6590.1053.9590.1210.0220.5490.5390.3840.3831.1710.017
Test 8: delete 1kb row0.12523.7520.1244.030.1660.0372.9792.9331.3141.06815.78719.827
Test 9: insert 10kb row0.34523.6040.3484.2510.3630.1223.023.3711.6831.50115.7420.041
Test 10: select 10kb row0.214.6560.1920.2460.2070.0490.5510.6130.4820.4891.5210.091
Test 11: update 10kb row0.32614.7310.3060.3280.3250.0720.5060.5040.4190.4181.1820.083
Test 12: delete 10kb row0.10523.5240.1243.9810.1340.0393.243.2141.4811.23815.79419.884

SQLite benchmark suite

The SQLite benchmark suite, converted to web for wa-sqlite - it performs a number of large queries to test the performance of the sql engine.

Values are seconds to complete the test - lower is better.

TestPGlite
Memory
PGlite
IDB FS
PGlite
IDB FS
relaxed durability
PGlite
OPFS Access Handle Pool
PGlite
OPFS Access Handle Pool
relaxed durability
wa-sqlite
Memory (sync)
wa-sqlite
Memory (async)
wa-sqlite
DB Minimal
wa-sqlite
IDB Minimal
relaxed durability
wa-sqlite
IDB Batch Atomic
wa-sqlite
IDB Batch Atomic
relaxed durability
wa-sqlite
OPFS
wa-sqlite
OPFS Access Handle Pool
Test 1: 1000 INSERTs0.0160.0350.0150.025\0.0350.0512.3842.5881.0940.93918.84724.67
Test 2: 25000 INSERTs in a transaction0.2920.2990.2780.2960.3040.0770.120.140.1050.150.1070.1410.137
Test 3: 25000 INSERTs into an indexed table0.3550.3880.3510.4020.3740.10.1380.230.1850.2280.1980.1740.143
Test 4: 100 SELECTs without an index0.2180.2290.2170.2150.2150.1040.170.1850.2810.1850.2750.2850.103
Test 5: 100 SELECTs on a string comparison0.4850.5040.4820.4820.4840.4510.5460.5490.5530.5460.5480.5450.452
Test 6: Creating an index0.0180.0430.0180.0350.0220.0120.0160.0310.0240.0330.0240.1910.061
Test 7: 5000 SELECTs with an index0.1620.1630.1490.1780.1830.0420.0640.060.0670.0710.0680.0610.044
Test 8: 1000 UPDATEs without an index0.1060.1290.1040.1130.1080.0320.0550.0620.0570.0590.0560.0770.053
Test 9: 25000 UPDATEs with an index0.5470.5790.5370.7270.6850.1310.2110.3910.3640.2580.2190.2740.163
Test 10: 25000 text UPDATEs with an index0.7290.7810.720.9360.8940.1010.1680.3480.3620.2440.2670.230.132
Test 11: INSERTs from a SELECT0.1230.1820.1230.1860.140.0470.0570.3110.330.3470.3580.1710.102
Test 12: DELETE without an index0.0140.0380.0140.0270.0150.020.0230.9150.9361.1481.1460.2220.094
Test 13: DELETE with an index0.020.0430.020.0390.0240.0380.0440.2980.3650.1610.2170.310.065
Test 14: A big INSERT after a big DELETE0.0960.1580.0970.1480.1120.0360.0450.2210.1690.2070.210.1750.084
Test 15: A big DELETE followed by many small INSERTs0.1410.1740.140.1610.140.0310.0430.1380.1380.0830.1370.1890.058
Test 16: DROP TABLE0.0040.0250.0020.0120.0040.0030.0020.0960.1630.0980.1440.610.077

Native baseline

All tests run with Node, Better-SQLite3 and node-postgres (via embedded-postgres)

TestSQLite In-MemorySQLite On-DiskPostgres
Test 1: 1000 INSERTs0.0020.2880.007
Test 2: 25000 INSERTs in a transaction0.0220.0190.114
Test 3: 25000 INSERTs into an indexed table0.0350.040.383
Test 4: 100 SELECTs without an index0.0760.0780.094
Test 5: 100 SELECTs on a string comparison0.2680.4290.259
Test 6: Creating an index0.0070.0110.01
Test 7: 5000 SELECTs with an index0.010.010.078
Test 8: 1000 UPDATEs without an index0.0180.0210.047
Test 9: 25000 UPDATEs with an index0.0470.0560.307
Test 10: 25000 text UPDATEs with an index0.0320.0410.416
Test 11: INSERTs from a SELECT0.0220.0270.072
Test 12: DELETE without an index0.010.0230.007
Test 13: DELETE with an index0.0170.0210.019
Test 14: A big INSERT after a big DELETE0.0170.0210.048
Test 15: A big DELETE followed by many small INSERTs0.0080.010.067
Test 16: DROP TABLE0.0010.0030.004

Run the benchmarks yourself

We have a hosted version of the benchmark runners that you can run yourself:

Additionally, to run the native baseline, checkout the PGlite monorepo, then:

sh
cd ./packages/benchmark
pnpm install
npx tsx baseline.ts