The use of the IN clause is grossly inefficient and it is used, not once, but twice. At first, it was causing full table scans. The index creates helped, but that is a band-aid. The query should be rewritten since all tables can easily be joined on the transaction_id column.
Indexes have been added, and budget data access is now sent through SQL logging, so that the times can be found in debug performance logging. Moving forward, we resolved a performance issue with financial rollups and budget transactions. The SQL is as efficient as it can be. The use of joins did not result in a query plan that was any better.