Speed up bulk-rendering of Banzai fields that are not cached in the database
Follow-up from https://gitlab.com/gitlab-org/gitlab-ce/issues/43140
tl;dr: rendering commits is slow and still takes too many SQL queries, even after the work that went into https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21500
Banzai, our markdown processor, has an interface to render a collection of objects - `Banzai::ObjectRenderer`. This attempts to reduce the number of SQL queries required to render the collection by aggregating reference lookups across all the documents.
Rendering a document has three steps - running the pipeline to convert markdown to HTML(render); postprocessing; and redaction.
At present, only references in the latter two steps are aggregated. This is because, typically, we only run the first stage once - the content is cached in the database. So while the initial render of a collection of notes is slow, subsequent renders are very fast.
However, we've since extended the `ObjectRenderer` to handle collections of commits. These *do not* have persistent storage associated with them, so the unoptimized render step must run every time the commits are viewed. This is slow and performs needless N+1 SQL queries for users, projects, groups, labels, milestones, epics... anything that can be referenced in GFM.
Two major options present themselves:
* Improve Banzai rendering to aggregate references in the first step
* Add some form of persistent storage to commits
Two options for the second:
* Redis caching
* A database table like:
```ruby
create_table :markdown_column_caches do |t|
t.references :project
t.string :key
t.integer :version # for cache invalidation
t.string :html # the unredacted output
end
```
Either would be fine from my point of view, but perhaps the database team strongly disapproves of the latter proposal.
/cc @DouweM @yorickpeterse @jramsay
issue