https://github.com/zendesk/predictive_load
https://github.com/zendesk/predictive_load
Last synced: 9 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/zendesk/predictive_load
- Owner: zendesk
- License: apache-2.0
- Created: 2013-12-27T23:39:17.000Z (over 12 years ago)
- Default Branch: master
- Last Pushed: 2024-10-06T22:56:21.000Z (over 1 year ago)
- Last Synced: 2025-04-01T19:09:21.915Z (over 1 year ago)
- Language: Ruby
- Size: 124 KB
- Stars: 11
- Watchers: 297
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
[](https://github.com/zendesk/predictive_load/actions/workflows/actions.yml)
predictive_load
===============
Observes Active Record collections and notifies when a member loads an association. This allows for:
* automatically preloading the association in a single query for all members of that collection.
* N+1 detection logging
### Automatic preloading
```ruby
require 'predictive_load'
require 'predictive_load/active_record_collection_observation'
ActiveRecord::Base.include(PredictiveLoad::ActiveRecordCollectionObservation)
require 'predictive_load/loader'
ActiveRecord::Relation.collection_observer = PredictiveLoad::Loader
Ticket.all.each do |ticket|
ticket.requester.identities.each { |identity| identity.account }
end
```
Produces:
```sql
SELECT `tickets`.* FROM `tickets`
SELECT `requesters`.* FROM `requesters` WHERE `requesters`.`id` IN (2, 7, 12, 32, 37)
SELECT `identities`.* FROM `identities` WHERE `identities`.`requester_id` IN (2, 7, 12, 32, 37)
SELECT `accounts`.* FROM `accounts` WHERE `accounts`.`id` IN (1, 2, 3)
```
### Disabling preload
Some things cannot be preloaded, use `predictive_load: false`
```
has_many :foos, predictive_load: false
```
### Instrumentation
The library can be instrumented by providing a callback, to be invoked every time automatic preloading happens. The callback must be a callable that receives two arguments:
* The record (instance) on which the queries that triggered automatic preloading are being performed, in the form of some association call.
* The association object, which can be inspected to check the type and name of the association.
For example, the callback could be used to emit some metrics:
```ruby
require "active_support/core_ext/string"
PredictiveLoad.callback = -> (record, association) do
METRICS_CLIENT.increment_counter(
"active_record.automatic_preloads",
tags: [
"model:#{record.class.name.underscore}",
"association:#{association.reflection.name}"
]
)
end
```
#### Known limitations:
* Calling association#size will trigger an N+1 on SELECT COUNT(*). Work around by calling #length, loading all records.
* Calling first / last will trigger an N+1.