0. 핵심 원칙 — 식별자 케이스 폴딩(Case Folding)
가장 먼저 이해해야 할 이식성 규칙이다. 엔진마다 따옴표 없는 식별자(unquoted identifier) 를 다르게 처리한다.
| 엔진 | unquoted 식별자 처리 | 표준 준수 |
|---|---|---|
| 표준 SQL | 대문자로 폴딩 | — |
| Oracle | 대문자로 폴딩 | 준수 |
| PostgreSQL 18 | 소문자로 폴딩 | 비표준 |
| MySQL — 테이블·DB·테이블 별칭 | lower_case_table_names 에 따라 다름 |
비표준 |
| MySQL — 그 밖의 식별자 | 폴딩하지 않고 비교에서만 무시 | 비표준 |
폴딩의 표준 방향은 대문자다. PostgreSQL 문서는 소문자 폴딩이 표준 SQL 과 호환되지 않는다고 스스로 밝힌다 — 표준대로라면 foo 는 "foo" 가 아니라 "FOO" 와 같아야 한다. PostgreSQL 에서 FOO·foo·"foo" 는 같은 식별자이고, "Foo" 와 "FOO" 는 그 셋과도 서로와도 다르다. Oracle 은 따옴표 없는 식별자를 대문자로 해석하므로 표준 쪽에 있다.
IMPORTANT — 결론
- 모든 식별자는 소문자 snake_case 로 작성한다. 대문자에 의미를 부여하는 규칙(대문자 접미사 등)은 PostgreSQL 의 소문자 폴딩에서 형태가 사라진다.
- 식별자 길이는 63자 이하로 유지한다. PostgreSQL 은 63 바이트, MySQL 은 64 문자다. 두 값이 63자에서 만나는 것은 식별자에 ASCII 만 쓸 때뿐이다(1-5).
- 따옴표(
"...",`...`) 없이 쓸 수 있는 이름만 쓴다. PostgreSQL 문서도 이식 가능한 애플리케이션을 쓰려면 특정 이름을 항상 따옴표로 감싸거나 아예 감싸지 말라고 권고한다(0-2).- 제약·인덱스 이름은 스키마 전역에서 유일하게 짓는다. 두 엔진과 표준의 유일성 범위를 모두 만족하는 최소 공통 규칙이다(4-3).
0-1. lower_case_table_names 가 좌우하는 것
이 변수가 좌우하는 대상은 테이블명·데이터베이스명·테이블 별칭 세 가지뿐이다.
| 값 | 디스크 저장 | 이름 비교 |
|---|---|---|
0 |
CREATE 문에 쓴 대소문자 그대로 |
대소문자 구분 |
1 |
소문자로 변환해 저장 | 대소문자 무시 |
2 |
쓴 대소문자 그대로, 조회 시 소문자 변환 | 대소문자 무시 |
기본값은 플랫폼마다 다르다 — Unix 0, Windows 1, macOS 2 다. 값 2 는 대소문자를 구분하지 않는 파일시스템에서만 동작하고, 그런 파일시스템에 0 을 강제하면 MyISAM 인덱스가 손상될 수 있다. 그리고 이 변수는 서버를 초기화할 때만 설정할 수 있다 — 이후 변경은 금지된다. 개발자 macOS(기본 2)와 운영 Linux(기본 0)가 갈리는 지점이므로 테이블명을 소문자로만 쓴다.
컬럼·인덱스·파티션·서브파티션·스토어드 루틴·이벤트·리소스 그룹 이름과 컬럼 별칭은 모든 플랫폼에서 대소문자를 구분하지 않는다. 쓴 대소문자가 보존되고 비교할 때만 무시되며, 이 변수와 무관하다. 트리거 이름도 이 변수의 영향을 받지 않는다. 로그 파일 그룹 이름은 반대로 대소문자를 구분하고, MySQL 문서는 이 동작이 표준 SQL 과 다르다고 밝힌다.
따라서 “MySQL 에서는 컬럼명 대문자가 보존된다” 는 사실이다. 대문자를 섞은 이름이 깨지는 경로는 PostgreSQL 의 소문자 폴딩 하나이고, 그것만으로도 소문자 통일 규칙이 필요하다.
0-2. 따옴표를 쓰면 무엇이 깨지는가
PostgreSQL 문서는 이식 가능한 애플리케이션을 쓰려면 특정 이름을 항상 따옴표로 감싸거나 아예 감싸지 말라고 권고한다. 결론 3번은 그 권고의 뒤쪽을 택한 것이다.
- PostgreSQL:
"Foo"와foo와"FOO"가 서로 다른 세 식별자다. 폴딩 방향이 표준과 반대이므로 Oracle 로 옮기면 Oracle 이 만든"FOO"와 어긋난다. 따옴표는 길이 한계를 우회하지도 못한다 — 인용 식별자에도 63바이트 제한이 적용된다. - MySQL: 기본 인용 문자는 백틱이다. 겹따옴표는
sql_mode의ANSI_QUOTES에 따라 의미가 바뀐다 — 꺼져 있으면 문자열 리터럴이라CREATE TABLE "test" (...)가ERROR 1064이고, 켜면 식별자로 해석되어 통과한다. 같은 DDL 이 서버 설정에 따라 성공하거나 실패한다.
예약어와 충돌하는 이름은 따옴표로 감싸지 말고 이름을 바꾼다(2-2).