MySQL 커넥터
MySQL 커넥터 (MySQL connector)
MySQL 커넥터는 Trino 쿼리에서 외부 MySQL 데이터베이스의 데이터를 읽고 쓸 수 있게 해줍니다. 여러 MySQL 인스턴스나 다른 데이터 소스의 데이터를 하나의 쿼리로 조합할 수 있어요.
출처: 문서
본문
요구 사항 (Requirements)
MySQL에 연결하려면 다음이 필요합니다:
- MySQL 서버 (5.7 이상 또는 8.0).
- Trino 코디네이터와 워커에서 MySQL로의 네트워크 접근. 기본 포트는 3306.
설정 (Configuration)
MySQL 커넥터를 example 카탈로그로 설정하려면 etc/catalog에 example.properties라는 파일을 만들고 다음 연결 속성을 넣어주세요:
connector.name=mysql
connection-url=jdbc:mysql://example.net:3306/
connection-user=root
connection-password=secret
connection-url은 JDBC 드라이버에 전달할 연결 정보와 파라미터를 정의합니다. 커넥터는 MySQL JDBC 드라이버를 사용하며, 연결 사용자 이름과 비밀번호가 필요합니다. 시크릿 (secrets)을 사용하면 카탈로그 속성 파일에 실제 값을 넣지 않고도 자격 증명을 관리할 수 있습니다.
데이터 소스 인증 (Data source authentication)
커넥터는 데이터 소스 연결용 자격 증명을 여러 방법으로 제공할 수 있습니다:
- 커넥터 설정 파일에 inline으로
- 별도의 properties 파일로
- 키 스토어 파일로
- Trino에 연결할 때 추가 자격 증명 (extra credentials)으로
시크릿 (secrets)을 활용하면 카탈로그 속성 파일에 민감한 값을 저장하지 않을 수 있어요.
쿼리 주석 (Query comments)
query.comment-format 카탈로그 설정 속성은 각 쿼리와 함께 데이터 소스에 전송되는 주석 문자열을 제어합니다. 기본값은 Query sent by Trino.이고, 특정 쿼리 메타데이터를 포함하도록 변경할 수 있습니다. 지원되는 메타데이터는 다음과 같습니다:
$QUERY_ID: 쿼리 식별자.$USER: 쿼리를 Trino에 제출한 사용자 이름.$SOURCE: 쿼리를 제출하는 데 사용된 클라이언트 도구 식별자 (예:trino-cli).$TRACE_TOKEN: 클라이언트 도구로 설정된 추적 토큰.
주석은 쿼리에 더 많은 맥락을 제공할 수 있으며, 이 정보는 데이터 소스의 로그에서 확인할 수 있습니다. Trino 클러스터의 환경 변수를 주석에 포함하려면 ${ENV:VARIABLE-NAME} 문법을 사용하세요.
다음 예제는 Trino가 보내는 각 쿼리를 식별하는 간단한 주석을 설정합니다:
query.comment-format=Query sent by Trino.
이 설정에서 SELECT * FROM example_table; 같은 쿼리는 주석이 덧붙여져 데이터 소스로 전송됩니다:
SELECT * FROM example_table; /*Query sent by Trino.*/
다음 예제는 메타데이터를 사용해 앞선 예제를 개선합니다:
query.comment-format=Query $QUERY_ID sent by user $USER from Trino.
Jane이 쿼리 식별자 20230622_180528_00000_bkizg로 쿼리를 보냈다면 다음 주석 문자열이 데이터 소스로 전송됩니다:
SELECT * FROM example_table; /*Query 20230622_180528_00000_bkizg sent by user Jane from Trino.*/
일부 JDBC 드라이버 설정과 로깅 구성은 주석이 제거되게 할 수 있습니다.
도메인 압축 임계값 (Domain compaction threshold)
큰 조건 목록을 데이터 소스로 푸시다운하면 성능이 저하될 수 있습니다. Trino는 기본적으로 큰 조건을 더 단순한 범위 조건으로 압축해 성능과 조건 푸시다운 사이의 균형을 맞춥니다. domain-compaction-threshold 카탈로그 설정 속성 또는 domain_compaction_threshold 카탈로그 세션 속성으로 이 임계값의 기본값인 256을 조정할 수 있습니다.
대소문자 구분 없는 매칭 (Case insensitive matching)
case-insensitive-name-matching을 true로 설정하면 Trino는 소문자 이름을 원격 시스템의 실제 이름에 매핑해 비소문자 스키마와 테이블을 조회할 수 있습니다. 다만 이름이 대소문자만 다른 두 스키마/테이블("customers"와 "Customers")이 있으면 모호성 때문에 조회가 실패합니다.
이런 경우 case-insensitive-name-matching.config-file 카탈로그 설정 속성으로 원격 스키마/테이블을 각각의 Trino 스키마/테이블에 매핑하는 설정 파일을 지정하세요. JSON 파일은 빈 배열이라도 schemas와 tables 속성을 모두 포함해야 합니다.
{
"schemas": [
{
"remoteSchema": "CaseSensitiveName",
"mapping": "case_insensitive_1"
},
{
"remoteSchema": "cASEsENSITIVEnAME",
"mapping": "case_insensitive_2"
}],
"tables": [
{
"remoteSchema": "CaseSensitiveName",
"remoteTable": "tablex",
"mapping": "table_1"
},
{
"remoteSchema": "CaseSensitiveName",
"remoteTable": "TABLEX",
"mapping": "table_2"
}]
}
mapping 속성에 정의된 테이블/스키마 중 하나를 대상으로 한 쿼리는 해당 원격 엔티티에 대해 실행됩니다. 예를 들어 case_insensitive_1 스키마의 테이블에 대한 쿼리는 CaseSensitiveName 스키마로 전달되고, case_insensitive_2에 대한 쿼리는 cASEsENSITIVEnAME 스키마로 전달됩니다.
테이블 매핑 수준에서 case_insensitive_1.table_1에 대한 쿼리는 CaseSensitiveName.tablex로, case_insensitive_1.table_2에 대한 쿼리는 CaseSensitiveName.TABLEX로 전달됩니다.
매핑 설정 파일이 변경되면 기본적으로 Trino를 재시작해야 변경 사항이 로드됩니다. case-insensitive-name-matching.config-file.refresh-period를 설정하면 재시작 없이 속성을 갱신할 수 있습니다:
case-insensitive-name-matching.config-file.refresh-period=30s
장애 허용 실행 지원 (Fault-tolerant execution support)
커넥터는 쿼리 처리의 장애 허용 실행을 지원합니다. 어떤 재시도 정책으로든 읽기와 쓰기 연산 모두 지원됩니다.
테이블 속성 (Table properties)
테이블 속성 사용 예제:
CREATE TABLE person (
id INT NOT NULL,
name VARCHAR,
age INT,
birthday DATE
)
WITH (
primary_key = ARRAY['id']
);
다음은 지원되는 MySQL 테이블 속성입니다:
| 속성 이름 | 필수 | 설명 |
|---|---|---|
primary_key |
아니요 | 테이블의 기본 키. 여러 컬럼을 기본 키로 선택할 수 있습니다. 모든 키 컬럼은 NOT NULL로 정의되어야 합니다. |
데이터 유형 매핑 (Type mapping)
Trino와 MySQL은 서로 지원하지 않는 유형이 있으므로, 이 커넥터는 데이터를 읽거나 쓸 때 일부 유형을 변환합니다. 각 방향의 매핑은 아래 표를 참고하세요.
MySQL에서 Trino로의 유형 매핑:
| MySQL 유형 | Trino 유형 | 비고 |
|---|---|---|
BIT |
BOOLEAN |
|
TINYINT |
TINYINT |
|
TINYINT UNSIGNED |
SMALLINT |
|
SMALLINT |
SMALLINT |
|
SMALLINT UNSIGNED |
INTEGER |
|
INTEGER |
INTEGER |
|
INTEGER UNSIGNED |
BIGINT |
|
BIGINT |
BIGINT |
|
BIGINT UNSIGNED |
DECIMAL(20, 0) |
|
DOUBLE PRECISION |
DOUBLE |
|
FLOAT |
REAL |
|
REAL |
REAL |
|
DECIMAL(p, s) |
DECIMAL(p, s) 또는 NUMBER |
p ≤ 38이면 Trino DECIMAL, 아니면 NUMBER로 매핑 |
CHAR(n) |
CHAR(n) |
|
VARCHAR(n) |
VARCHAR(n) |
|
TINYTEXT |
VARCHAR(255) |
|
TEXT |
VARCHAR(65535) |
|
MEDIUMTEXT |
VARCHAR(16777215) |
|
LONGTEXT |
VARCHAR |
|
ENUM(n) |
VARCHAR(n) |
|
BINARY, VARBINARY, TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB |
VARBINARY |
|
JSON |
JSON |
|
DATE |
DATE |
|
TIME(n) |
TIME(n) |
|
DATETIME(n) |
TIMESTAMP(n) |
|
TIMESTAMP(n) |
TIMESTAMP(n) WITH TIME ZONE |
그 외 유형은 지원되지 않습니다.
Trino에서 MySQL로의 유형 매핑:
| Trino 유형 | MySQL 유형 | 비고 |
|---|---|---|
BOOLEAN |
TINYINT |
|
TINYINT |
TINYINT |
|
SMALLINT |
SMALLINT |
|
INTEGER |
INTEGER |
|
BIGINT |
BIGINT |
|
REAL |
REAL |
|
DOUBLE |
DOUBLE PRECISION |
|
DECIMAL(p, s) |
DECIMAL(p, s) |
|
CHAR(n) |
CHAR(n) |
|
VARCHAR(n) |
VARCHAR(n) |
|
JSON |
JSON |
|
DATE |
DATE |
|
TIME(n) |
TIME(n) |
|
TIMESTAMP(n) |
DATETIME(n) |
|
TIMESTAMP(n) WITH TIME ZONE |
TIMESTAMP(n) |
그 외 유형은 지원되지 않습니다.
타임스탬프 유형 처리 (Timestamp type handling)
MySQL TIMESTAMP 유형은 Trino TIMESTAMP WITH TIME ZONE으로 매핑됩니다. 시간 인스턴스를 보존하기 위해 Trino는 MySQL 연결의 세션 시간대를 JVM 시간대와 일치시킵니다. 그 결과, JVM의 시간대가 MySQL 서버에 없으면 다음과 유사한 오류 메시지가 발생합니다:
com.mysql.cj.exceptions.CJException: Unknown or incorrect time zone: 'UTC'
오류를 피하려면 두 시스템 모두에 알려진 시간대를 사용하거나, MySQL 서버에 누락된 시간대를 설치해야 합니다.
유형 매핑 설정 속성 (Type mapping configuration properties)
| 속성 이름 | 설명 | 기본값 |
|---|---|---|
unsupported-type-handling |
지원되지 않는 컬럼 유형 처리 방식: IGNORE(컬럼 접근 불가) 또는 CONVERT_TO_VARCHAR(무제한 VARCHAR로 변환). 해당 카탈로그 세션 속성은 unsupported_type_handling. |
IGNORE |
jdbc-types-mapped-to-varchar |
무제한 VARCHAR로 변환할 유형의 쉼표 구분 목록을 강제 매핑. |
— |
MySQL 조회 (Querying MySQL)
MySQL 커넥터는 각 MySQL 데이터베이스에 대해 스키마를 제공합니다. SHOW SCHEMAS로 사용 가능한 MySQL 데이터베이스를 확인할 수 있습니다:
SHOW SCHEMAS FROM example;
web이라는 MySQL 데이터베이스가 있으면 SHOW TABLES로 이 데이터베이스의 테이블을 볼 수 있습니다:
SHOW TABLES FROM example.web;
web 데이터베이스의 clicks 테이블 컬럼 목록은 다음 중 하나로 확인할 수 있습니다:
DESCRIBE example.web.clicks;
SHOW COLUMNS FROM example.web.clicks;
마지막으로 web 데이터베이스의 clicks 테이블에 접근할 수 있습니다:
SELECT * FROM example.web.clicks;
카탈로그 속성 파일에 다른 이름을 사용했다면 위 예제의 example 대신 해당 카탈로그 이름을 사용하세요.
SQL 지원 (SQL support)
커넥터는 MySQL 데이터베이스의 데이터와 메타데이터에 대해 읽기/쓰기 접근을 제공합니다. 전역 사용 가능 명령문과 읽기 연산 명령문에 더해 다음 기능을 지원합니다:
- INSERT — 비트랜잭션 INSERT 참고
- UPDATE — UPDATE 제한 참고
- DELETE — DELETE 제한 참고
- MERGE — 비트랜잭션 MERGE 참고
- TRUNCATE
- CREATE TABLE
- CREATE TABLE AS
- DROP TABLE
- CREATE SCHEMA
- DROP SCHEMA
- 프로시저
- 테이블 함수
비트랜잭션 INSERT (Non-transactional INSERT)
커넥터는 INSERT 문으로 행 추가를 지원합니다. 기본적으로 데이터는 임시 테이블에 먼저 기록됩니다. insert.non-transactional-insert.enabled 카탈로그 속성 또는 해당 non_transactional_insert 카탈로그 세션 속성을 true로 설정하면 이 단계를 건너뛰고 대상 테이블에 직접 기록해 성능을 높일 수 있습니다.
이 속성을 켜면 드물게 insert 작업 중 예외가 발생할 때 데이터가 손상될 수 있습니다. 트랜잭션이 비활성화되므로 롤백이 불가능합니다.
UPDATE 제한 (UPDATE limitation)
상수 할당과 상수 조건을 가진 UPDATE 문만 지원합니다. 예를 들어 다음 문은 값이 상수이므로 지원됩니다:
UPDATE table SET col1 = 1 WHERE col3 = 1
산술 표현식, 함수 호출 등 비상수 UPDATE 문은 지원되지 않습니다:
UPDATE table SET col1 = col2 + 2 WHERE col3 = 1
한 행의 모든 컬럼 값을 동시에 갱신할 수는 없습니다:
UPDATE table SET col1 = 1, col2 = 2, col3 = 3 WHERE col3 = 1
DELETE 제한 (DELETE limitation)
WHERE 절이 지정되면 해당 절의 조건을 데이터 소스에 완전히 푸시다운할 수 있을 때만 DELETE가 동작합니다.
비트랜잭션 MERGE (Non-transactional MERGE)
merge.non-transactional-merge.enabled 카탈로그 속성 또는 non_transactional_merge_enabled 카탈로그 세션 속성이 true이면 MERGE 문으로 행 추가/갱신/삭제를 지원합니다. MERGE는 대상 테이블을 직접 수정할 때만 지원됩니다.
드물게 merge 작업 중 예외가 발생해 부분 갱신이 일어날 수 있습니다.
프로시저 (Procedures)
system.flush_metadata_cache()
JDBC 메타데이터 캐시를 비웁니다:
USE example.example_schema;
CALL system.flush_metadata_cache();
system.execute('query')
execute 프로시저는 연결된 데이터 소스에서 쿼리를 직접 실행하게 해줍니다. 쿼리는 연결된 데이터 소스의 지원 문법을 사용해야 합니다. Trino에 없는 기능에 접근하거나, 결과 집합을 반환하지 않아 query나 raw_query 패스스루 테이블 함수로 사용할 수 없는 쿼리를 실행할 때 유용합니다.
쿼리 텍스트는 Trino가 파싱하지 않고 그대로 전달하므로, 연결된 데이터 소스의 보안/접근 제어만 적용됩니다.
USE example.example_schema;
CALL system.execute(query => 'ALTER TABLE your_table ALTER COLUMN your_column DROP DEFAULT');
테이블 함수 (Table functions)
커넥터는 MySQL에 접근하기 위한 특정 테이블 함수를 제공합니다.
query(varchar) -> table
query 함수는 연결된 데이터베이스를 직접 조회하게 해줍니다. 전체 쿼리가 푸시다운되어 MySQL에서 처리되므로 MySQL 고유 문법이 필요합니다.
연결된 데이터 소스에 전달되는 네이티브 쿼리는 결과 집합으로 테이블을 반환해야 합니다. 검증과 보안 검사는 오직 데이터 소스가 자체 설정으로 수행합니다. 패스스루 쿼리는 데이터 읽기에만 사용하세요.
예를 들어 example 카탈로그를 조회해 모든 직원 ID를 관리자 ID별로 그룹화해 연결합니다:
SELECT
*
FROM
TABLE(
example.system.query(
query => 'SELECT
manager_id, GROUP_CONCAT(employee_id)
FROM
company.employees
GROUP BY
manager_id'
)
);
쿼리 엔진은 이 함수의 결과 순서를 보존하지 않습니다. 전달한 쿼리에 ORDER BY 절이 있으면 함수 결과 순서가 예상과 다를 수 있습니다.
성능 (Performance)
커넥터는 다음 섹션에 설명된 여러 성능 개선을 포함합니다.
테이블 통계 (Table statistics)
MySQL 커넥터는 비용 기반 최적화를 위해 테이블/컬럼 통계를 사용해 실제 데이터에 기반한 쿼리 처리 성능을 높일 수 있습니다.
통계는 MySQL이 수집하고 커넥터가 가져옵니다. 테이블 수준 통계는 MySQL의 INFORMATION_SCHEMA.TABLES 테이블 기반이고, 컬럼 수준 통계는 MySQL 인덱스 통계 INFORMATION_SCHEMA.STATISTICS 테이블 기반입니다. 커넥터는 컬럼이 어떤 인덱스의 첫 번째 컬럼일 때만 컬럼 수준 통계를 반환할 수 있습니다.
MySQL 데이터베이스는 테이블/인덱스 통계를 자동 갱신할 수 있습니다. 경우에 따라(예: 새 인덱스 생성 후, 또는 테이블 데이터 변경 후) 통계 갱신을 강제하고 싶을 수 있습니다:
ANALYZE TABLE table_name;
MySQL과 Trino는 통계 정보를 다르게 사용할 수 있으므로 MySQL 커넥터가 반환하는 통계 정확도가 다른 커넥터보다 낮을 수 있습니다.
통계 정확도 개선 (Improving statistics accuracy)
MySQL 8.0부터 사용 가능한 히스토그램 통계로 정확도를 개선할 수 있습니다:
ANALYZE TABLE table_name UPDATE HISTOGRAM ON column_name1, column_name2, ...;
푸시다운 (Pushdown)
커넥터는 다음 연산에 대해 푸시다운을 지원합니다:
- 조인 푸시다운
- LIMIT 푸시다운
- Top-N 푸시다운
- 다음 함수에 대한 집계 푸시다운:
avg(),count(),max(),min(),sum(),stddev(),stddev_pop(),stddev_samp(),variance(),var_pop(),var_samp()
커넥터는 성능이 향상될 수 있는 곳에서 푸시다운을 수행하지만, 정확성을 지키기 위해 일부 연산은 푸시다운되지 않을 수 있습니다.
비용 기반 조인 푸시다운 (Cost-based join pushdown)
커넥터는 조인 연산을 데이터 소스로 푸시다운할지 여부를 지능적으로 결정하는 비용 기반 조인 푸시다운을 지원합니다.
비용 기반 조인 푸시다운이 활성화되면 커넥터는 사용 가능한 테이블 통계가 성능을 개선한다고 시사할 때만 조인 연산을 푸시다운합니다. 테이블 통계가 없으면 쿼리 성능 저하를 피하기 위해 조인 연산 푸시다운이 발생하지 않습니다.
| 속성 이름 | 설명 | 기본값 |
|---|---|---|
join-pushdown.enabled |
조인 푸시다운 활성화. 해당 카탈로그 세션 속성은 join_pushdown_enabled. |
true |
join-pushdown.strategy |
조인 푸시다운 여부를 평가하는 전략. AUTOMATIC이면 비용 기반 조인 푸시다운, EAGER이면 가능할 때마다 조인 푸시다운. EAGER는 테이블 통계가 없어도 푸시다운하므로 쿼리 성능 저하가 생길 수 있어 테스트/트러블슈팅 용도로만 권장. |
AUTOMATIC |
조건 푸시다운 지원 (Predicate pushdown support)
커넥터는 CHAR나 VARCHAR 같은 텍스트 유형 컬럼에 대한 조건 푸시다운을 지원하지 않습니다. 다음 예제에서 name은 VARCHAR 유형 컬럼이므로 두 쿼리 모두 조건이 푸시다운되지 않습니다:
SELECT * FROM nation WHERE name > 'CANADA';
SELECT * FROM nation WHERE name = 'CANADA';
더 알아보기 (Learn more)
MySQL 커넥터로 다른 데이터 소스와 데이터를 조합해보세요. 커넥터의 일반적인 개념은 커넥터 개요 문서에서 확인할 수 있어요.