A critical factor when considering database retrieval using multithreading is the size/volume of the information that is to be retrieved.
The exchange of data between threads uses a DataStore (DataWindows, as a visual object can only be used in the main, GUI thread because alternate threads are always non-visual), so the data that is retrieved in an alternate thread is placed into a blob via the GetFullState method, the blob gets passed to the main thread via a "callback" non-visual object, then the blob gets loaded into a DataWindow and/or DataStore in the main thread using the SetFullState method.
Although a little complicated, this works well... EXCEPT when the volume of data is large, because multiple in-memory copies of the data have to exist simultaneously within one address space: (1) Inside of the DataStore that retrieves the data, (2) In the one or more blobs used to transfer the data across threads, and (3) In the DataWindow/DataStore in the main thread that ultimately receives the data. The tutorial on Multithreading explains this is greater detail.
In short, multithreaded data retrieval is best suited for retrievals that take a (relatively) long time for the database to complete and not for large volumes of data.
If the database interface you are using in your application supports asynchronous database operations (DBParm: Async=1), I suggest you first examine and consider this option because it is far simpler to implement and it can potentially help to alleviate the user's perception that an application is not performing well. The multithreading example program in CodeXchange I linked to earlier optionally uses asynchronous database operations, either with or without the use of multithreading, provided your database driver/interface supports it (many, but not all, do).
Below is a link to the explanation of the "Async" DBParm setting:
https://docs.appeon.com/pb2021/connection_reference/Database_parameters_and_supported_database_interfaces.html#Async
Good luck!