[the following is oversimplified to make it easy to understand] In WAL mode, until you reach a checkpoint, SQLite doesn't update the database. All changes are logged in the WAL file. When a checkpoint is processed, SQLite has to go through the log of changes, figure out which ones haven't been obsoleted by later changes, and make appropriate changes to the database file. Then it can start again with a new blank WAL file. That's why the checkpoints are the bottleneck: really SQLite doesn't do much writing between checkpoints. In your situation of many small unpredictable changes, it may be that WAL mode is not the best mode to use. You might be better off with <code>PRAGMA journal_mode = TRUNCATE</code> Perhaps you could try it.