> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-parallel-read-in-order-multi-part.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> ClickHouse Connect의 고급 사용법

# 고급 사용법

<h2 id="raw-api">
  Raw API
</h2>

ClickHouse 데이터와 네이티브 또는 서드파티 데이터 타입 및 구조 간 변환이 필요하지 않은 사용 사례를 위해, ClickHouse Connect 클라이언트는 ClickHouse 연결을 직접 사용할 수 있는 메서드를 제공합니다.

<h3 id="client-rawquery-method">
  Client `raw_query` 메서드
</h3>

`Client.raw_query` 메서드를 사용하면 클라이언트 connection을 통해 ClickHouse HTTP 쿼리 인터페이스를 직접 사용할 수 있습니다. 반환값은 가공되지 않은 `bytes` 객체입니다. 이 메서드는 최소한의 인터페이스로 매개변수 바인딩, 오류 처리, 재시도, 설정 관리를 제공하는 편리한 래퍼입니다.

| 매개변수 | 유형 | 기본값 | 설명 |
| - | - | - | - |
| `query` | str | 필수 | 유효한 모든 ClickHouse 쿼리입니다. |
| `parameters` | dict or sequence | `None` | [매개변수 인수](/ko/integrations/language-clients/python/driver-api#parameters-argument)을 참조하십시오. |
| `settings` | dict | `None` | [설정 인수](/ko/integrations/language-clients/python/driver-api#settings-argument-1)을 참조하십시오. |
| `fmt` | str | `None` | 반환되는 bytes에 사용할 ClickHouse 출력 형식입니다. 지정하지 않으면 ClickHouse는 TSV를 사용합니다. |
| `use_database` | bool | `True` | 클라이언트에 구성된 데이터베이스를 포함합니다. |
| `external_data` | `ExternalData` | `None` | 외부 파일 또는 바이너리 데이터입니다. [외부 데이터](/ko/integrations/language-clients/python/advanced-querying#external-data)를 참조하십시오. |
| `transport_settings` | dict | `None` | 이 요청에 추가되는 HTTP headers입니다. |

반환된 `bytes` 객체는 호출자가 직접 처리해야 합니다. `Client.query_arrow`는 ClickHouse `Arrow` 출력 형식을 사용하는 이 메서드의 얇은 래퍼일 뿐이라는 점에 유의하십시오.

<h3 id="client-rawstream-method">
  Client `raw_stream` 메서드
</h3>

동기식 `Client.raw_stream` 메서드는 `raw_query`와 동일한 API를 사용하지만, 바이트 청크로 이루어진 `io.IOBase` 스트림을 반환합니다. 처리가 완료되면 스트림을 닫으십시오. `AsyncClient.raw_stream`은 await해야 하며, `async with` 및 `async for`와 함께 사용할 수 있는 비동기 `StreamContext`를 반환합니다.

<h3 id="client-rawinsert-method">
  Client `raw_insert` 메서드
</h3>

`Client.raw_insert` 메서드를 사용하면 클라이언트 연결을 통해 `bytes` 객체 또는 `bytes` 객체 생성기를 직접 삽입할 수 있습니다. 이 메서드는 삽입 payload를 별도로 처리하지 않으므로 성능이 매우 뛰어납니다. 또한 설정과 삽입 포맷을 지정하는 옵션을 제공합니다:

| 매개변수 | 유형 | 기본값 | 설명 |
| - | - | - | - |
| `table` | str | Required | 단순 테이블 이름 또는 데이터베이스를 포함한 정규화된 대상 테이블입니다. |
| `column_names` | Sequence\[str] | `None` | 삽입 block의 컬럼 이름입니다. `fmt`에 이름이 포함되지 않으면 필요합니다. |
| `insert_block` | str, bytes, generator, or `BinaryIO` | Required | 삽입할 데이터입니다. 문자열은 클라이언트 인코딩을 사용해 인코딩됩니다. |
| `settings` | dict | `None` | [설정 인수](/ko/integrations/language-clients/python/driver-api#settings-argument-1)를 참조하십시오. |
| `fmt` | str | `None` | `insert_block` payload의 ClickHouse 입력 형식입니다. 포맷을 지정하지 않으면 `네이티브`가 사용됩니다. |
| `compression` | str | `None` | `"gzip"`, `"lz4"`, `"zstd"`와 같이 `insert_block`에 이미 적용된 압축 방식입니다. |
| `transport_settings` | dict | `None` | 이 요청에 추가되는 HTTP headers입니다. |

호출자는 `insert_block`이 지정한 포맷이며 지정한 compression method를 사용하도록 보장할 책임이 있습니다. ClickHouse Connect는 파일 업로드와 PyArrow Tables에 이러한 원시 삽입을 사용하며, parsing은 ClickHouse 서버에 위임합니다.

<h2 id="saving-query-results-as-files">
  쿼리 결과를 파일로 저장하기
</h2>

`raw_stream` 메서드를 사용하면 ClickHouse에서 로컬 파일 시스템으로 파일을 직접 스트리밍할 수 있습니다. 예를 들어, 쿼리 결과를 CSV 파일로 저장하려면 다음 코드 예시를 사용할 수 있습니다.

```python theme={null}
import clickhouse_connect

if __name__ == "__main__":
    client = clickhouse_connect.get_client()
    query = (
        "SELECT number, toString(number) AS number_as_str "
        "FROM system.numbers LIMIT 5"
    )
    stream = client.raw_stream(query=query, fmt="CSVWithNames")
    try:
        with open("output.csv", "wb") as file:
            for chunk in stream:
                file.write(chunk)
    finally:
        stream.close()
        client.close()
```

위 코드를 실행하면 다음 내용이 담긴 `output.csv` 파일이 생성됩니다:

```csv theme={null}
"number","number_as_str"
0,"0"
1,"1"
2,"2"
3,"3"
4,"4"
```

마찬가지로 [TabSeparated](/ko/reference/formats/TabSeparated/TabSeparated) 및 기타 포맷으로도 데이터를 저장할 수 있습니다. 사용 가능한 모든 포맷 옵션의 개요는 [입력 및 출력 데이터 포맷](/ko/reference/formats)에서 확인할 수 있습니다.

<h2 id="multithreaded-multiprocess-and-asyncevent-driven-use-cases">
  멀티스레드, 멀티프로세스 및 async/이벤트 기반 사용 사례
</h2>

ClickHouse Connect는 멀티스레드, 멀티프로세스, 이벤트 루프 기반/비동기 애플리케이션에서 잘 작동합니다. 모든 쿼리 및 삽입 처리는 단일 스레드에서 이루어지므로, 작업은 일반적으로 스레드 안전합니다. (일부 작업을 하위 수준에서 병렬로 처리해 단일 스레드에 따른 성능 저하를 완화하는 기능이 향후 개선 사항으로 추가될 수 있지만, 그 경우에도 스레드 안전성은 유지됩니다.)

각 쿼리 또는 삽입 실행은 각각 자체 `QueryContext` 또는 `InsertContext` 객체에 상태를 유지하므로, 이러한 도우미 객체는 스레드 안전하지 않으며 여러 처리 스트림 간에 공유해서는 안 됩니다. context 객체에 대한 추가 설명은 [QueryContexts](/ko/integrations/language-clients/python/advanced-querying#querycontexts) 및 [InsertContexts](/ko/integrations/language-clients/python/advanced-inserting#insertcontexts) 섹션을 참조하십시오.

또한 애플리케이션에서 2개 이상의 쿼리 및/또는 삽입이 동시에 "진행 중"인 경우에는 추가로 고려해야 할 사항이 2가지 있습니다. 첫 번째는 쿼리/삽입에 연결된 ClickHouse "세션"이고, 두 번째는 ClickHouse Connect Client 인스턴스에서 사용하는 HTTP 연결 풀입니다.

<h2 id="asyncclient">
  AsyncClient
</h2>

ClickHouse Connect는 asyncio 애플리케이션용 네이티브 aiohttp 기반 클라이언트를 제공합니다. 사용하기 전에 선택적 종속성을 설치하십시오:

```bash theme={null}
pip install "clickhouse-connect[async]"
```

`get_async_client`를 await하여 클라이언트를 생성하고 초기화하십시오. `query`, `command`, `insert`와 같은 I/O 메서드는 코루틴입니다:

```python theme={null}
import asyncio

import clickhouse_connect


async def main():
    async with await clickhouse_connect.get_async_client() as client:
        result = await client.query(
            "SELECT name FROM system.databases ORDER BY name LIMIT 1"
        )
        print(result.result_rows)


asyncio.run(main())
```

비동기 클라이언트는 동기 클라이언트와 동일한 쿼리, 삽입, raw, Arrow, 스트리밍 인터페이스를 따릅니다. 네트워크 I/O에는 aiohttp를 사용합니다. CPU 바운드인 네이티브 포맷 파싱은 이벤트 루프를 차단하지 않도록 실행기에서 처리될 수 있습니다.

비동기 클라이언트는 하나의 이벤트 루프에서 생성된 aiohttp 세션을 소유합니다. 클라이언트를 다른 이벤트 루프로 옮기려면 먼저 클라이언트를 소유한 루프에서 닫은 다음, 새 루프에서 요청을 보내기 전에 `await client._initialize()`를 호출하십시오. 소유 루프가 이미 닫혔다면 현재 루프에서 `await client.close()`를 호출한 후 `await client._initialize()`를 호출하십시오. 소유 루프가 닫힌 뒤에야 정리 작업이 시작되면 aiohttp가 닫히지 않은 전송(transport)을 보고할 수 있으므로, 가능하면 다른 루프로 옮기기 전에 클라이언트를 닫으십시오.

반환된 컨텍스트에 들어가기 전에 비동기 스트리밍 메서드를 await해야 합니다:

```python theme={null}
async with await client.query_rows_stream(
    "SELECT number FROM numbers(100000)"
) as stream:
    async for row in stream:
        process(row)
```

동기 팩터리와 달리 `get_async_client`는 여러 코루틴이 동시에 하나의 클라이언트를 공유할 수 있도록 기본적으로 자동 세션 ID를 비활성화합니다. 세션 상태가 필요하고 해당 세션에서 동시 쿼리를 피할 때만 명시적인 `session_id` 또는 `autogenerate_session_id=True`를 전달하십시오.

<h2 id="managing-clickhouse-session-ids">
  ClickHouse 세션 ID 관리
</h2>

각 ClickHouse 쿼리는 ClickHouse "세션" 컨텍스트에서 실행됩니다. 현재 세션은 두 가지 용도로 사용됩니다.

* 여러 쿼리에 특정 ClickHouse 설정을 연결하는 데 사용됩니다([user settings](/ko/reference/settings/session-settings) 참조). 사용자 세션 범위의 설정을 변경하려면 ClickHouse `SET` 명령을 사용합니다.
* [임시 테이블](/ko/reference/statements/create/table#temporary-tables)을 추적하는 데 사용됩니다.

기본적으로 동기 `Client`는 생성된 세션 ID를 사용합니다. `SET` SQL 문과 임시 테이블은 해당 클라이언트의 요청이 동일한 ClickHouse 서버 프로세스에 전달되는 경우에만 요청 간에 유지됩니다. async 팩토리는 기본적으로 세션 ID를 생성하지 않습니다. 이름이 지정된 세션의 상태와 동일 세션 중복 검사는 프로세스 내에서만 적용되며, 클라이언트는 요청을 전송하기 전에 로컬에서 중복을 감지하면 `ProgrammingError`를 발생시킵니다. ClickHouse Cloud 또는 기타 부하 분산 배포 환경에서는 고정된 `session_id`를 분산 상태나 분산 뮤텍스로 사용해서는 안 됩니다. 중복이 문제가 되는 경우 ClickHouse로 요청을 보내기 전에 직렬화하세요. 다음 패턴 중 하나를 사용하세요.

1. 세션 격리가 필요한 각 스레드/프로세스/이벤트 핸들러마다 별도의 `Client` 인스턴스를 생성합니다. 이렇게 하면 클라이언트별 세션 상태(임시 테이블 및 `SET` 값)가 유지됩니다.
2. 공유 세션 상태가 필요하지 않다면, `query`, `command`, 또는 `insert`를 호출할 때 `settings` 인수를 통해 각 쿼리에 고유한 `session_id`를 사용합니다.
3. 공유 클라이언트에서 세션을 비활성화하려면 클라이언트를 생성하기 전에 `autogenerate_session_id=False`로 설정합니다(또는 이를 `get_client`에 직접 전달합니다).

```python theme={null}
import clickhouse_connect
from clickhouse_connect import common

common.set_setting("autogenerate_session_id", False)
client = clickhouse_connect.get_client(
    host="somehost.com",
    username="dbuser",
    password="password",
)
```

또는 `autogenerate_session_id=False`를 `get_client(...)`에 직접 전달할 수 있습니다.

이 경우 ClickHouse Connect는 `session_id`를 전송하지 않으며, 서버는 개별 요청을 동일한 세션에 속한 것으로 처리하지 않습니다. 임시 테이블과 세션 수준 설정은 요청 간에 유지되지 않습니다.

<h2 id="customizing-the-http-connection-pool">
  HTTP 연결 풀 사용자 지정
</h2>

ClickHouse Connect는 서버와의 기본 HTTP 연결을 처리하기 위해 `urllib3` 연결 풀을 사용합니다. 기본적으로 한 프로세스 내의 모든 동기 클라이언트 인스턴스는 동일한 연결 풀을 공유하며, 이는 대부분의 사용 사례에 충분합니다. 각 multiprocessing worker는 프로세스 로컬 기본 풀을 별도로 가지며, 해당 worker에서 생성된 클라이언트들이 이 풀을 재사용합니다. fork 이전에 생성된 클라이언트는 부모 프로세스의 풀을 그대로 유지하므로 자식 프로세스에서 사용해서는 안 됩니다. 기본 풀은 애플리케이션에서 사용하는 각 ClickHouse 서버에 대해 최대 8개의 HTTP Keep Alive 연결을 유지합니다.

기본 소켓 옵션에서는 TCP keepalive와 `TCP_NODELAY`가 활성화되어 있습니다. 소켓 송수신 버퍼 크기는 운영 체제가 관리합니다.

대규모 멀티스레드 애플리케이션에서는 별도의 연결 풀이 더 적합할 수 있습니다. 사용자 지정 연결 풀은 기본 `clickhouse_connect.get_client` 함수에 `pool_mgr` 키워드 인수로 전달할 수 있습니다:

```python theme={null}
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)
```

클라이언트는 풀 관리자를 공유할 수도 있고, 각 클라이언트가 별도의 관리자를 사용할 수도 있습니다. 자세한 내용은 [`urllib3` PoolManager 문서](https://urllib3.readthedocs.io/en/stable/advanced-usage.html#customizing-pool-behavior)를 참조하십시오.

소켓 옵션을 설정하려면 `httputil.get_pool_manager` 또는 `httputil.get_pool_manager_options`에 `socket_options`를 전달하십시오. 이렇게 하면 keepalive 옵션과 `TCP_NODELAY`를 포함한 기본 목록 전체가 대체됩니다. 명시적인 소켓 옵션을 적용하지 않으려면 `[]` 또는 `None`을 전달하십시오.

비동기 클라이언트는 `urllib3` 대신 aiohttp 풀을 사용합니다. `get_async_client`의 `connector_limit`, `connector_limit_per_host`, `keepalive_timeout`을 통해 이를 구성하십시오. `await async_client.close_connections()`를 호출하면 진행 중인 요청을 중단하지 않고 풀이 순환됩니다.

비동기 쿼리와 삽입에서는 사용 가능한 풀 슬롯을 기다리는 데 타임아웃이 적용되지 않습니다. 스트리밍 응답은 끝까지 읽거나 닫아서 풀 슬롯을 반환하십시오. `connect_timeout`은 슬롯을 사용할 수 있게 된 시점부터 적용되며, DNS 해석, TCP 및 TLS 설정, 프록시 협상을 포함합니다. `send_receive_timeout`은 소켓 읽기 시간을 제한합니다. 풀 대기를 포함한 전체 작업에 기한을 설정하려면 `asyncio.wait_for`를 사용하십시오(예: `await asyncio.wait_for(client.query("SELECT 13"), timeout=30)`).
