공공부하자개발 · 영어 학습 노트
SQL
DB별 비교 요약Oracle·Tibero·MySQL·MSSQL 대응표0/3 완료
  • 01함수·표현식 대응표
  • 02쿼리 문법 대응표
  • 03DDL·운영 대응표
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › DB별 비교 요약 › 03 / 3

DDL·운영 대응표

타입, 제약, 채번, 인덱스, 파티션, 트랜잭션, 락, 실행 계획, 통계, 프로시저
섹션 12진행 0 / 3

DDL·운영 대응표: 타입, 제약, 채번, 인덱스, 파티션, 트랜잭션, 락, 실행 계획, 통계, 프로시저

테이블을 만들고 운영할 때 Oracle·Tibero, MySQL, MSSQL 이 어떻게 다른지 한 페이지에 모았습니다. Ctrl+F 로 기능 이름(예: IDENTITY, SAVEPOINT, SKIP LOCKED, INVISIBLE)을 검색하면 됩니다. 원리는 각 절 끝에 적은 레슨에서 다루고, 여기서는 바로 찾아 쓰는 표와 짧은 코드만 담습니다. Tibero 는 Oracle 호환이라 Oracle 과 묶고, 다른 점만 따로 적습니다.

01한눈에 보기

자주 헷갈리는 10가지입니다.

기능 Oracle·Tibero MySQL MSSQL
한글 문자열 타입 VARCHAR2(n CHAR) VARCHAR(n) (문자 수) NVARCHAR(n)
DDL 과 트랜잭션 암묵적 커밋 암묵적 커밋 트랜잭션 안에서 롤백 가능
채번 방식 시퀀스, IDENTITY (12c) AUTO_INCREMENT IDENTITY, SEQUENCE (2012)
UNIQUE 컬럼의 NULL 여러 개 허용 여러 개 허용 하나만 허용
함수 기반 인덱스 지원 8.0.13 부터 계산 열 + 인덱스
클러스터드 인덱스 없음 (힙) PK 가 클러스터드 PK 가 기본 클러스터드
자동 커밋 도구가 정함 켬 켬
기본 격리 수준 READ COMMITTED REPEATABLE READ READ COMMITTED
락 대기 기본값 무한 50초 무한
데드락 시 롤백 범위 문장만 희생 트랜잭션 전체 희생 트랜잭션 전체

핵심은 세 가지입니다.

  • Oracle 의 VARCHAR2(n) 은 기본이 바이트 단위라 한글이 3바이트로 셉니다.
  • DDL 은 Oracle·MySQL 에서 실행 즉시 커밋되어 롤백할 수 없습니다.
  • MSSQL 만 UNIQUE 컬럼에 NULL 을 하나만 허용합니다.
02타입·DDL

문자열 길이 단위와 컬럼 변경 문법이 DB마다 다릅니다.

기능 Oracle·Tibero MySQL MSSQL
기본 문자열 타입 VARCHAR2(n) (바이트) VARCHAR(n) (문자) VARCHAR(n) (바이트)
문자 단위 지정 VARCHAR2(n CHAR) 기본이 문자 단위 NVARCHAR(n)
한글 저장 바이트면 3바이트씩 문자 수로 셈 NVARCHAR 사용
빈 문자열 '' NULL 로 저장 빈 문자열 그대로 빈 문자열 그대로
타입만 변경 MODIFY MODIFY COLUMN ALTER COLUMN
이름과 타입 동시 변경 RENAME COLUMN 후 MODIFY CHANGE COLUMN 한 번 sp_rename 후 ALTER COLUMN
DDL 실행 시 암묵적 커밋 암묵적 커밋 트랜잭션 안에서 롤백 가능
테이블 복사 CREATE TABLE AS SELECT CREATE TABLE AS SELECT SELECT INTO
참조되는 표 TRUNCATE 불가 (FK) 불가 (FK) 불가 (FK)

컬럼 변경 문법은 아래와 같습니다. 이름과 타입을 같이 바꿀 때 문장 수가 다릅니다.

sql
-- Oracle · Tibero
ALTER TABLE emp RENAME COLUMN name TO ename;
ALTER TABLE emp MODIFY (ename VARCHAR2(50 CHAR));

-- MySQL
ALTER TABLE emp CHANGE COLUMN name ename VARCHAR(50);

-- MSSQL
EXEC sp_rename 'emp.name', 'ename', 'COLUMN';
ALTER TABLE emp ALTER COLUMN ename NVARCHAR(50);
주의

Oracle 은 '' 를 NULL 로 저장합니다. NOT NULL 컬럼에 '' 를 넣으면 오류이고, col = '' 조건은 항상 알 수 없음이 됩니다. MySQL·MSSQL 은 빈 문자열이 값입니다.

DDL 을 배포 스크립트에 넣을 때는 이 차이가 중요합니다. Oracle·MySQL 은 중간에 실패해도 앞 문장이 이미 반영됩니다. MSSQL 은 BEGIN TRAN 으로 묶어 롤백할 수 있습니다.

관련 레슨은 SQL 중급의 DDL·제약 레슨, 실무의 데이터 이관·검증 레슨입니다.

03제약

제약은 문법보다 NULL 을 다루는 방식과 버전이 다릅니다.

기능 Oracle·Tibero MySQL MSSQL
UNIQUE 와 NULL 여러 개 허용 여러 개 허용 하나만 허용
NULL 허용 UNIQUE 우회 해당 없음 해당 없음 필터 인덱스
CHECK 지원 8.0.16 부터 동작 지원
CHECK 옛 버전 해당 없음 8.0.16 전에는 무시 해당 없음
ON UPDATE 절 없음 지원 지원
함수 기반 유니크 함수 기반 유니크 인덱스 ((식)) 유니크 인덱스 (8.0.13) 계산 열 + 유니크 인덱스

함수 기반 유니크는 대소문자 무시 같은 요구에 씁니다. 아래 는 이름을 대문자로 바꾼 값이 중복되지 않게 합니다.

sql
-- Oracle · Tibero
CREATE UNIQUE INDEX ux_emp_uname ON emp (UPPER(name));

-- MySQL (8.0.13 부터)
CREATE UNIQUE INDEX ux_emp_uname ON emp ((UPPER(name)));

-- MSSQL
ALTER TABLE emp ADD uname AS UPPER(name);
CREATE UNIQUE INDEX ux_emp_uname ON emp (uname);

MySQL 8.0.16 이전에는 CHECK 를 써도 오류 없이 무시했습니다. 옛 버전에서 이관한 스키마는 제약이 실제로 걸려 있는지 확인합니다.

관련 레슨은 SQL 중급의 제약 레슨입니다.

04채번

번호를 자동으로 붙이는 방식입니다.

기능 Oracle·Tibero MySQL MSSQL
시퀀스 객체 있음 없음 SEQUENCE (2012)
자동 증가 컬럼 IDENTITY (12c) AUTO_INCREMENT IDENTITY
다음 번호 seq.NEXTVAL 자동 NEXT VALUE FOR seq
방금 번호 조회 seq.CURRVAL LAST_INSERT_ID() SCOPE_IDENTITY()
조회 조건 같은 세션에서 NEXTVAL 후 같은 연결 @@IDENTITY 는 트리거 영향
재시작 후 카운터 시퀀스는 유지 8.0 부터 유지 유지
롤백 시 번호 되돌아가지 않음 되돌아가지 않음 되돌아가지 않음

시퀀스와 IDENTITY 는 롤백해도 번호가 되돌아가지 않아 구멍이 생깁니다. 구멍 없는 번호가 필요하면 채번 테이블을 씁니다.

  • 최대값에 1 을 더하는 방식은 동시에 실행하면 충돌합니다.
  • PK 로 충돌을 막고 재시도하거나, 채번 테이블에서 UPDATE 를 먼저 실행해 행을 잠급니다.
  • 번호를 잠그며 읽는 문법은 DB마다 다릅니다.
기능 Oracle·Tibero MySQL MSSQL
잠그며 읽기 SELECT ... FOR UPDATE SELECT ... FOR UPDATE WITH (UPDLOCK, HOLDLOCK)
한 문장 채번 UPDATE ... RETURNING INTO LAST_INSERT_ID(식) UPDATE ... OUTPUT inserted.x
0 채우기 LPAD LPAD RIGHT('0000' + CAST(...))

한 문장 채번은 아래와 같습니다. 세 DB 모두 갱신과 조회가 한 번에 끝나 동시 실행에도 번호가 겹치지 않습니다.

sql
-- Oracle · Tibero (PL/SQL 안)
UPDATE seq_tab SET last_no = last_no + 1
 WHERE name = 'ORD'
RETURNING last_no INTO v_no;

-- MySQL
UPDATE seq_tab SET last_no = LAST_INSERT_ID(last_no + 1)
 WHERE name = 'ORD';
SELECT LAST_INSERT_ID();

-- MSSQL
UPDATE seq_tab SET last_no = last_no + 1
OUTPUT inserted.last_no
 WHERE name = 'ORD';

LPAD 는 자릿수를 넘으면 앞이 아니라 뒤가 잘립니다(Oracle·MySQL). 자릿수를 넉넉히 잡습니다.

IDENTITY 컬럼에 큰 값을 직접 넣었을 때 Oracle 은 카운터가 따라가지 않아 이후 충돌할 수 있습니다. MySQL AUTO_INCREMENT 와 MSSQL IDENTITY 는 더 큰 값을 따라갑니다.

관련 레슨은 SQL 실무의 채번 레슨입니다.

05인덱스

인덱스 종류와 사용 여부를 확인하는 방법입니다.

기능 Oracle·Tibero MySQL MSSQL
클러스터드 힙 (IOT 는 예외) InnoDB PK PK 가 기본 클러스터드
함수 기반 지원 ((식)) (8.0.13) 계산 열 + 인덱스
INCLUDE 컬럼 없음 없음 지원
단일 컬럼과 NULL NULL 을 저장하지 않음 저장함 저장함
커버링 표시 BY INDEX ROWID 사라짐 Using index Key Lookup 사라짐
Skip Scan 지원 8.0.13 부터 없음
보조 인덱스 구조 ROWID 를 가짐 PK 를 포함 클러스터드 키를 포함

Oracle 의 단일 컬럼 B-tree 인덱스는 NULL 을 저장하지 않아 IS NULL 조건에 쓸 수 없습니다. 조회가 잦으면 복합 인덱스나 다른 표현을 씁니다.

인덱스가 실제로 쓰이는지 확인하는 방법과 임시로 숨기는 방법은 아래 표입니다.

기능 Oracle·Tibero MySQL MSSQL
사용 기록 조회 MONITORING USAGE, DBA_INDEX_USAGE (12cR2) sys.schema_unused_indexes dm_db_index_usage_stats
기록 초기화 해당 없음 재시작 후 초기화 재시작 후 초기화
인덱스 숨기기 INVISIBLE (11g) INVISIBLE (8.0) DISABLE
되돌리기 VISIBLE 로 즉시 VISIBLE 로 즉시 REBUILD 필요

MSSQL 의 사용 기록은 재시작하면 초기화됩니다. 재시작 직후의 "사용 안 함" 을 보고 인덱스를 지우지 않습니다.

관련 레슨은 대용량·배치 03 인덱스 튜닝입니다.

06파티션

큰 표를 조각으로 나누는 기능입니다.

기능 Oracle·Tibero MySQL MSSQL
방식 RANGE·LIST·HASH RANGE·LIST·HASH 범위만
자동 생성 INTERVAL (11g) 없음 없음
나누는 기준 정의 PARTITION BY PARTITION BY 파티션 함수 + 구성표
경계 방향 VALUES LESS THAN VALUES LESS THAN RANGE LEFT·RIGHT
조각 교체 EXCHANGE PARTITION EXCHANGE PARTITION SWITCH
조각 비우기 TRUNCATE PARTITION TRUNCATE PARTITION TRUNCATE 의 WITH (PARTITIONS) (2016)
프루닝 확인 실행 계획 EXPLAIN 의 partitions 열 실행 계획
라이선스 Enterprise 유료 옵션 기본 2016 SP1 부터 Standard 허용

제약이 DB마다 다릅니다.

  • MySQL 은 모든 유니크 키에 파티션 키를 포함해야 하고 외래 키를 쓸 수 없습니다.
  • Oracle 은 글로벌 인덱스가 조각 삭제 뒤 깨지므로 UPDATE GLOBAL INDEXES 를 붙입니다.
  • MSSQL 은 범위 분할만 있어 목록·해시 분할은 다른 방식으로 흉내 냅니다.

Oracle 의 INTERVAL 파티션은 아래 처럼 첫 조각만 정의하면 새 달의 데이터가 들어올 때 조각이 자동으로 생깁니다.

sql
-- Oracle · Tibero
CREATE TABLE ord_log (
    id       NUMBER
  , ord_date DATE
)
PARTITION BY RANGE (ord_date)
INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))
(
    PARTITION p0 VALUES LESS THAN (DATE '2026-01-01')
);

파티션의 목적은 조각 단위 삭제·교체와 프루닝입니다. 조건에 파티션 키가 없으면 모든 조각을 읽습니다.

관련 레슨은 대용량·배치 05 파티션입니다.

07트랜잭션·격리

시작과 종료 방식, 오류 시 동작이 다릅니다.

기능 Oracle·Tibero MySQL MSSQL
시작 첫 DML START TRANSACTION, BEGIN BEGIN TRAN
암묵적 시작 항상 autocommit=0 이면 IMPLICIT_TRANSACTIONS ON
자동 커밋 도구가 정함 켬 켬
도구별 예 SQL*Plus 끔, JDBC 켬 해당 없음 해당 없음
저장점 SAVEPOINT s SAVEPOINT s SAVE TRAN s
저장점 롤백 ROLLBACK TO [SAVEPOINT] s ROLLBACK TO [SAVEPOINT] s ROLLBACK TRAN s
오류 시 기본 문장만 취소 문장만 취소 문장만 취소
전체 취소로 바꾸기 해당 없음 해당 없음 XACT_ABORT ON
기본 격리 READ COMMITTED REPEATABLE READ READ COMMITTED

Oracle 의 BEGIN 은 트랜잭션 시작이 아니라 PL/SQL 블록 시작입니다. 트랜잭션은 첫 DML 에서 시작합니다.

MySQL 의 REPEATABLE READ 스냅샷은 트랜잭션 시작 시점이 아니라 첫 읽기 시점에 만들어집니다.

저장점 사용은 아래와 같습니다. 저장점 이후만 취소하고 앞 작업은 유지합니다.

sql
-- Oracle · Tibero, MySQL
SAVEPOINT s1;
ROLLBACK TO SAVEPOINT s1;

-- MSSQL
SAVE TRAN s1;
ROLLBACK TRAN s1;
주의

오류가 나도 기본은 그 문장만 취소되고 트랜잭션은 열려 있습니다. 앞 문장이 남은 채 커밋하지 않도록 애플리케이션이 롤백을 결정해야 합니다. MSSQL 은 SET XACT_ABORT ON 으로 전체 취소로 바꿉니다.

관련 레슨은 SQL 실무의 트랜잭션 레슨입니다.

08락

락 대기와 데드락 처리는 운영 중 가장 자주 부딪히는 차이입니다.

기능 Oracle·Tibero MySQL MSSQL
기본 대기 한도 무한 50초 무한
대기 지정 NOWAIT, WAIT n innodb_lock_wait_timeout SET LOCK_TIMEOUT
시간 초과 오류 WAIT n 지정 시 오류 1205 1222 (설정 시)
데드락 오류 ORA-00060 1213 1205
데드락 롤백 범위 문장만 희생 트랜잭션 전체 희생 트랜잭션 전체
작업 큐 잠금 SKIP LOCKED SKIP LOCKED (8.0) UPDLOCK + READPAST
FK 컬럼 인덱스 수동 InnoDB 자동 수동

오류 번호가 같은 1205 라도 MySQL 은 시간 초과, MSSQL 은 데드락입니다. 오류 번호만 보고 재시도 로직을 공유하지 않습니다.

Oracle 은 데드락에서 걸린 문장만 롤백하고 트랜잭션은 남아 있습니다. 애플리케이션이 롤백하지 않으면 락이 계속 잡혀 있습니다.

FK 컬럼에 인덱스가 없을 때 Oracle 은 부모 행을 지우거나 키를 바꾸면 자식 표를 잠급니다. MySQL InnoDB 는 인덱스를 자동으로 만들어 주지만 MSSQL·Oracle 은 직접 만듭니다.

작업 큐처럼 잠긴 행을 건너뛰는 문법은 아래와 같습니다.

sql
-- Oracle · Tibero, MySQL 8.0
SELECT
       id
  FROM job
 WHERE status = 'WAIT'
 ORDER BY id
   FOR UPDATE SKIP LOCKED;

-- MSSQL
SELECT TOP (10)
       id
  FROM job WITH (UPDLOCK, READPAST)
 WHERE status = 'WAIT'
 ORDER BY id;

Oracle 에서 FETCH FIRST 와 FOR UPDATE 를 같이 쓰면 ORA-02014 입니다. 또 ROWNUM 조건은 SKIP LOCKED 보다 먼저 적용되어 원하는 건수를 못 채울 수 있습니다.

MSSQL 은 LOCK_TIMEOUT 을 설정하지 않으면 무한 대기입니다. Oracle 도 기본은 무한이라, 운영 배치에는 대기 한도를 명시합니다.

관련 레슨은 대용량·배치 07 락과 데드락입니다.

09실행 계획·통계·힌트

계획을 보는 명령과 통계 수집, 힌트 형태입니다.

기능 Oracle·Tibero MySQL MSSQL
예상 계획 EXPLAIN PLAN FOR + DBMS_XPLAN.DISPLAY EXPLAIN SHOWPLAN_TEXT, SSMS Ctrl+L
실제 계획 ALLSTATS LAST 형식 EXPLAIN ANALYZE (8.0.18) STATISTICS PROFILE, SSMS Ctrl+M
실제 행 수 열 A-Rows (예상은 E-Rows) EXPLAIN ANALYZE 출력 STATISTICS PROFILE 의 Rows
트리 형식 해당 없음 FORMAT=TREE (8.0.16) 해당 없음
통계 수집 DBMS_STATS ANALYZE TABLE UPDATE STATISTICS
자동 수집 10g 부터 변경 10% 에서 자동 재계산 기본 AUTO_UPDATE 기본
히스토그램 DBMS_STATS 옵션 UPDATE HISTOGRAM (8.0) 통계 객체에 늘 포함
힌트 형태 /*+ ... */ USE INDEX, /*+ */ (5.7.7) WITH (INDEX()), OPTION ()
힌트 오류 조용히 무시 해당 없음 해당 없음

Oracle 에서 실제 행 수를 보려면 통계 수집 힌트를 붙여 실행한 뒤 커서 계획을 봅니다. 아래와 같습니다.

sql
-- Oracle · Tibero
SELECT /*+ GATHER_PLAN_STATISTICS */ COUNT(*) FROM orders;
SELECT * FROM TABLE(
    DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST')
);

예상 행 수(E-Rows)와 실제 행 수(A-Rows)가 크게 다르면 통계가 낡았거나 조건 추정이 틀린 것입니다.

DB별 통계 수집 명령은 아래와 같습니다.

sql
-- Oracle · Tibero
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'ORDERS');

-- MySQL
ANALYZE TABLE orders;
ANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 16 BUCKETS;

-- MSSQL
UPDATE STATISTICS orders WITH FULLSCAN;
주의

비용 숫자는 DB 간 비교가 무의미합니다. 같은 쿼리의 계획 변화를 같은 DB 안에서 비교합니다. Oracle 힌트는 이름이 틀려도 오류 없이 무시되므로 계획을 다시 확인합니다.

바인드 값에 따라 계획이 달라지는 문제는 DB마다 이름이 다릅니다. Oracle 은 바인드 피킹(11g 적응형 커서 공유)이고, MSSQL 은 파라미터 스니핑입니다. MSSQL 은 RECOMPILE·OPTIMIZE FOR 로 다룹니다. Query Store 는 2016 부터입니다.

관련 레슨은 대용량·배치 01 실행 계획 읽기, 04 통계 정보와 힌트입니다.

10대량 처리·삭제

대량 적재와 청크 처리, 공간 회수 문법입니다.

기능 Oracle·Tibero MySQL MSSQL
적재 도구 SQL*Loader, APPEND LOAD DATA BULK INSERT, bcp
여러 행 VALUES 23ai 지원 2008 (1000행)
JDBC 배치 드라이버 배치 rewriteBatchedStatements=true 드라이버 배치
청크 삭제 ROWNUM, 키 범위 DELETE ... LIMIT DELETE TOP (n)
청크 갱신 서브쿼리 안 FETCH FIRST UPDATE ... LIMIT UPDATE TOP (n)
LIMIT 범위 해당 없음 단일 표만 순서 비보장
삭제 행 받기 DELETE ... RETURNING INTO 해당 없음 DELETE ... OUTPUT deleted.*
공간 회수 SHRINK SPACE (10g), MOVE OPTIMIZE TABLE REBUILD

청크 삭제는 한 번에 지우지 않고 잘라서 커밋합니다. 아래 은 DB별 한 번의 청크 삭제입니다.

sql
-- Oracle · Tibero
DELETE FROM orders
 WHERE status = 'DONE'
   AND ROWNUM <= 10000;

-- MySQL
DELETE FROM orders
 WHERE status = 'DONE'
 LIMIT 10000;

-- MSSQL
DELETE TOP (10000) FROM orders
 WHERE status = 'DONE';

MySQL 의 DELETE ... LIMIT 은 단일 표에서만 되고, IN (서브쿼리) 안에는 LIMIT 을 쓸 수 없습니다. 서브쿼리의 FETCH FIRST 도 MySQL 에서는 안 됩니다.

Oracle 의 MOVE 는 인덱스를 UNUSABLE 로 만들어 다시 만들어야 합니다. MSSQL 의 SHRINKFILE 은 신중히 씁니다.

지울 양이 표의 대부분이면 DELETE 를 나누기보다 남길 행만 새 표에 복사하고 바꾸는 편이 빠릅니다. 청크 삭제는 일부만 지울 때 씁니다.

관련 레슨은 대용량·배치 06 대량 DML·배치 커밋, 08 대용량 삭제·아카이빙입니다.

11프로시저

프로시저 정의와 호출 문법입니다.

기능 Oracle·Tibero MySQL MSSQL
본문 형태 IS BEGIN ... END BEGIN ... END AS BEGIN ... END
Tibero tbPSM 해당 없음 해당 없음
구분자 변경 해당 없음 DELIMITER (클라이언트 명령) 해당 없음
파라미터 IN·OUT IN·OUT @p, 출력은 OUTPUT
영향 행 수 SQL%ROWCOUNT ROW_COUNT() @@ROWCOUNT
예외 처리 EXCEPTION WHEN DECLARE HANDLER TRY ... CATCH (2005)
오류 발생 RAISE_APPLICATION_ERROR SIGNAL SQLSTATE '45000' THROW (2012)
다시 던지기 RAISE RESIGNAL THROW; (CATCH 안)
호출 EXEC p 또는 BEGIN p; END; CALL p(@b) EXEC p
교체 생성 CREATE OR REPLACE 없음 CREATE OR ALTER (2016 SP1)

RAISE_APPLICATION_ERROR 의 오류 번호는 -20000 부터 -20999 까지 씁니다.

SQL%ROWCOUNT·ROW_COUNT()·@@ROWCOUNT 는 직전 DML 의 영향 행 수입니다. 다른 문장이 끼면 값이 바뀌므로 DML 바로 다음에 읽습니다.

같은 일을 하는 프로시저를 아래 에서 DB별로 비교합니다. 부서 코드를 받아 인상하고 영향 행 수를 돌려줍니다.

sql
-- Oracle · Tibero
CREATE OR REPLACE PROCEDURE raise_sal(p_dept IN VARCHAR2, p_cnt OUT NUMBER) IS
BEGIN
    UPDATE emp SET sal = sal + 10 WHERE dept = p_dept;
    p_cnt := SQL%ROWCOUNT;
EXCEPTION
    WHEN OTHERS THEN
        RAISE_APPLICATION_ERROR(-20001, '인상 실패');
END;
/

-- MySQL
DELIMITER //
CREATE PROCEDURE raise_sal(IN p_dept VARCHAR(10), OUT p_cnt INT)
BEGIN
    UPDATE emp SET sal = sal + 10 WHERE dept = p_dept;
    SET p_cnt = ROW_COUNT();
END //
DELIMITER ;

-- MSSQL
CREATE OR ALTER PROCEDURE raise_sal @dept VARCHAR(10), @cnt INT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    UPDATE emp SET sal = sal + 10 WHERE dept = @dept;
    SET @cnt = @@ROWCOUNT;
END;

MySQL 에서 바이너리 로그를 켠 서버는 함수에 DETERMINISTIC 등의 특성을 지정해야 만들어집니다. MSSQL 은 SET NOCOUNT ON 을 빠뜨리면 영향 행 수 메시지가 결과로 섞이고, 스칼라 함수는 dbo. 를 붙여 호출합니다.

COMMIT 은 보통 프로시저 안이 아니라 호출한 쪽이 결정합니다. 프로시저가 마음대로 커밋하면 호출자가 여러 프로시저를 한 트랜잭션으로 묶을 수 없습니다.

관련 레슨은 SQL 실무의 프로시저 레슨입니다.

12자주 틀리는 것

DDL·운영 쪽에서 실제로 틀렸다가 고친 사례입니다.

틀린 생각 실제
Oracle VARCHAR2(10) 은 10글자 기본은 10바이트, 한글이면 3글자
DDL 은 롤백할 수 있다 Oracle·MySQL 은 암묵적 커밋, MSSQL 만 롤백 가능
UNIQUE 컬럼은 NULL 을 하나만 Oracle·MySQL 은 여러 개, MSSQL 만 하나
MySQL 은 옛 버전에서도 CHECK 가 동작 8.0.16 이전에는 무시
Oracle 에도 ON UPDATE 절이 있다 없음
이름과 타입은 한 문장으로 변경 MySQL 만 CHANGE COLUMN 한 번
롤백하면 채번 번호도 되돌아간다 시퀀스·IDENTITY 는 구멍이 생김
참조되는 표도 TRUNCATE 가능 FK 로 참조되면 불가
Oracle 은 NULL 도 인덱스에 저장 단일 컬럼 B-tree 는 저장 안 함
MySQL 기본 격리는 READ COMMITTED REPEATABLE READ
오류가 나면 트랜잭션 전체가 취소 기본은 그 문장만 취소
1205 는 데드락 오류 MySQL 1205 는 시간 초과, MSSQL 1205 가 데드락
데드락이면 Oracle 도 전체 롤백 Oracle 은 문장만 롤백
모든 DB 가 FK 인덱스를 만들어 준다 MySQL InnoDB 만 자동
DELETE ... LIMIT 은 서브쿼리에도 됨 MySQL 은 단일 표만, IN 서브쿼리 안 불가
Oracle 힌트가 틀리면 오류가 난다 조용히 무시
EXPLAIN 비용으로 DB 끼리 비교 비용 숫자는 DB 간 비교 무의미

이 표의 대부분은 문법이 아니라 기본값과 기본 동작의 차이입니다. 새 DB 로 옮길 때는 대응표보다 이 기본값들부터 확인합니다.

지금까지 SQL 그룹 41개 레슨을 중급의 서브쿼리와 조인, 고급의 분석 함수와 계층, 실무의 이력과 이관, 대용량의 실행 계획과 락으로 이어 왔습니다. 이 세 장의 대응표는 그 내용을 세 DB 에서 다시 찾아볼 때 쓰는 색인이며, 헷갈리면 먼저 "한눈에 보기" 를 확인한 뒤 해당 절과 레슨으로 돌아가면 됩니다.

목차
  • 한눈에 보기
  • 타입·DDL
  • 제약
  • 채번
  • 인덱스
  • 파티션
  • 트랜잭션·격리
  • 락
  • 실행 계획·통계·힌트
  • 대량 처리·삭제
  • 프로시저
  • 자주 틀리는 것
참고 영상 · 인터넷 연결 시 유튜브 검색이 열립니다DDL·운영 대응표sql 대응표 비교 요약
이전02 쿼리 문법 대응표