Joel,
you can use util_memoize in conjunction with util_multirow_to_list (to stuff query result in the cache) and util_list_to_multirow (to reconstruct the multirow) see this thread:
https://openacs.org/forums/message-view?message_id=77562
Basically what I did was I created a proc that returns the list representation of the query result, wrapped that proc in util_memoize and then applied util_list_to_multirow to get the multirow back.
For cache control, see /acs-admin/cache.