Most of the time in a web application, a single API request consists of multiple database queries. For example:
class DashboardsController < ApplicationController
@users = User.some_complex_scope.load_async
@products = Product.some_complex_scope.load_async
@library_files = LibraryFile.some_complex_scope.load_async
Quoting snippet from load_async PR description from rails repository.
The queries are executed synchronously, which mostly isn’t a huge concern. But, as the database grows larger in size, the response time of requests is getting longer. A significant part of the query time is often just I/O waits. Since these two queries are totally independent, ideally you could execute them in parallel, so that assuming that each take 50ms, the total query time would be 50ms rather than 100ms. In the above scenario, the queries can be executed asynchronously, and the time saved on the I/O waits can be reutilized for the next query execution.
load_async method will initiate a new thread to execute the query, which will reduce the wait time. If you use the usual lazy loading way in the controller (without the
load_async method), the loading will not begin until the view references it. But in the case of
load_async, loading will start before it is referenced in the view.
We need to set the value for
async_query_executor in the environment configuration for load_async to work. By default, Rails initializes
nil. The query runs in the foreground if
load_async is called and executor is not defined.
async_query_executor comes with two configuration options.
:global_thread_poolis used to create a common thread pool for all database connections.
# config/environments/development.rb config.active_record.async_query_executor = :global_thread_pool
:multi_thread_poolis used to create a unique thread pool for each database connection.
# config/environments/development.rb config.active_record.async_query_executor = :multi_thread_pool