How can I tell if a query runs multi-threaded?

I’m running the following query in QuestDB:

SELECT 
    timestamp,
    first(price) AS open,
    last(price) AS close,
    min(price),
    max(price),
    sum(amount) AS volume
FROM trades
WHERE symbol = 'BTC-USD' AND timestamp > dateadd('d', -1, now())
SAMPLE BY 15m ALIGN TO CALENDAR;

How can I tell that this query uses all available cores on the server?

You should check the execution plan for your query. You can see it by adding EXPLAIN clause at the beginning of the query text:

EXPLAIN SELECT 
    timestamp,
    first(price) AS open,
    last(price) AS close,
    min(price),
    max(price),
    sum(amount) AS volume
FROM trades
WHERE symbol = 'BTC-USD' AND timestamp > dateadd('d', -1, now())
SAMPLE BY 15m ALIGN TO CALENDAR;

If you see Async ... nodes in the output, e.g. Async JIT Group By or Async JIT Filter, it means that the corresponding parts of the query execution plan run in parallel, i.e. on multiple threads.

Note that by default, parallel execution is disabled on machines with less than 4 cores.

Also, in many cases, if your query runs on a single thread, you can rewrite it in a parallel-friendly way. Sometimes this can be as simple as moving the aggregates and the filter from the outer query for the sub-query.

Here is a simple example:

SELECT symbol, sum(price)
FROM (
    SELECT symbol, price FROM trades
    UNION ALL
    SELECT symbol, price FROM trades
)
WHERE symbol = 'BTC-USD';

This query will run single-threaded since the GROUP BY and the filter is applied to a UNION ALL sub-query. But if you rewrite it in the following way, both parts of the sub-query will be handled on multiple threads:

SELECT symbol, sum(price)
FROM (
    SELECT symbol, sum(price) FROM trades
    WHERE symbol = 'BTC-USD'
    UNION ALL
    SELECT symbol, sum(price) FROM trades
    WHERE symbol = 'BTC-USD'
);