**Describe the situation**

```
SELECT * FROM test.hits INTO OUTFILE 'dump.csv' FORMAT CSV

8873898 rows in set. Elapsed: 32.487 sec. Processed 8.87 million rows, 8.46 GB (273.15 thousand rows/s., 260.42 MB/s.)
```

is bounded by single CPU core. Too slow :(
/// FIXME: try to prettify this cast using `as<>()`
        const auto * with_output = dynamic_cast<const ASTQueryWithOutput *>(parsed_query.get()
        if (with_output && with_output->settings_ast)
            apply_query_settings(*with_output->settings_ast
        if (!connection->checkConnected())
            connect(
        ASTPtr input_function;
        if (insert && insert->select)
            insert->tryFindInputFunction(input_function
        /// INSERT query for which data transfer is needed (not an INSERT SELECT or input()) is processed separately.
        if (insert && (!insert->select || input_function) && !insert->watch)
        {
            if (input_function && insert->format.empty())
                throw Exception("FORMAT must be specified for function input()", ErrorCodes::INVALID_USAGE_OF_INPUT
            processInsertQuery(query_to_execute, parsed_query
        }
        else
            processOrdinaryQuery(query_to_execute, parsed_query
    }
    /// Do not change context (current DB, settings) in case of an exception.
    if (!have_error)
    {
        if (const auto * set_query = parsed_query->as<ASTSetQuery>())
        {
            /// Save all changes in settings to avoid losing them if the connection is lost.
            for (const auto & change : set_query->changes)
            {
                if (change.name == "profile")
                    current_profile = change.value.safeGet<String>(
                else