You may now find your database to be your chokepoint on performance.
All the updates flow in while queries for adjacency data is also being pulled.
How you database mechanism interlocks between writes and reads may be making the system run at a fraction of what an optimized solution might do.
The read/write transactions have to be queued (and that queue interlocked). The record updates need to block concurrent read attempts for the adjacency queries
Is it possible to maintain 2 database images - one for the current turn to read (read-only, having been written the previous 'turn')
and a second to receive the object updates (write-only, to be used the next turn for reads). ((NOTE- this also prevents an object arbitrarily reacting/being one turn ahead in its actions.))
The two databases simply flip flop between the two uses (you have to make sure every record is written to the new write DB for every active object and wipe/mark all the just-dead objects)
This scheme eliminates multitude of read/write locks for individual records inside the DB
The update transactions and query results goingto/from the DB process still have to queue/dequeue, but you might manage in/out lockless ringbuffers to dodge alot of wasteful locking overhead. Multiple threads (cores)might do the queries if they are sufficient percentage of the processing.
The entire simulation works in lockstep with your multiple worker cores each working an assigned object lists -- no pulling from a shared list if possible - as thats another resource interlock to avoid (have minor reassignments for load leveling would be done between the different core's work lists).
There still might be a point in the 'turn' processing where complex results (effects from multiple objects must be summed and arbitrated) but if the game mechanics can allow the locked in situation data from the previous turn to compound with results posted to the next turns situation state, it just becomes another phase which can also be processes with locks on individual object datat.