Ask business questions against a data lake with Athena-style safety and cost checks. — Claude Skill
Claude Code용 Claude 스킬 · 제공: AWS✓ · 실행: /querying-data-lake (Claude 내)·업데이트: 2026년 6월 14일·vmain@7cd875e
올바른 데이터 원천, workgroup, SQL 패턴을 고르고 대형 데이터 레이크 테이블을 비용 인식, 결과 해석, 안전 제한과 함께 조회하도록 돕습니다.
- 큰 테이블을 스캔하기 전에 비즈니스 질문을 안전한 데이터 레이크 쿼리 계획으로 바꿉니다.
- 적절한 workgroup, 테이블, 파티션, 제한, 쿼리 패턴을 선택합니다.
- 스캔 데이터, 비용 위험, 결과를 사용할 만큼 신뢰할 수 있는지 설명합니다.
- 읽기 전용 분석과 파괴적이거나 안전하지 않은 작업을 분리합니다.
팀이 데이터 엔지니어에게 숫자를 요청하고 비싸거나 의미가 불명확한 일회성 쿼리를 받습니다.
/querying-data-lake를 실행해 질문, 원천, SQL 패턴, 비용, 주의점을 답변 사용 전에 명확히 합니다.
대상
기능
영구 대시보드 없이 데이터 레이크에서 비즈니스 질문에 답합니다.
과도한 스캔 전에 파티션과 workgroup을 확인하며 큰 테이블을 탐색합니다.
데이터 레이크 테이블이 지표나 벤치마크를 지원할 수 있는지 확인합니다.
작동 방식
비즈니스 질문, 기간, 지표, 필터, 필요한 출력을 명확히 합니다.
가능성 높은 catalog, database, table, partition, workgroup을 찾습니다.
스캔 데이터를 줄이고 위험한 작업을 피하는 쿼리 계획을 만듭니다.
미리보기 제한을 둔 SQL을 실행하거나 초안화하고 결과 타당성을 점검합니다.
답, 주의점, 반복 보고서로 만들 가치가 있는지 설명합니다.
입력 옵션
답해야 할 의사결정, 지표, 세그먼트, 기간입니다.
예시
비즈니스 질문: 새 온보딩 체크리스트 이후 활성화가 개선되었나요? 기간: 5월 1일-6월 14일. 세그먼트: SMB, 중견, 엔터프라이즈. 활성화 정의: 워크스페이스가 7일 안에 팀원 2명 이상을 초대하고 첫 프로젝트를 완료. 알려진 테이블: - event_date로 파티션된 product_events - created_month로 파티션된 accounts - workspaces 필요: 제품팀과 재무팀에 공유하기 전 쿼리 계획, 안전한 SQL 개요, 결과 표, 주의점.
읽기 전용 Athena SQL을 사용합니다. product_events는 5월 1일부터 6월 14일까지 event_date로 제한합니다. accounts는 workspace_id와 created_month로만 조인합니다. 집계 전에 100행 미리보기를 실행하고, 가능하면 analytics workgroup을 사용합니다.
1. 기간 내 생성된 워크스페이스를 찾습니다. 2. 생성 후 7일 안의 invited_팀원와 first_project_completed 이벤트를 계산합니다. 3. 두 조건이 모두 참이면 활성화로 표시합니다. 4. 계정 세그먼트와 체크리스트 출시 전후로 그룹화합니다. 5. 워크스페이스 수, 활성화 수, 활성화율, 신뢰 주의점을 반환합니다.
| 세그먼트 | 기간 | 워크스페이스 | 활성화 | 활성화율 | 해석 | |---|---|---:|---:|---:|---| | SMB | 전 | 420 | 151 | 36% | 기준선 | | SMB | 후 | 390 | 171 | 44% | 개선 확인 | | 중견 | 전 | 180 | 76 | 42% | 기준선 | | 중견 | 후 | 165 | 84 | 51% | 강한 움직임 | | 엔터프라이즈 | 전 | 52 | 19 | 37% | 표본 작음 | | 엔터프라이즈 | 후 | 48 | 20 | 42% | 조심스럽게 해석 |
인과를 증명하지 않습니다. 유입 원천 변화, 이벤트 계측 안정성, 엔터프라이즈 표본 크기 부족 여부를 확인하세요.
개선되는 지표
지원 도구
데이터 레이크 쿼리을(를) 사용해 보시겠어요?
시작 방법을 선택하세요.
이 스킬을 컴퓨터에 로컬로 설치하고 실행합니다.
컴퓨터에서 터미널을 열고 이 명령을 붙여넣으세요:
이 명령은 스킬과 모든 파일을 컴퓨터에 다운로드합니다:
모든 프로젝트에서 사용하려면 끝에 -g를 추가하세요.
Claude Code를 시작한 다음 명령을 입력하세요:
데이터 레이크 쿼리
워크그룹 선택, 문장 분류, 오류 복구를 포함해 기본 및 페더레이션 카탈로그(Glue, S3 Tables, Redshift) 전반에서 Amazon Athena SQL 쿼리를 실행합니다.
개요
기본 및 페더레이션 카탈로그 전반에서 Athena SQL 쿼리를 실행하고 관리합니다. 워크그룹을 선택하고, 대상 자산을 확인하며(모호한 참조는 finding-data-lake-assets에 위임), 안전을 위해 문장을 분류하고, 비용과 스캔한 데이터를 보고합니다. 샌드박스 실행과 감사 로깅에는 AWS MCP 서버를 사용합니다. MCP 서버를 사용할 수 없을 때는 동일한 AWS CLI 명령이 직접 동작합니다.
매개변수 확보 제약:
- 선택적 인수 하나를 반드시 받아야 합니다: SQL 텍스트, 이름 있는 쿼리 이름, 워크그룹 이름, 카탈로그 이름 또는
profile TABLE_NAME - 인수는 직접 텍스트이거나 SQL이 들어 있는 파일 포인터여야 합니다.
- 대상 AWS 리전이 아직 설정되지 않았으면 사용자에게 반드시 물어봐야 합니다.
- 사소하지 않은 쿼리를 실행하기 전에 출력 S3 위치를 반드시 확인해야 합니다.
- 어느 단계에서든 중단하겠다는 사용자의 결정을 반드시 존중해야 합니다.
일반 작업
1. 의존성 확인
쿼리를 실행하기 전에 필요한 도구와 AWS 접근 권한을 확인합니다.
제약:
- AWS MCP 서버 도구(
aws___call_aws)를 사용할 수 있는지 반드시 확인하고, 있으면 그 도구로 쿼리를 실행해야 합니다. MCP 서버를 사용할 수 없을 때만 AWS CLI로 대체합니다. - 쿼리 실행을 shell이나 Bash로 대체하면 안 됩니다. 출력 위치와 비용을 추적할 수 있도록 MCP 도구 또는
aws athenaCLI로 결과를 캡처해야 합니다. aws sts get-caller-identity로 자격 증명을 반드시 확인하고, 누락된 도구가 있으면 사용자에게 알려야 합니다.
2. 워크그룹 확인
호출자 ID를 확인하고, 워크그룹을 나열하고, 가장 적합한 워크그룹을 자동 선택합니다(workgroup-selection.md 참조).
제약:
- 쿼리를 제출하기 전에 반드시 워크그룹을 선택해야 합니다(출력 위치 오류 방지).
- 선택한 워크그룹과 출력 위치를 사용자에게 반드시 제시해야 합니다.
- 실패 시 사용자 확인 없이 다른 워크그룹으로 자동 전환하면 안 됩니다.
3. 대상 자산 확인
사용자가 테이블을 이름, 비즈니스 개념("우리 분기 보고서", "영업 데이터"), S3 경로 또는 테이블을 지정하지 않은 카탈로그로 언급하면 finding-data-lake-assets에 위임해 구체적인 database.table(기본값이 아니면 카탈로그도 포함)을 반환하게 합니다.
제약:
athena list-data-catalogs또는get-tables반복으로 모호한 자산 참조를 해결하려고 해서는 안 됩니다. 이는 페더레이션 카탈로그를 놓치고 토큰을 낭비합니다.- 사용자가 완전한 참조(정확한
database.table) 또는 그대로 실행할 원시 SQL을 제공한 경우에만 이 단계를 건너뛰는 것이 좋습니다. - 쿼리를 만들기 전에 확인된 자산을 명시해야 합니다: "[catalog]에서 [table]을 찾았습니다. 이 테이블을 쿼리에 사용합니다."
- 사용자가 "federated", "Redshift", "S3 Tables"를 언급하거나
finding-data-lake-assets가 다른 카탈로그를 반환하지 않는 한 기본 Glue 카탈로그를 기본값으로 삼는 것이 좋습니다.
4. 스키마 탐색
분석 쿼리의 경우 최종 쿼리를 만들기 전에 대상 테이블을 프로파일링하는 것이 좋습니다. 프로파일링의 일부로 샘플 행(SELECT ... LIMIT 5)을 반드시 보여줘야 합니다.
5. 쿼리 작성
테이블 주소 지정은 카탈로그 유형에 따라 달라집니다:
- 기본 Glue 카탈로그:
database.table(단일 카탈로그 쿼리에서는 카탈로그 접두사 생략). 카탈로그 간 쿼리에서는 기본 카탈로그 테이블을"awsdatacatalog".database.table로 한정합니다. - 등록된 데이터 소스:
datasource.database.table - 등록되지 않은 Glue 카탈로그:
"catalog/subcatalog".database.table
6. 분류와 실행
실행 전에 SQL 문장을 분류합니다:
| 문장 | 동작 |
|---|---|
SELECT, SHOW, DESCRIBE, EXPLAIN | 안전 — 실행 |
INSERT, UPDATE, DELETE, DROP, ALTER, CREATE, TRUNCATE, MERGE | 파괴적 — 사용자에게 경고하고 명시적 확인 필요 |
| 불확실 | 파괴적으로 간주하고 확인 |
도구 호출 예시(AWS MCP 서버 경유):
aws___call_aws(command="aws athena start-query-execution --work-group <WORKGROUP_NAME> --query-string '<sql>' --query-execution-context Database=<db>")
페더레이션 또는 S3 Tables 카탈로그의 경우 실행 컨텍스트에 Catalog=<CATALOG_PATH>도 설정합니다(예: Catalog=s3tablescatalog/<BUCKET_NAME>).
제약:
- 대상이 Redshift 페더레이션이면 실행 전에 반드시 사용자에게 경고해야 합니다("파티션 가지치기 없음 — 모든 쿼리가 전체 테이블을 스캔합니다").
- 카탈로그 간 조인을 실행하기 전에 반드시 사용자에게 경고해야 합니다("카탈로그 간 조인은 네트워크 오버헤드를 발생시키며 느릴 수 있습니다").
- 실행 전에 출력 S3 위치를 반드시 확인해야 합니다.
- 실행 전에 어떤 도구를 호출하는지 반드시 설명해야 합니다.
- 중단하겠다는 사용자의 결정을 반드시 존중해야 합니다.
7. 제시와 복구
비용, 스캔한 데이터, 소요 시간, 실행 가능한 인사이트와 함께 결과를 제시합니다. 실패하면 사용 가능한 워크그룹을 나열하고 어떤 것으로 재시도할지 사용자가 선택하게 합니다.
인수 라우팅
다음 순서로 확인하고 첫 일치에서 중단합니다:
- SQL 키워드(
SELECT,SHOW,DESCRIBE,INSERT등)를 포함 — SQL 텍스트로 보고 직접 실행 profile TABLE_NAME— 종합 테이블 프로파일링 실행(query-patterns.md 참조)- 알려진 이름 있는 쿼리와 일치 — 조회 후 실행
- 알려진 워크그룹과 일치 — 워크그룹 상태와 최근 쿼리 표시
- 알려진 카탈로그와 일치 —
exploring-data-catalog에 위임해 데이터베이스와 테이블 열거 - 인수 없음 — 최근 쿼리 활동과 사용 가능한 테이블 표시
원칙
- 실행 전에 항상 워크그룹을 선택합니다(출력 위치 오류 방지).
- 익숙하지 않은 테이블은 분석 쿼리 전에 프로파일링합니다.
- 사용자가 비용 감각을 쌓을 수 있도록 결과와 함께 비용을 제시합니다.
- 큰 테이블의 탐색 쿼리에는
LIMIT을 제안합니다. - 답이 명확한 도메인 질문은 묻지 않지만, 보안 관련 조치(워크그룹 전환, 출력 위치 변경, SELECT가 아닌 문장)는 항상 확인합니다.
문제 해결
| 오류 | 원인 | 해결 |
|---|---|---|
| 대소문자가 섞인 Redshift 식별자 오류 | Redshift 페더레이션 이름은 소문자만 허용 | 식별자를 소문자로 변경 |
CatalogId 검증 실패 | 카탈로그 이름 대신 ARN 전달 | ARN이 아니라 카탈로그 이름 전달 |
카탈로그 간 information_schema가 아무것도 반환하지 않음 | 카탈로그 한정자 누락 | 카탈로그로 한정한 경로 사용: "catalog".information_schema.tables |
| 쿼리가 출력 위치 오류로 실패 | 워크그룹에 출력 위치가 설정되지 않음 | 출력 위치가 있는 다른 워크그룹을 선택하거나 하나를 설정 |
| 확인 없이 파괴적 문장 실행 | 문장 분류를 건너뜀 | 항상 INSERT/UPDATE/DELETE/DROP/ALTER/CREATE/TRUNCATE/MERGE를 분류하고 사용자에게 확인 |
추가 자료
참조 문서
일반 쿼리 패턴(Presto/Athena SQL)
테이블 프로파일링
-- 스키마 탐색
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_schema = '<database>' AND table_name = '<table>';
-- 빠른 행 수와 날짜 범위 확인
SELECT COUNT(*) as total_rows,
MIN(created_at) as earliest,
MAX(created_at) as latest
FROM <table>;
-- 샘플 데이터(분석 쿼리 전에 항상 실행)
SELECT * FROM <table> LIMIT 5;
-- Null 분석
SELECT
'<column>' as field,
COUNT(*) - COUNT(<column>) as null_count,
ROUND((COUNT(*) - COUNT(<column>)) * 100.0 / COUNT(*), 2) as null_pct
FROM <table>;
코호트 유지율
WITH cohorts AS (
SELECT
user_id,
DATE_TRUNC('month', first_activity_date) as cohort_month
FROM users
),
activity AS (
SELECT
user_id,
DATE_TRUNC('month', activity_date) as activity_month
FROM user_activity
)
SELECT
c.cohort_month,
COUNT(DISTINCT c.user_id) as cohort_size,
COUNT(DISTINCT CASE
WHEN a.activity_month = c.cohort_month THEN a.user_id
END) as month_0,
COUNT(DISTINCT CASE
WHEN a.activity_month = DATE_ADD('month', 1, c.cohort_month) THEN a.user_id
END) as month_1,
COUNT(DISTINCT CASE
WHEN a.activity_month = DATE_ADD('month', 3, c.cohort_month) THEN a.user_id
END) as month_3,
COUNT(DISTINCT CASE
WHEN a.activity_month = DATE_ADD('month', 6, c.cohort_month) THEN a.user_id
END) as month_6
FROM cohorts c
LEFT JOIN activity a ON c.user_id = a.user_id
GROUP BY c.cohort_month
ORDER BY c.cohort_month;
퍼널 분석
WITH funnel AS (
SELECT
user_id,
MAX(CASE WHEN event = 'page_view' THEN 1 ELSE 0 END) as step_1_view,
MAX(CASE WHEN event = 'signup_start' THEN 1 ELSE 0 END) as step_2_start,
MAX(CASE WHEN event = 'signup_complete' THEN 1 ELSE 0 END) as step_3_complete,
MAX(CASE WHEN event = 'first_purchase' THEN 1 ELSE 0 END) as step_4_purchase
FROM events
WHERE event_date >= DATE_ADD('day', -30, CURRENT_DATE)
GROUP BY user_id
)
SELECT
COUNT(*) as total_users,
SUM(step_1_view) as viewed,
SUM(step_2_start) as started_signup,
SUM(step_3_complete) as completed_signup,
SUM(step_4_purchase) as purchased,
ROUND(100.0 * SUM(step_2_start) / NULLIF(SUM(step_1_view), 0), 1) as view_to_start_pct,
ROUND(100.0 * SUM(step_3_complete) / NULLIF(SUM(step_2_start), 0), 1) as start_to_complete_pct,
ROUND(100.0 * SUM(step_4_purchase) / NULLIF(SUM(step_3_complete), 0), 1) as complete_to_purchase_pct
FROM funnel;
중복 제거
-- 키별 최신 레코드 유지(Presto/Athena 문법)
WITH ranked AS (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY entity_id
ORDER BY updated_at DESC
) as rn
FROM source_table
)
SELECT * FROM ranked WHERE rn = 1;
윈도 함수
-- 누계
SUM(revenue) OVER (ORDER BY event_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as running_total
-- 7일 이동 평균
AVG(revenue) OVER (ORDER BY event_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as moving_avg_7d
-- 기간 대비 비교
LAG(value, 1) OVER (PARTITION BY entity ORDER BY event_date) as prev_value
-- 전체 대비 비율
revenue / SUM(revenue) OVER () as pct_of_total
revenue / SUM(revenue) OVER (PARTITION BY category) as pct_of_category
-- 순위
ROW_NUMBER() OVER (PARTITION BY category ORDER BY revenue DESC) as rank_in_category
기간 비교 / 성장
사용자가 기간 간 "성장", "변화", "비교"를 요청하면 원시 합계가 아니라 차이를 계산합니다.
WITH quarterly AS (
SELECT
category,
QUARTER(order_date) as q,
SUM(amount) as revenue
FROM orders
WHERE YEAR(order_date) = 2025
GROUP BY category, QUARTER(order_date)
)
SELECT
curr.category,
prev.revenue as prev_period,
curr.revenue as curr_period,
ROUND((curr.revenue - prev.revenue) / prev.revenue * 100, 1) as growth_pct
FROM quarterly curr
JOIN quarterly prev ON curr.category = prev.category AND curr.q = prev.q + 1
ORDER BY growth_pct DESC;
성능을 고려한 패턴
-- 스캔 비용을 줄이기 위해 항상 파티션 키로 필터링
SELECT region, COUNT(*)
FROM sales
WHERE year = '2024' AND month = '02'
GROUP BY region;
-- 탐색 쿼리에는 LIMIT 사용
SELECT * FROM large_table LIMIT 100;
-- 대규모 카디널리티에는 근사 함수 사용
SELECT APPROX_DISTINCT(user_id) as approx_unique_users
FROM events;
데이터 품질 검사
-- 열별 고유값 수
SELECT
COUNT(DISTINCT col1) as col1_unique,
COUNT(DISTINCT col2) as col2_unique
FROM <table>;
-- 예상 밖 값 감지
SELECT column_name, COUNT(*) as cnt
FROM <table>
GROUP BY column_name
ORDER BY cnt DESC
LIMIT 20;
-- 조인 폭증 확인
SELECT COUNT(*) as pre_join FROM table_a;
SELECT COUNT(*) as post_join FROM table_a a JOIN table_b b ON a.id = b.a_id;
name: querying-data-lake description: >- 기본 및 페더레이션 카탈로그(Glue, S3 Tables, Redshift) 전반에서 Athena SQL 쿼리를 실행하고 관리합니다. 데이터 쿼리, SQL 실행, Athena 쿼리, 테이블 분석, SQL 쿼리, 워크그룹 상태, 테이블 프로파일링, Redshift 카탈로그 쿼리, S3 Tables 쿼리 같은 문구에 반응합니다. 특정 데이터 자산 찾기에는 사용하지 마십시오(finding-data-lake-assets 사용). 전체 카탈로그 감사에는 exploring-data-catalog, 데이터 가져오기에는 ingesting-into-data-lake를 사용합니다. version: 1 argument-hint: '[SQL-query|query-name|workgroup-name|catalog-name|''profile TABLE_NAME'']'
데이터 레이크 쿼리
워크그룹 선택, 문장 분류, 오류 복구를 포함해 기본 및 페더레이션 카탈로그(Glue, S3 Tables, Redshift) 전반에서 Amazon Athena SQL 쿼리를 실행합니다.
개요
기본 및 페더레이션 카탈로그 전반에서 Athena SQL 쿼리를 실행하고 관리합니다. 워크그룹을 선택하고, 대상 자산을 확인하며(모호한 참조는 finding-data-lake-assets에 위임), 안전을 위해 문장을 분류하고, 비용과 스캔한 데이터를 보고합니다. 샌드박스 실행과 감사 로깅에는 AWS MCP 서버를 사용합니다. MCP 서버를 사용할 수 없을 때는 동일한 AWS CLI 명령이 직접 동작합니다.
매개변수 확보 제약:
- 선택적 인수 하나를 반드시 받아야 합니다: SQL 텍스트, 이름 있는 쿼리 이름, 워크그룹 이름, 카탈로그 이름 또는
profile TABLE_NAME - 인수는 직접 텍스트이거나 SQL이 들어 있는 파일 포인터여야 합니다.
- 대상 AWS 리전이 아직 설정되지 않았으면 사용자에게 반드시 물어봐야 합니다.
- 사소하지 않은 쿼리를 실행하기 전에 출력 S3 위치를 반드시 확인해야 합니다.
- 어느 단계에서든 중단하겠다는 사용자의 결정을 반드시 존중해야 합니다.
일반 작업
1. 의존성 확인
쿼리를 실행하기 전에 필요한 도구와 AWS 접근 권한을 확인합니다.
제약:
- AWS MCP 서버 도구(
aws___call_aws)를 사용할 수 있는지 반드시 확인하고, 있으면 그 도구로 쿼리를 실행해야 합니다. MCP 서버를 사용할 수 없을 때만 AWS CLI로 대체합니다. - 쿼리 실행을 shell이나 Bash로 대체하면 안 됩니다. 출력 위치와 비용을 추적할 수 있도록 MCP 도구 또는
aws athenaCLI로 결과를 캡처해야 합니다. aws sts get-caller-identity로 자격 증명을 반드시 확인하고, 누락된 도구가 있으면 사용자에게 알려야 합니다.
2. 워크그룹 확인
호출자 ID를 확인하고, 워크그룹을 나열하고, 가장 적합한 워크그룹을 자동 선택합니다(workgroup-selection.md 참조).
제약:
- 쿼리를 제출하기 전에 반드시 워크그룹을 선택해야 합니다(출력 위치 오류 방지).
- 선택한 워크그룹과 출력 위치를 사용자에게 반드시 제시해야 합니다.
- 실패 시 사용자 확인 없이 다른 워크그룹으로 자동 전환하면 안 됩니다.
3. 대상 자산 확인
사용자가 테이블을 이름, 비즈니스 개념("우리 분기 보고서", "영업 데이터"), S3 경로 또는 테이블을 지정하지 않은 카탈로그로 언급하면 finding-data-lake-assets에 위임해 구체적인 database.table(기본값이 아니면 카탈로그도 포함)을 반환하게 합니다.
제약:
athena list-data-catalogs또는get-tables반복으로 모호한 자산 참조를 해결하려고 해서는 안 됩니다. 이는 페더레이션 카탈로그를 놓치고 토큰을 낭비합니다.- 사용자가 완전한 참조(정확한
database.table) 또는 그대로 실행할 원시 SQL을 제공한 경우에만 이 단계를 건너뛰는 것이 좋습니다. - 쿼리를 만들기 전에 확인된 자산을 명시해야 합니다: "[catalog]에서 [table]을 찾았습니다. 이 테이블을 쿼리에 사용합니다."
- 사용자가 "federated", "Redshift", "S3 Tables"를 언급하거나
finding-data-lake-assets가 다른 카탈로그를 반환하지 않는 한 기본 Glue 카탈로그를 기본값으로 삼는 것이 좋습니다.
4. 스키마 탐색
분석 쿼리의 경우 최종 쿼리를 만들기 전에 대상 테이블을 프로파일링하는 것이 좋습니다. 프로파일링의 일부로 샘플 행(SELECT ... LIMIT 5)을 반드시 보여줘야 합니다.
5. 쿼리 작성
테이블 주소 지정은 카탈로그 유형에 따라 달라집니다:
- 기본 Glue 카탈로그:
database.table(단일 카탈로그 쿼리에서는 카탈로그 접두사 생략). 카탈로그 간 쿼리에서는 기본 카탈로그 테이블을"awsdatacatalog".database.table로 한정합니다. - 등록된 데이터 소스:
datasource.database.table - 등록되지 않은 Glue 카탈로그:
"catalog/subcatalog".database.table
6. 분류와 실행
실행 전에 SQL 문장을 분류합니다:
| 문장 | 동작 |
|---|---|
SELECT, SHOW, DESCRIBE, EXPLAIN | 안전 — 실행 |
INSERT, UPDATE, DELETE, DROP, ALTER, CREATE, TRUNCATE, MERGE | 파괴적 — 사용자에게 경고하고 명시적 확인 필요 |
| 불확실 | 파괴적으로 간주하고 확인 |
도구 호출 예시(AWS MCP 서버 경유):
aws___call_aws(command="aws athena start-query-execution --work-group <WORKGROUP_NAME> --query-string '<sql>' --query-execution-context Database=<db>")
페더레이션 또는 S3 Tables 카탈로그의 경우 실행 컨텍스트에 Catalog=<CATALOG_PATH>도 설정합니다(예: Catalog=s3tablescatalog/<BUCKET_NAME>).
제약:
- 대상이 Redshift 페더레이션이면 실행 전에 반드시 사용자에게 경고해야 합니다("파티션 가지치기 없음 — 모든 쿼리가 전체 테이블을 스캔합니다").
- 카탈로그 간 조인을 실행하기 전에 반드시 사용자에게 경고해야 합니다("카탈로그 간 조인은 네트워크 오버헤드를 발생시키며 느릴 수 있습니다").
- 실행 전에 출력 S3 위치를 반드시 확인해야 합니다.
- 실행 전에 어떤 도구를 호출하는지 반드시 설명해야 합니다.
- 중단하겠다는 사용자의 결정을 반드시 존중해야 합니다.
7. 제시와 복구
비용, 스캔한 데이터, 소요 시간, 실행 가능한 인사이트와 함께 결과를 제시합니다. 실패하면 사용 가능한 워크그룹을 나열하고 어떤 것으로 재시도할지 사용자가 선택하게 합니다.
인수 라우팅
다음 순서로 확인하고 첫 일치에서 중단합니다:
- SQL 키워드(
SELECT,SHOW,DESCRIBE,INSERT등)를 포함 — SQL 텍스트로 보고 직접 실행 profile TABLE_NAME— 종합 테이블 프로파일링 실행(query-patterns.md 참조)- 알려진 이름 있는 쿼리와 일치 — 조회 후 실행
- 알려진 워크그룹과 일치 — 워크그룹 상태와 최근 쿼리 표시
- 알려진 카탈로그와 일치 —
exploring-data-catalog에 위임해 데이터베이스와 테이블 열거 - 인수 없음 — 최근 쿼리 활동과 사용 가능한 테이블 표시
원칙
- 실행 전에 항상 워크그룹을 선택합니다(출력 위치 오류 방지).
- 익숙하지 않은 테이블은 분석 쿼리 전에 프로파일링합니다.
- 사용자가 비용 감각을 쌓을 수 있도록 결과와 함께 비용을 제시합니다.
- 큰 테이블의 탐색 쿼리에는
LIMIT을 제안합니다. - 답이 명확한 도메인 질문은 묻지 않지만, 보안 관련 조치(워크그룹 전환, 출력 위치 변경, SELECT가 아닌 문장)는 항상 확인합니다.
문제 해결
| 오류 | 원인 | 해결 |
|---|---|---|
| 대소문자가 섞인 Redshift 식별자 오류 | Redshift 페더레이션 이름은 소문자만 허용 | 식별자를 소문자로 변경 |
CatalogId 검증 실패 | 카탈로그 이름 대신 ARN 전달 | ARN이 아니라 카탈로그 이름 전달 |
카탈로그 간 information_schema가 아무것도 반환하지 않음 | 카탈로그 한정자 누락 | 카탈로그로 한정한 경로 사용: "catalog".information_schema.tables |
| 쿼리가 출력 위치 오류로 실패 | 워크그룹에 출력 위치가 설정되지 않음 | 출력 위치가 있는 다른 워크그룹을 선택하거나 하나를 설정 |
| 확인 없이 파괴적 문장 실행 | 문장 분류를 건너뜀 | 항상 INSERT/UPDATE/DELETE/DROP/ALTER/CREATE/TRUNCATE/MERGE를 분류하고 사용자에게 확인 |
추가 자료
워크그룹 선택
쿼리를 실행하기 전에 항상 워크그룹 목록을 먼저 확인합니다.
실행 컨텍스트 감지
워크그룹을 선택하기 전에 현재 IAM ID를 확인합니다:
aws sts get-caller-identity --query Arn --output text
ARN 패턴은 실행 컨텍스트를 보여줍니다:
| ARN 패턴 | 컨텍스트 | 워크그룹 전략 |
|---|---|---|
arn:aws:sts::*:assumed-role/AmazonDataZone-<project-id>-<suffix>/<session> | SageMaker Unified Studio 프로젝트 역할 | 프로젝트 범위 워크그룹을 사용합니다(아래 참조) |
arn:aws:sts::*:assumed-role/SageMakerUnifiedStudio-<project-id>-<suffix>/<session> | SageMaker Unified Studio 프로젝트 역할 | 프로젝트 범위 워크그룹을 사용합니다(아래 참조) |
arn:aws:sts::*:assumed-role/AmazonSageMaker-ExecutionRole-* | SageMaker 노트북/스튜디오 역할 | sagemaker-studio-workgroup-*을 우선합니다 |
| 그 외 모든 경우 | 표준 IAM 사용자/역할 | 일반 우선순위를 따릅니다 |
SageMaker 프로젝트 역할 선택
SageMaker 프로젝트 역할(AmazonDataZone-* 또는 SageMakerUnifiedStudio-*)로 실행할 때:
-
역할이 접근할 수 있는 모든 워크그룹을 나열합니다:
aws athena list-work-groups --query 'WorkGroups[].Name' --output json -
역할 ARN에서 프로젝트 ID를 추출합니다. 역할 이름을
-기준으로 나눕니다. 첫 번째 구간은 접두사(예:AmazonDataZone), 두 번째 구간은 프로젝트 ID(예:abc123def), 이후 구간은 접미사(예:DataLakeAccess)입니다. 두 번째 구간을 사용합니다. 프로젝트 ID는 하이픈이 없는 영숫자 문자열입니다. 프로젝트 ID 뒤에 오는 알려진 접미사:DataLakeAccess,SparkAccess,QueryAccess,IngestionAccess. 예:arn:aws:sts::123456789012:assumed-role/AmazonDataZone-abc123def-DataLakeAccess/session ^^^^^^^^^ project ID = abc123def -
워크그룹을 프로젝트와 매칭합니다. 프로젝트 워크그룹은
sagemaker-studio-workgroup-<project-id>패턴을 따르거나 프로젝트 ID를 포함합니다. -
sagemaker-studio-workgroup-*이 정확히 하나만 있으면, 그 접미사가 2단계에서 추출한 프로젝트 ID를 포함하는지 확인합니다. 일치하면 사용합니다. 일치하지 않으면 6단계로 넘어갑니다. -
여러 개가 있으면 역할 ARN에서 추출한 프로젝트 ID와 접미사가 일치하는 것을 선택합니다. ARN 추출이 모호하면 선택적으로 환경 변수
SAGEMAKER_PROJECT_ID또는SAGEMAKER_PROJECT_NAME을 확인합니다. -
sagemaker-studio-workgroup-*이 없으면 다른 워크그룹으로 대체하지 않습니다. 프로젝트 범위 워크그룹을 찾지 못했다고 사용자에게 알리고, 프로젝트 설정이나 IAM 권한을 확인해 달라고 요청합니다.
프로젝트 역할은 보통 자기 워크그룹 범위로 제한된 IAM 권한을 가집니다.
primary 또는 다른 프로젝트의 워크그룹을 사용하려고 하면 AccessDeniedException으로
실패합니다. 이 컨텍스트에서는 primary로 재시도하지 않습니다.
일반 우선순위(비프로젝트 역할)
sagemaker-studio-workgroup-*워크그룹 -- 가장 안정적이며 항상 출력 위치가 설정되어 있습니다.- 출력 위치가 명시적으로 설정된 워크그룹
primary워크그룹(출력 위치가 없을 수 있으므로 주의해서 사용)
오류 복구
| 오류 | 컨텍스트 | 조치 |
|---|---|---|
| 출력 위치 없음 | 모든 경우 | 우선순위에 따라 다음 워크그룹으로 재시도 |
| 워크그룹에서 AccessDeniedException | 프로젝트 역할 | 다른 워크그룹으로 재시도하지 않습니다. 프로젝트 역할에 접근 권한이 없다고 사용자에게 알립니다. |
| 워크그룹에서 AccessDeniedException | 표준 역할 | 우선순위에 따라 다음 워크그룹으로 재시도 |
| 워크그룹 없음 | 모든 경우 | 사용자에게 워크그룹을 설정하거나 IAM 권한을 확인해 달라고 요청 |
안티패턴
- 다른 워크그룹을 먼저 확인하지 않고
primary워크그룹을 기본값으로 사용하지 않습니다. - 세션을 넘어 워크그룹 이름을 하드코딩하지 않습니다.
- SageMaker 프로젝트 역할로 실행 중일 때
primary로 재시도하지 않습니다. AccessDeniedException으로 실패합니다.