Refactor link expansion to avoid N+1 queries

This improved expansion of 100 items from c. 190ms to c. 30ms in testing on my dev VM.

This also adds a relative performance test around this behaviour.  I'm a little concerned that this could lead to spurious test failures if CI is being slow momentarily.  I'd appreciate other opinions on this.
Also, should it exclude unpublished items?  It would be reasonable to address both of these comments in a separate pull request, though, since the behaviour in this area is unchanged by this PR.