perf(transactions): add kind to Transaction model and remove expensive Transfer joins in aggregations
#2388
Reference in New Issue
Block a user
Delete Branch "zachgoll/perf-transactions-index"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
This PR primarily aims to improve the performance of
/transactions, but serves a dual purpose:Transferjoin queries by addingkindfield toTransactionPerformance Benchmarks
This PR optimizes IncomeStatement queries by eliminating complex transfer joins and replacing them with simple
kindfiltering, achieving significant performance improvements.Summary
/transactions)[WARM] 2.180 i/s
[WARM] 2.139 i/s
Production Endpoint Benchmarks
Measured with
derailed_benchmarksin production-like environment/transactionsEndpointBefore Optimization:
After Optimization:
Performance issues overview
Prior to this PR, the
/transactionsendpoint was patched in #2372 to load faster on the "warm" path, but those fixes were temporary by nature and did not address the root cause of the slowness.By adding a denormalized
kindfield to theTransactionmodel, our queries could be drastically simplified and we can defer the complex join logic for detecting various Transfer types to the write side (background jobs) while keeping the read side simple, indexable (was not possible before), and performant.This PR improves
/transactionssignificantly on the cold path.Splits and Fees (not in PR scope)
The full enum we'll likely use moving forward:
The
kindfield largely answers two questions:This field provides a lot of flexibility and opens us up to start incorporating concepts like splits and fees (future PR).
Bug: Transfer Status Inconsistency
The template inconsistently uses
transaction.transfer?(enum-basedkind) andtransaction.transfer.present?(association presence) to determine transfer status. This can lead to UI inconsistencies such as incorrect checkboxdisabledstates, misdirected links (e.g., linking toentry_pathinstead of a transfer path), and inconsistent display of transfer-specific UI elements. The discrepancy arises when a transaction'skindindicates a transfer but noTransferrecord is associated, or vice-versa, potentially causing nil errors.app/views/transactions/_transaction.html.erb#L12-L73ec7882b09c/app/views/transactions/_transaction.html.erb (L12-L73)Fix in Cursor
Was this report helpful? Give feedback by reacting with 👍 or 👎
Bug: Inconsistent Transfer Detection Causes UI Issues
The view uses inconsistent logic for detecting transfers. It mixes
transaction.transfer.present?(which checks the association) withtransaction.transfer?(which checks thekindenum). This affects elements like the checkbox disabling and other display logic, potentially causing divergent UI behavior and negating the performance benefit of thetransaction.transfer?method.app/views/transactions/_transaction.html.erb#L11-L96af0a2b9e92/app/views/transactions/_transaction.html.erb (L11-L96)Fix in Cursor
Bug: Family Ownership Check Fails, Returns Nil
The
set_transfermethod inTransfersControllerincorrectly determines family ownership by only checking theinflow_transaction_id, making transfers with family-ownedoutflow_transactioninaccessible. Furthermore, it returnsnilwhen a transfer is not found or not owned, causingNoMethodErrorinshow,update, anddestroyactions instead of the expectedActiveRecord::RecordNotFound(404).app/controllers/transfers_controller.rb#L52-L58af0a2b9e92/app/controllers/transfers_controller.rb (L52-L58)Fix in Cursor
Was this report helpful? Give feedback by reacting with 👍 or 👎