Advanced Usage

## AsyncClient wrapper[​](#asyncclient-wrapper "Direct link to AsyncClient wrapper")

ClickHouse Connect provides an async wrapper over the regular `Client`, so that it is possible to use the client in an `asyncio` environment.

To get an instance of the `AsyncClient`, you can use the `get_async_client` factory function, which accepts the same parameters as the standard `get_client`:

```
import asyncio

import clickhouse_connect


async def main():
    client = await clickhouse_connect.get_async_client()
    result = await client.query("SELECT name FROM system.databases LIMIT 1")
    print(result.result_rows)
    # Output:
    # [('INFORMATION_SCHEMA',)]

asyncio.run(main())
```

`AsyncClient` has the same methods with the same parameters as the standard `Client`, but they're coroutines when applicable. Internally, these methods from the `Client` that perform I/O operations are wrapped in a [run\_in\_executor](https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor) call.

Multithreaded performance will increase when using the `AsyncClient` wrapper, as the execution threads and the GIL will be released while waiting for I/O operations to complete.

Note: Unlike the regular `Client`, the `AsyncClient` enforces `autogenerate_session_id` to be `False` by default.

See also: [run\_async example](https://github.com/ClickHouse/clickhouse-connect/blob/main/examples/run_async.py).

## Managing ClickHouse session IDs[​](#managing-clickhouse-session-ids "Direct link to Managing ClickHouse session IDs")

Each ClickHouse query occurs within the context of a ClickHouse "session". Sessions are currently used for two purposes:

- To associate specific ClickHouse settings with multiple queries (see the [user settings](/docs/operations/settings/settings)). The ClickHouse `SET` command is used to change the settings for the scope of a user session.
- To track [temporary tables.](/docs/sql-reference/statements/create/table#temporary-tables)

By default, each query executed with a ClickHouse Connect `Client` instance uses that client's session ID. `SET` statements and temporary tables work as expected when using a single client. However, the ClickHouse server doesn't allow concurrent queries within the same session (the client will raise a `ProgrammingError` if attempted). For applications that execute concurrent queries, use one of the following patterns:

1. Create a separate `Client` instance for each thread/process/event handler that needs session isolation. This preserves per-client session state (temporary tables and `SET` values).
2. Use a unique `session_id` for each query via the `settings` argument when calling `query`, `command`, or `insert`, if you don't require shared session state.
3. Disable sessions on a shared client by setting `autogenerate_session_id=False` before creating the client (or pass it directly to `get_client`).

```
from clickhouse_connect import common
import clickhouse_connect

common.set_setting('autogenerate_session_id', False)  # This should always be set before creating a client
client = clickhouse_connect.get_client(host='somehost.com', user='dbuser', password=1234)
```

Alternatively, pass `autogenerate_session_id=False` directly to `get_client(...)`.

In this case ClickHouse Connect doesn't send a `session_id`; the server doesn't treat separate requests as belonging to the same session. Temporary tables and session-level settings won't persist across requests.

## Customizing the HTTP connection pool[​](#customizing-the-http-connection-pool "Direct link to Customizing the HTTP connection pool")

ClickHouse Connect uses `urllib3` connection pools to handle the underlying HTTP connection to the server. By default, all client instances share the same connection pool, which is sufficient for the majority of use cases. This default pool maintains up to 8 HTTP Keep Alive connections to each ClickHouse server used by the application.

For large multi-threaded applications, separate connection pools may be appropriate. Customized connection pools can be provided as the `pool_mgr` keyword argument to the main `clickhouse_connect.get_client` function:

```
import clickhouse_connect
from clickhouse_connect.driver import httputil

big_pool_mgr = httputil.get_pool_manager(maxsize=16, num_pools=12)

client1 = clickhouse_connect.get_client(pool_mgr=big_pool_mgr)
client2 = clickhouse_connect.get_client(pool_mgr=big_pool_mgr)
```

As demonstrated by the above example, clients can share a pool manager, or a separate pool manager can be created for each client. For more details on the options available when creating a PoolManager, see the [`urllib3` documentation](https://urllib3.readthedocs.io/en/stable/advanced-usage.html#customizing-pool-behavior).

- [Raw API](#raw-api)
  - [Client `raw_query` method](#client-rawquery-method)- [Client `raw_stream` method](#client-rawstream-method)- [Client `raw_insert` method](#client-rawinsert-method)- [Saving query results as files](#saving-query-results-as-files)- [Multithreaded, multiprocess, and async/event driven use cases](#multithreaded-multiprocess-and-asyncevent-driven-use-cases)- [AsyncClient wrapper](#asyncclient-wrapper)- [Managing ClickHouse session IDs](#managing-clickhouse-session-ids)- [Customizing the HTTP connection pool](#customizing-the-http-connection-pool)

Was this page helpful?