-
SQL 안티패턴 감지DB 2026. 4. 28. 01:48
목표
사용자의 SQL 쿼리를 실행 전/후로 분석하여 안티패턴을 감지하고 튜닝 포인트를 제공합니다.
- Dry-run — 실제 실행 없이 쿼리 구조를 정적 분석
- 필수 규칙 강제 — Critical 안티패턴은 차단 또는 강한 경고
- 실행 전 튜닝 포인트 — 정적 분석 / EXPLAIN 기반 개선 제안
- 실행 후 튜닝 포인트 — 실행 통계 기반 병목 진단
참고 도구 분석
도구 안티패턴 수 플랫폼 접근 방식
BigQuery Anti-Pattern Recognition 11개 BigQuery 전용 AST 정적 분석 (ZetaSQL 파서) sqlcheck 29개 범용 RDBMS CLI 정적 분석 (C++) AltimateAI / altimate-code 19개 10개 웨어하우스 (Snowflake·BQ·Databricks 등) AI 기반 + 정적 분석 sqlglot — 31개 방언 (Trino·Databricks·Snowflake 등) Python 파서·트랜스파일러 (자체 구현 기반)
BigQuery Anti-Pattern Recognition
구글이 공식 오픈소스로 제공한 도구입니다. ZetaSQL 파서로 AST를 분석하고, 실제 쿼리 실행 없이 안티패턴을 탐지합니다.
감지 안티패턴 11개
# 이름 설명
1 SimpleSelectStar SELECT * — 불필요한 전체 컬럼 조회 2 SemiJoinWithoutAggregation IN 필터 서브쿼리에서 DISTINCT 누락 3 MultipleCTEReferences 동일 CTE를 2회 이상 참조 (재연산 발생) 4 OrderByWithoutLimit LIMIT 없는 ORDER BY 5 RegexpContainsUsage REGEXP_CONTAINS 대신 LIKE 사용 권고 6 LatestRecordWithAnalyticFun ROW_NUMBER()로 최신 레코드 필터링 7 DynamicPredicate 서브쿼리 필터 → 정적 술어로 변환 권고 8 WhereOrder WHERE 절 필터 순서 — 선택도 높은 조건 우선 9 JoinOrder 테이블 크기 기반 JOIN 순서 최적화 10 MissingDropStatement TEMP 테이블 생성 후 DROP 누락 11 DroppedPersistentTable 스크립트 끝에서 영구 테이블 삭제 감지 설치
# 사전 조건: JDK 11+, Maven, Docker, gcloud CLI gcloud auth application-default login git clone <https://github.com/GoogleCloudPlatform/bigquery-antipattern-recognition.git> cd bigquery-antipattern-recognition # Docker 이미지 빌드 mvn clean package jib:dockerBuild -DskipTests # 또는 JAR 직접 다운로드 wget <https://github.com/GoogleCloudPlatform/bigquery-antipattern-recognition/releases/download/v1.0.0/bigquery-antipattern-recognition.jar>입력 옵션 (Input Flags)
플래그 설명
--query "SELECT ..." CLI에서 SQL 문자열 직접 입력 --read_from_info_schema INFORMATION_SCHEMA.JOBS에서 쿼리 읽기 --read_from_info_schema_days N 읽을 기간 (기본값: 1일) --info_schema_project <project> 분석 대상 프로젝트 --info_schema_region us 리전 지정 --read_from_info_schema_start_time "timestamp" 시작 시간 지정 --read_from_info_schema_end_time "timestamp" 종료 시간 지정 --info_schema_top_n_percentage_of_jobs N 상위 슬롯 소비 비율 (0~1, 예: 0.1 = 상위 10%) --input_bq_table project.dataset.table BigQuery 테이블에서 읽기 (컬럼: id, query) --input_file_path /path/to/file.sql 로컬 또는 GCS 파일에서 읽기 --input_folder_path /path/to/folder 폴더 내 전체 .sql 파일 파싱 --input_csv_file_path /path/to/file.csv CSV 파일에서 읽기 (컬럼: id, query) 출력 옵션 (Output Flags)
플래그 설명
--output_file_path /path/to/output.csv CSV 파일로 출력 --output_table "project.dataset.table" BigQuery 테이블에 결과 저장 (사전 생성 필요) --rewrite_sql Vertex AI로 최적화된 SQL 자동 재작성 (실험 기능) --processing_project_id <project> INFORMATION_SCHEMA 조회 및 결과 저장 프로젝트 실행 예시
인라인 쿼리 분석 (Docker)
docker run -i bigquery-antipattern-recognition \\ --query "SELECT * FROM \\`project.dataset.orders\\` WHERE YEAR(created_at) = 2024"# 출력 예시 SimpleSelectStar: SELECT * at line 1. All columns on table are being selected. Non-sargable predicate: YEAR(created_at) at line 1 disables partition pruning.인라인 쿼리 분석 (JAR)
java -jar bigquery-antipattern-recognition.jar \\ --query "SELECT * FROM \\`project.dataset.table1\\`"INFORMATION_SCHEMA → BigQuery 테이블 저장
docker run -v ~/.config:/root/.config -i bigquery-antipattern-recognition \\ --read_from_info_schema \\ --info_schema_project my-project \\ --info_schema_region us \\ --read_from_info_schema_days 7 \\ --info_schema_top_n_percentage_of_jobs 0.1 \\ --processing_project_id my-project \\ --output_table "my-project.dataset.antipattern_output"AI 기반 SQL 자동 재작성
docker run -v ~/.config:/root/.config -i bigquery-antipattern-recognition \\ --query "SELECT col1 FROM table1 WHERE col2 LIKE '%abc%' AND col3 = 1" \\ --rewrite_sql \\ --processing_project_id my-project로컬 파일 → CSV 출력
docker run -v /local/path:/data -i bigquery-antipattern-recognition \\ --input_file_path /data/query.sql \\ --output_file_path /data/output.csv폴더 내 전체 SQL 파일 분석
docker run -v /local/path:/data -i bigquery-antipattern-recognition \\ --input_folder_path /data/sql_files \\ --output_file_path /data/output.csv출력 테이블 DDL
CREATE OR REPLACE TABLE `project.dataset.antipattern_output_table` ( job_id STRING, user_email STRING, query STRING, recommendation ARRAY<STRUCT<name STRING, description STRING>>, slot_hours FLOAT64, optimized_sql STRING, process_timestamp TIMESTAMP );결과 조회 쿼리
SELECT job_id, user_email, query, recommendation, slot_hours FROM `project.dataset.antipattern_output_table` ORDER BY slot_hours DESC LIMIT 100;
sqlcheck
범용 SQL 안티패턴 탐지 CLI 도구 (C++)입니다. 29개 패턴을 4개 카테고리로 분류하여 분석합니다.
쿼리 안티패턴 16개 (실무 관련도 높음)
코드 이름 설명
3001 SELECT * 전체 컬럼 조회 3002 NULL Usage NULL 오용 3004 String Concatenation 문자열 연결 성능 3005 GROUP BY Usage GROUP BY 오용 3006 ORDER BY RAND RAND() 정렬 — 전체 스캔 3007 Pattern Matching 앞자리 와일드카드 LIKE '%...' 3008 Spaghetti Query 지나치게 복잡한 단일 쿼리 3009 Reduce JOINs 과도한 JOIN 3010 Unnecessary DISTINCT 불필요한 DISTINCT 3012 HAVING Clause HAVING 절 오용 (WHERE로 대체 가능) 3013 Nested Subqueries 중첩 서브쿼리 3014 OR Usage OR 연산자 — 인덱스 미활용 3015 UNION Usage UNION (UNION ALL 권고) 3016 DISTINCT & JOIN DISTINCT + JOIN 조합 설치
# macOS (DMG) wget <https://github.com/jarulraj/sqlcheck/releases/download/v1.3/sqlcheck-x86_64.dmg> cp /Volumes/sqlcheck-x86_64/bin/sqlcheck /usr/local/bin/ # Ubuntu/Debian (.deb) wget <https://github.com/jarulraj/sqlcheck/releases/download/v1.3/sqlcheck-x86_64.deb> dpkg -i sqlcheck-x86_64.deb # CentOS/Fedora (.rpm) wget <https://github.com/jarulraj/sqlcheck/releases/download/v1.3/sqlcheck-x86_64.rpm> yum --nogpgcheck localinstall sqlcheck-x86_64.rpm # 소스 빌드 (g++ 4.9+, CMake 필요) git clone --recursive <https://github.com/jarulraj/sqlcheck.git> ./bootstrap cd build && cmake -DCMAKE_BUILD_TYPE=RELEASE .. && make && make installCLI 플래그
플래그 설명
-f, --file_name 분석할 SQL 파일 경로 -r, --risk_level 탐지 위험도 필터 (1: 전체, 2: MEDIUM 이상, 3: HIGH만) -c, --color_mode 컬러 출력 활성화 -v, --verbose_mode 상세 정보 출력 --stdin 표준 입력에서 SQL 읽기 실행 예시
SQL 파일 분석
sqlcheck -f my_query.sql------------------------------------------------- SQL ANTI-PATTERN REPORT :: my_query.sql ------------------------------------------------- [my_query.sql]: (HIGH RISK) (QUERY ANTI-PATTERN) SELECT * Never use * in a SELECT. Always list out the columns needed. Pattern: SELECT * [my_query.sql]: (LOW RISK) (QUERY ANTI-PATTERN) SPAGHETTI QUERY ALERT This query is too complex. Consider splitting into simpler queries. ====================== Total Anti-Patterns: 2 High Risk: 1 Medium Risk: 0 Low Risk: 1상세 출력 + 색상 모드
sqlcheck -f my_query.sql -v -cHIGH 위험도만 탐지
sqlcheck -f my_query.sql -r 3파이프 입력 (stdin)
echo "SELECT * FROM orders JOIN customers ON 1=1" | sqlcheck --stdin여러 파일 일괄 분석
for f in ./queries/*.sql; do echo "=== $f ===" sqlcheck -f "$f" -r 2 doneCI/CD 파이프라인 연동
# 안티패턴 발견 시 비정상 종료 → CI 실패 처리 가능 sqlcheck -f migration.sql -r 3 || exit 1위험도 레벨
레벨 범위 언제 사용
1 LOW 이상 전체 코드 리뷰 시 2 MEDIUM 이상 일반 개발 환경 3 HIGH만 CI/CD 게이트, 배포 전 필수 체크
AltimateAI / altimate-code
AI 기반 데이터 엔지니어링 도구입니다. 10개 웨어하우스를 지원하며, Claude Code 통합이 가능합니다.
탐지 안티패턴 (19개 규칙, 신뢰도 점수 포함)
- SELECT *
- 카르테시안 조인 (조건 없는 JOIN)
- Non-sargable 조건절 (함수가 필터 컬럼에 적용)
- 상관 서브쿼리 (Correlated Subquery)
-
- 15개 추가 규칙
지원 플랫폼
Snowflake, BigQuery, Databricks, PostgreSQL, Redshift, ClickHouse, DuckDB, MySQL, SQL Server, Oracle, SQLite, MongoDB
주요 기능
- FinOps 분석: 비용 소비 쿼리 탐지, 웨어하우스 크기 최적화
- 열 수준 계보: 조인/CTE/서브쿼리를 통해 컬럼 추적
- dbt 통합: 매니페스트 파싱, 테스트 생성, 영향 분석
- 교차 방언 변환: Snowflake ↔ BigQuery ↔ Databricks SQL 자동 변환
- PII 감지: 30+ 패턴으로 민감 정보 스캔
설치
npm install -g altimate-code # LLM API 키 설정 (하나 이상 필요) export ANTHROPIC_API_KEY=your_key export OPENAI_API_KEY=your_key초기 설정
altimate /connect # LLM 공급자 선택 및 API 키 입력 /discover # dbt 프로젝트, 웨어하우스 연결 자동 감지 /configure-claude # Claude Code와 연동데이터베이스 연결 방식
# ~/.dbt/profiles.yml 자동 감지 또는 직접 설정 my_snowflake: type: snowflake account: myorg.us-east-1 user: myuser password: "{{ env_var('SNOWFLAKE_PASSWORD') }}" database: MY_DB schema: PUBLIC warehouse: MY_WH에이전트 모드
모드 역할 권한 권장 환경
Analyst 데이터 탐색, SELECT 쿼리 읽기 전용 프로덕션 (안전) Builder dbt 모델/SQL 파이프라인 생성 읽기/쓰기 (DROP 금지) 개발 환경 Plan 접근 방식 수립만 파일 읽기만 설계 단계 주요 CLI 명령어 사용 예시
안티패턴 탐지
> Analyze this query for issues: SELECT * FROM orders o JOIN customers c ON o.id = c.order_id WHERE YEAR(o.created_at) = 2024 ORDER BY o.total_amount[HIGH] SELECT * detected — specify required columns (confidence: 98%) [HIGH] Non-sargable predicate: YEAR(created_at) → Fix: created_at >= '2024-01-01' AND created_at < '2025-01-01' [MAJOR] ORDER BY without LIMIT — full sort on potentially large dataset → Fix: add LIMIT clause or use window functionSQL 방언 변환
> /sql-translate this Snowflake query to Databricks: SELECT DATEADD(day, 7, CURRENT_DATE()), ZEROIFNULL(revenue) FROM salesdbt 테스트 자동 생성
> /generate-tests for models/staging/stg_orders.sql비용 리포트 조회
> /cost-report컬럼 계보 추적
> Trace column lineage for customer_id in fact_ordersPII 탐지
> Scan schema my_schema for PII columns지원 LLM
Anthropic Claude · OpenAI · Google Gemini · Amazon Bedrock · Azure OpenAI · Mistral · Groq · Ollama
sqlglot (자체 구현 시 파서 기반)
Python SQL 파서 및 트랜스파일러입니다. Trino·Databricks·Snowflake 등 31개 방언을 공식 지원하며, 자체 안티패턴 엔진 구현 시 기반으로 활용합니다.
설치
pip install sqlglot # C 확장 버전 (성능 향상) pip install "sqlglot[c]"지원 방언 (주요)
방언 지정 키워드
Trino "trino" Databricks "databricks" Snowflake "snowflake" BigQuery "bigquery" Spark SQL "spark" Presto "presto" DuckDB "duckdb" PostgreSQL "postgres" 기본 파싱
import sqlglot from sqlglot import exp, parse_one # 방언을 명시해야 정확한 파싱이 가능합니다 ast = parse_one( "SELECT * FROM orders WHERE YEAR(created_at) = 2024 ORDER BY id", dialect="trino" )AST 순회 방법
# find: 첫 번째 매칭 노드 반환 order = ast.find(exp.Order) # find_all: 모든 매칭 노드 반환 for col in ast.find_all(exp.Column): print(col.alias_or_name) # walk: 전체 노드 순회 for node in ast.walk(): if isinstance(node, exp.Star): print("SELECT * 발견")안티패턴 탐지 예시 코드
from sqlglot import exp, parse_one from dataclasses import dataclass from typing import List @dataclass class Issue: severity: str # CRITICAL / MAJOR / MINOR message: str suggestion: str def detect_antipatterns(query: str, dialect: str = "trino") -> List[Issue]: ast = parse_one(query, dialect=dialect) issues = [] # [CRITICAL] SELECT * for node in ast.find_all(exp.Star): issues.append(Issue( severity="CRITICAL", message="SELECT * 사용 — 불필요한 전체 컬럼 조회", suggestion="필요한 컬럼만 명시하세요" )) # [CRITICAL] Cartesian JOIN (조건 없는 JOIN) for join in ast.find_all(exp.Join): if not join.args.get("on") and not join.args.get("using"): if str(join.args.get("kind", "")).upper() not in ("CROSS",): issues.append(Issue( severity="CRITICAL", message="조건 없는 JOIN 감지 — Cartesian product 발생 가능", suggestion="ON 또는 USING 조건을 추가하세요" )) # [CRITICAL] Non-sargable predicate (WHERE 절 함수 적용) where = ast.find(exp.Where) if where: for func in where.find_all(exp.Func): if any(isinstance(c, exp.Column) for c in func.find_all(exp.Column)): issues.append(Issue( severity="CRITICAL", message=f"WHERE 절 함수 적용: {func.sql()} — 파티션 프루닝 불가", suggestion="함수를 우변으로 이동하거나 범위 조건으로 변환하세요" )) # [MAJOR] ORDER BY without LIMIT if ast.find(exp.Order) and not ast.find(exp.Limit): issues.append(Issue( severity="MAJOR", message="ORDER BY에 LIMIT 없음 — 전체 데이터 정렬 발생", suggestion="LIMIT 절을 추가하세요" )) # [MAJOR] UNION (UNION ALL 권고) for union in ast.find_all(exp.Union): if not isinstance(union, exp.UnionAll): issues.append(Issue( severity="MAJOR", message="UNION 사용 — 중복 제거 정렬 비용 발생", suggestion="중복 허용 시 UNION ALL로 변경하세요" )) return issues # 실행 예시 query = """ SELECT * FROM orders o JOIN customers c ON 1=1 WHERE YEAR(o.created_at) = 2024 ORDER BY o.id """ for issue in detect_antipatterns(query, dialect="trino"): print(f"[{issue.severity}] {issue.message}") print(f" → {issue.suggestion}") print()[CRITICAL] SELECT * 사용 — 불필요한 전체 컬럼 조회 → 필요한 컬럼만 명시하세요 [CRITICAL] 조건 없는 JOIN 감지 — Cartesian product 발생 가능 → ON 또는 USING 조건을 추가하세요 [CRITICAL] WHERE 절 함수 적용: YEAR(o.created_at) — 파티션 프루닝 불가 → 함수를 우변으로 이동하거나 범위 조건으로 변환하세요 [MAJOR] ORDER BY에 LIMIT 없음 — 전체 데이터 정렬 발생 → LIMIT 절을 추가하세요방언 간 SQL 변환
import sqlglot # Snowflake → Trino 변환 result = sqlglot.transpile( "SELECT DATEADD(day, 7, CURRENT_DATE()), ZEROIFNULL(revenue) FROM sales", read="snowflake", write="trino" )[0] print(result) # → SELECT DATE_ADD('day', 7, CURRENT_DATE), COALESCE(revenue, 0) FROM sales # Databricks → Snowflake 변환 result = sqlglot.transpile( "SELECT DATE_FORMAT(order_date, 'yyyy-MM-dd') FROM orders", read="databricks", write="snowflake" )[0] print(result)구문 오류 탐지
import sqlglot try: sqlglot.transpile("SELECT foo FROM (SELECT baz FROM t") except sqlglot.errors.ParseError as e: for err in e.errors: print(f"Line {err['line']}, Col {err['col']}: {err['description']}") print(f"Context: ...{err['start_context']}{err['highlight']}...")Line 1, Col 34: Expecting ) Context: ...SELECT foo FROM (SELECT baz FROM t...Scope API (서브쿼리·CTE 정확한 분석)
from sqlglot import parse_one, exp from sqlglot.optimizer.scope import build_scope query = """ WITH cte AS (SELECT id FROM orders) SELECT * FROM cte JOIN cte AS cte2 ON cte.id = cte2.id """ ast = parse_one(query, dialect="trino") root = build_scope(ast) # CTE 중복 참조 탐지 for scope in root.traverse(): cte_refs = {} for name, (node, source) in scope.selected_sources.items(): if isinstance(source, exp.Subquery): cte_name = source.alias cte_refs[cte_name] = cte_refs.get(cte_name, 0) + 1 for cte_name, count in cte_refs.items(): if count >= 2: print(f"[MAJOR] CTE '{cte_name}' 중복 참조 ({count}회) — 반복 연산 발생")
통합 안티패턴 카탈로그
🔴 Critical — 반드시 수정 (실행 차단 권고)
안티패턴 설명 영향
SELECT * 전체 컬럼 조회 스캔 비용 폭증, 컬럼 추가 시 부작용 Cartesian JOIN 조건 없는 JOIN (CROSS JOIN) 행 수 곱 증가 → OOM·무한 실행 Non-sargable predicate 필터 컬럼에 함수 적용: WHERE YEAR(date) = 2024 파티션 프루닝·인덱스 무력화 Correlated subquery in WHERE 행마다 서브쿼리 재실행 O(N²) 복잡도 🟠 Major — 강하게 권고
안티패턴 설명 영향
ORDER BY without LIMIT 전체 정렬 후 페이지네이션 없음 전체 데이터 메모리 적재 CTE 중복 참조 동일 CTE를 여러 번 참조 반복 연산 (DB에 따라 materialized 미보장) IN 서브쿼리 without DISTINCT IN (SELECT id FROM ...) 중복 비교로 성능 저하 DISTINCT + JOIN 조합 JOIN 후 DISTINCT로 중복 제거 불필요한 해시 빌드 중첩 서브쿼리 SELECT·FROM 절 내 서브쿼리 중첩 최적화 불가 구간 생성 LIKE '%keyword' 앞자리 와일드카드 전체 스캔 강제 UNION (UNION ALL 대신) 중복 제거 정렬 포함 추가 정렬 비용 🟡 Minor — 권고
안티패턴 설명
HAVING (WHERE로 대체 가능) 집계 전 필터는 WHERE로 이동 ORDER BY RAND() 전체 스캔 후 랜덤 정렬 불필요한 DISTINCT 중복이 없는 상황에서 DISTINCT 사용 지나치게 복잡한 단일 쿼리 CTE로 분리 권고 OR 연산자 남용 UNION ALL 또는 IN으로 대체 가능 REGEXP_CONTAINS (BigQuery) 단순 패턴은 LIKE로 충분
플랫폼별 특화 안티패턴
Trino
안티패턴 설명 탐지 시점
소파일 과다 (Too many splits) 파티션당 소파일 → 과도한 split 생성 EXPLAIN 분석 Dynamic filtering 미활용 브로드캐스트 조인 없이 대형 테이블 풀스캔 EXPLAIN Predicate pushdown 비활성 커넥터에 필터가 내려가지 않음 EXPLAIN JOIN 순서 비최적 큰 테이블이 build side가 됨 EXPLAIN 컬럼형 포맷 미사용 ORC/Parquet 대신 CSV/JSON 정적 분석 Databricks / Spark
안티패턴 설명 탐지 시점
UDF 남용 Python UDF → Spark native 함수로 대체 정적 분석 collect() 호출 드라이버에 전체 데이터 수집 → OOM 정적 분석 explode() 후 집계 없는 JOIN 행 폭발 후 바로 조인 정적 분석 Shuffle partition 미조정 기본 200 파티션 그대로 사용 EXPLAIN EXTENDED autoMerge 스키마 진화 예상 못한 스키마 변경 정적 분석 Liquid Clustering 미사용 Z-order 대신 Liquid Clustering 미전환 메타데이터 분석 Small file 누적 OPTIMIZE/VACUUM 미실행 메타데이터 분석 Snowflake
안티패턴 설명 탐지 시점
필터 컬럼에 함수 적용 WHERE DATE_TRUNC(...) → 파티션 프루닝 불가 정적 분석 Clustering key 미사용 대형 테이블 파티션 pruning 없음 EXPLAIN / 메타데이터 VARIANT/JSON 전체 스캔 반구조 데이터 전체 파싱 정적 분석 Small file INSERT COPY INTO 대신 단건 INSERT 반복 정적 분석 Warehouse 과대 설정 쿼리 복잡도 대비 X-Large 사용 실행 후 통계 RESULT_SCAN 미활용 동일 쿼리 반복 실행 (캐시 미활용) 히스토리 분석
구현 방향
전체 흐름
쿼리 입력 ↓ [1] 정적 분석 (AST) → Critical/Major 즉시 차단·경고 ↓ [2] EXPLAIN 분석 → 실행 계획 기반 추가 경고 ↓ [3] 실행 (선택) ↓ [4] 실행 후 프로파일 분석 → 실제 비용 기반 튜닝 포인트Pre-execution: 정적 분석 (Dry-run)
실제 실행 없이 SQL 텍스트 → AST 파싱 → 패턴 매칭 방식으로 동작합니다.
- 추천 도구: sqlglot (Python) — Trino·Databricks·Snowflake 방언 모두 지원, AST 변환 가능
- 탐지 가능: SELECT *, Cartesian JOIN, Non-sargable predicate, UNION vs UNION ALL, 중첩 서브쿼리, ORDER BY without LIMIT 등
Pre-execution: EXPLAIN 분석
DB에 EXPLAIN을 실행하여 (데이터 스캔 없음) 실행 계획을 파싱합니다.
플랫폼 명령어 얻을 수 있는 정보
Trino EXPLAIN query 논리/분산 실행 계획, 예상 행 수 Databricks EXPLAIN EXTENDED query 논리/물리 플랜, AQE 정보 Snowflake EXPLAIN USING TABULAR query 파티션 프루닝 여부, 예상 스캔 크기 BigQuery dry_run=True (API) 예상 바이트 스캔 비용 EXPLAIN으로 탐지 가능한 항목: Full scan (파티션 프루닝 없음), 비효율적 JOIN 순서, 브로드캐스트 JOIN 미활용, 동적 필터 미적용입니다.
Post-execution: 프로파일 분석
실행 완료 후 통계 데이터를 수집하여 실제 병목을 진단합니다.
플랫폼 데이터 소스 분석 포인트
Trino system.runtime.queries 실제 스캔 바이트, CPU 시간, 스필 여부 Databricks Spark UI / DESCRIBE HISTORY 스테이지별 실행 시간, 셔플 크기 Snowflake Query Profile / QUERY_HISTORY 파티션 스캔율, Spill to disk, 원격 스필 BigQuery INFORMATION_SCHEMA.JOBS 실제 바이트 처리, Slot ms 우선순위 체계
심각도 액션 예시
🔴 Critical 실행 차단 또는 명시적 확인 요구 Cartesian JOIN, Non-sargable 🟠 Major 경고 + 수정 제안 코드 제공 ORDER BY without LIMIT, CTE 중복 참조 🟡 Minor 선택적 최적화 제안 UNION → UNION ALL, OR → IN 추천 구현 스택
- SQL 파싱: sqlglot (Python) — 다방언 지원, AST 변환, 방언 간 변환 가능
- 안티패턴 규칙 엔진: 규칙 기반 (Rule-based) + LLM 보완
- EXPLAIN 파싱: 플랫폼별 EXPLAIN 출력 파서 (JSON 형태 권장)
- 레퍼런스 아키텍처: BigQuery Anti-Pattern Recognition (오픈소스) 참고
도구 선택 가이드
상황 추천 도구
BigQuery 환경에서 전체 쿼리 자동 감사 BigQuery Anti-Pattern Recognition DB 무관한 SQL 파일 빠른 CLI 검사 sqlcheck Snowflake·Databricks 멀티 웨어하우스 + AI 제안 AltimateAI/altimate-code 자체 안티패턴 엔진 개발, 다방언 지원 필요 sqlglot CI/CD 게이트에서 HIGH 패턴만 차단 sqlcheck (-r 3) 방언 간 SQL 마이그레이션 sqlglot (transpile)
참고 링크