과목2-1. SQL 기본
SQL 종류
DML
- SELECT, INSERT, UPDATE, DELETE
DDL
- CREATE, ALTER, DROP, RENAME
DCL
- GRANT, REVOKE
TCL
- COMMIT, ROLLBACK, SAVEPOINT, LOCKING
제약조건
PK
- CONSTRAINT PRODUCT_PK PRIMARY KEY (PROD_ID)
- ALTER TABLE EMP ADD CONSTRAINT MEP_PK PRIMARY KEY (EMP_NO);
UNIQUE KEY
- NULL 값을 가질 수 있다.
NOT NULL
- NULL 과 공백, 숫자 0 은 전혀 다른 값
CHECK
- 데이터의 무결성을 유지하기 위하여 테이블의 특정 칼럼에 설정하는 제약
* 데이터 무결성 : 데이터가 전송, 저장되고 처리되는 모든 과정에서 변경되거나 손상되지 않고 완전성 정확성 일관성을 유지함을 보장하는 특성
FOREIGN KEY
Index 생성
- CREATE INDEX IDX_EMP_01 ON EMP (JOIN_DATE);
ALTER
칼럼 추가
- ALTER TABLE 테이블명 ADD 속성명 VARCHAR(30) [DEFAULT]
칼럼 변경
- ALTER TABLE 테이블명 ALTER COLUMN 속성명 VARCHAR(30) NOT NULL;
- ALTER TABLE DROP [CASCADE | RESTRICT (자식 테이블에 pk가 없는 경우에만 부모 삭제 허용)]
- ALTER TABLE MODIFY
제약조건 추가
- ALTER TABLE ADD CONSTRAINT
제약조건 삭제
- ALTER TABLE DROP CONSTRAINT
테이블 이름 변경
- RENAME 변경전 테이블명 TO 변경후 테이블명
참조동작
Delete(Modify)
- Cascade : Master 삭제 시 Child 같이 삭제
- Set Null : .. 필드 Null
- Set Default : .. 필드 Default 값으로 설정
- Restrict : Child 테이블에 PK 값이 없는 경우만 Master 삭제 허용
Insert
- Automatic : Master 테이블에 PK가 없는 경우 Master PK를 생성 후 Child 입력
- Set Null : .. Child 외부키를 Null 값으로 처리
- Set Default
- Dependent : PK 가 존재할 때만 Child 입력 허용
트랜잭션
- 원자성 : 트랜잭션에 정의된 연산들은 모두 성공적으로 실행되던지 아니면 전혀 실행되지 않은 상태
- 일관성 : 트랜잭션이 실행되기 전의 데이터베이스 내용이 잘못 되어 있지 않다면 트랜잭션이 실행된 이후에도 데이터베이스의 내용에 잘못이 있으면 안된다.
- 고립성 : 트랜잭션 실행 도중에 다른 트랜잭션의 영향을 받아 잘못된 결과를 만들어서는 안된다.
- 지속성 : 트랜잭션이 성공적으로 수행되면 그 트랜잭션이 갱신한 데이터베이스의 내용은 영구적으로 저장된다.
트랜잭션 격리성
Read Uncommitted < Read Committed < Repeatable Read < Serializable
Read Uncommitted -- 커밋하지 않은 데이터를 읽을 수 있다.
한 트랜잭션에서 커밋하지 않은 데이터에 다른 트랜잭션이 접근 가능
- 발생 문제점 : Dirty Read, Non-Repeatable Read, Phantom Read
Read Committed -- 커밋 완료된 데이터만 읽을 수 있다.
- 발생 문제점 : Non-Repeatable Read, Phantom Read
Repeatable Read
트랜잭션 내에서 한번 조회한 데이터를 반복해서 조회해도 같은 데이터가 조회
- 발생 문제점 : Phantom Read
Serializable
가장 엄격한 격리 수준
위 3가지 문제점을 모두 커버 가능하다. 하지만 동시 처리 성능은 급격히 떨어질 수 있다.
문제점
Dirty Read
다른 트랜잭션 내에서 A라는 Key의 Row(행)를 읽고, 이후에 다시 읽었는데 그 사이에 값이 변경되어 삭제되거나 결과가 다르게 나타나는 문제
Non-Repeatable Read
트랜잭션 T1이 데이터를 Read 하고 있는 중
이때 다른 트랜잭션 T2가 데이터 접근하여 값 변경 또는 삭제하고 커밋하면,
T1은 다시 해당 데이터를 Read 하고자 하면 변경된 데이터 혹은 사라진 데이터를 찾게 된다.
Phantom Read
트랜잭션 T1 중에 특정 조건으로 데이터 검색하여 결과 얻었다.
이때 다른 트랜잭션 T2가 접근해 해당 조건의 데이터 일부를 삭제 또는 추가,
아직 끝나지 않은 T1이 다시 한번 해당 조건으로 데이터 조회하면 T2에서 추가/삭제된 데이터가 함께 조회/누락됨
T2가 롤백하면 데이터 꼬임
ORACLE VS SQL Server
ORACLE
- DDL 문장 수행 후 자동으로 COMMIT 수행
- 내부적으로 트랜젝션을 종료 시킴, ROLLBACK 불가
SQL Server
- DDL 문장 수행 후 자동으로 COMMIT 수행하지 않는다.
- CREATE도 TRANSACTION의 범주에 포함되므로 ROLLBACK 수행됨
Oracle에선 null을 가장 큰 값, SQL Server 에선 null을 가장 작은 값으로 간주
데이터 삭제
TRUNCATE TABLE -- 테이블 비우기
-- 모든 행 제거 후 저장공간 재사용 (디스크 사용량도 초기화)
TRUNCATE TABLE 테이블명;
-- 구조 자체 삭제는 DROP COLUMN 삭제할 칼럼명
TRUNCATE TABLE 테이블명 DROP COLUMN 삭제할 칼럼명;
DELETE -- 삭제
DELETE FROM 테이블명 WHERE 조건절;
DELETE FROM BOARD; -- 조건절 없으면 전체 테이블 삭제
DROP -- 테이블 정의 자체를 삭제
DROP TABLE PLAYER; -- 테이블 전부 삭제, 회복 불가
ALTER TABLE PLAYER DROP COLUMN ADDRESS; -- 테이블의 일부 칼럼 삭제, 회복 불가
DDL과 DML
DDL은 반드시 AUTO COMMIT 일어남 -> DROP, TRUNCATE 원상복구 불가
DML은 사용자가 COMMIT 해야함 -> DELETE 테이블 삭제해도 ROLLBACK으로 복구 가능
ROLLBACK
COMMIT 되지 않은 상위의 모든 트랜잭션을 모두 롤백
오라클 날짜형 데이터
1/24/60 = 1분
1/24/(60/10) = 10분
CASE 문 - SIMPLE_CASE_EXPRESSION
CASE LOC WHEN 'NEW YORK' THEN 'EAST'
단일행 NULL 관련 함수 종류
일반형 함수 | 함수설명 |
NVL(표현식1, 표현식2) ISNULL(표현식1, 표현식2) |
표현식1이 NULL 이면 표현식2 출력 |
NULLIF(표현식1, 표현식2) | 표현식1 = 표현식2 이면 NULL 같지 않으면 표현식1 |
COALESCE(표현식1, 표현식2, ... ) | 결과로 NULL이 아닌 최초 표현식 모든 표현식이 NULL이라면 NULL 리턴 |
SELECT SUM(COALESCE(C1, C2, C3))
FROM TAB1
C1 | C2 | C3 |
1 | 2 | 3 |
2 | 3 | |
3 |
결과 : 1 + 2 + 3 = 6
SQL 문장
집계함수
- 다중행 함수
- SELECT, HAVING, ORDER BY 절에 사용
- 집계함수명 (ALL | DISTINCT)
COUNT(*) : NULL 포함 갯수
COUNT(col3) : NULL 제외 갯수
SUM
AVG
MAX
MIN
...
SQL 문장 오류
SELECT 메뉴ID, 사용유형코드, AVG(COUNT(*))
FROM 시스템사용이력
GROUP BY 메뉴ID, 사용유형코드
-> 중첩된 그룹함수의 경우 최종 결과값은 1건이 될 수밖에 없기에
GROUP BY 절에 기술된 메뉴ID와 사용유형코드는 SELECT 절에 기술될 수 없다.
HAVING
SELECT SUM(주문금액)
FROM 주문
HAVING AVG(주문금액) > 100;
SELECT 문장 실행 순서
FROM - WHERE - GROUP BY - HAVING - SELECT - ORDER BY
TOP(n) WITH TIES
동일한 값이 있다면 함께 출력
과목2-2. SQL 활용
조인
일반 집합 연산자
- UNION : 합집합
- INTERSECTION : 교집합
- DIFFERENCE (EXCEPT기능, Oracle = MINUS) : 차집합
- PRODUCT (CROSS JOIN 기능) : 곱집합
순수 관계 연산자
- SELECT
- PROJECT
- JOIN
- DIVIDE
JOIN 형태
INNER JOIN, NATURAL, USING, ON, CROSS JOIN, OUTER JOIN
NATURAL JOIN
- 두 테이블간 동일한 이름을 갖는 모든 칼럼에 대해 EQUI JOIN을 수행
- ALIAS나 접두사 붙일 수 없다.
>> SELECT DEPTNO, EMPNO FROM EMP NATURAL JOIN DEPT;
USING
- FROM 절에 같은 이름을 가진 칼럼들 중에서 원하는 칼럼에 대해서만 선택적으로 EQUI JOIN 수행
- SQL Server 에서 지원 x
- ALIAS나 접두사 붙일 수 없다.
- JOIN에 사용되는 칼럼은 1개만 표시
Oracle SQL >> SELECT * FROM DEPT JOIN DEPT USING(DEPTNO);
CROSS JOIN (= CARTESIAN PRODUCT , CROSS PRODUCT)
M*N
>> SELECT X.KEY1, Y.KEY2 FROM TAB1 X CROSS JOIN TAB2 Y
OUTER JOIN
ORACLE >>
WHERE A.게시판ID = B.게시판ID(+)
AND B.삭제여부(+) = 'N'
SQL>>
FROM 게시판 A LEFT OTER JOIN 게시글 B
ON (A.게시판ID = B.게시판ID AND B.삭제여부 ='N')
집합 연산자
UNION : 중복 데이터(이전 데이터 포함)가 모두 제거
UNION ALL : 합집합, 중복된 행 그대로 결과로 표시
INTERSECT
EXCEPT (MINUS)
EXISTS
>> WHERE NOT EXISTS (SELECT
Oracle 계층형 질의
- START WITH절은 계층 구조의 시작점 지정
- 순방향전개란 부모 노드로부터 자식 노드 방향으로 전개
- 루트 노드의 LEVEL 값은 1이다.
- PRIOR 키워드는 SELECT, WHERE절에서 사용할 수 있다.
CONNECT BY PRIOR 상위부서코드 = 부서코드 (순방향)
상위부서코드 | 부서코드 | LEVEL |
1 | 1 | |
2 | 1 | 2 |
이전의 상위부서코드가 부서코드가 된다.
CONNECT BY 상위부서코드 = PRIOR 부서코드
이전의 부서코드가 상위부서코드가 된다.
서브쿼리
- 서브쿼리는 단일 행 또는 복수 행 비교 연산자와 함께 사용
- 서브쿼리는 select, from, having, order by 에서 사용
- DELECT문 사용 불가
- 메인 쿼리의 결과가 서브쿼리로 제공될 수도 있고, 서브쿼리의 결과가 메인쿼리로 제공될 수 있으므로 실행 순서는 상황에 따라 달라짐
- SELECT 절에 서브쿼리 사용 >> 스칼라 서브쿼리
- 한 행, 한 칼럼만을 반환
- 스칼라 서브쿼리 대신 JOIN으로 동일한 결과 추출 가능
비연관 서브쿼리
- 서브쿼리가 메인쿼리 칼럼을 가지고 있지 않은 형태
- 메인쿼리에 값을 제공하기 위한 목적
연관 서브쿼리
- 서브쿼리가 메인쿼리 칼럼을 가지고 있는 형태
- 메인쿼리가 먼저 수행되어 읽혀진 데이터를 서브쿼리에서 조건이 맞는지 확인하고자 할 때
Single Row 서브쿼리
- 단일 행 비교 연산자 =, <, <=, >, >= <>
Multi Row 서브쿼리
- 실행결과 여러건, 다중 행 비교 연산자 IN, ALL, ANY, SOME, EXISTS *(Single Row 에서도 사용가능)
Multi Column 서브쿼리 (다중 칼럼 서브쿼리)
- SQL Server에서는 현재 지원하지 않는 기능
NOT EXISTS, NOT IN, LEFT OUTER JOIN 같은 결과 표현
WHERE NOT EXISTS (SELECT * FROM 가족 WHERE 사번 = 부양사번)
WHERE 사번 NOT IN (SELECT 부양사번 FROM 가족)
FROM 사원 LEFT OUTER JOIN 가족 ON (사번 = 부양사번)
WHERE 부양사번 IS NULL
뷰
- 가상 테이블, FROM절에 사용하는 뷰는 인라인 뷰, 실제 데이터 x
- 인라인 뷰는 동적 뷰
- 독립성 : 테이블 구조 변경 자동 반영
- 편리성 : 쿼리 단순하게 작성
- 보안성 : 뷰 생성할 때 칼럼 제외 가능
그룹함수
- 그룹 함수 모두 일반 그룹 함수로 동일한 결과를 추출할 수 있음
- 집계된 레코드에서 집계 대상 칼럼 이외의 GROUP 대상 칼럼의 값은 NULL을 반환
ROLLUP 함수
- ROLLUP에 지정된 Grouping Columns의 List는 Subtotal을 생성하기 위해 사용
- Grouping Columns의 수를 N이라고 했을 때 N+1 Level의 Subtotal이 생성
- GROUP BY로 묶인 칼럼의 소계 계산, 계층 구조
- GROUP BY 칼럼 순서가 바뀌면 결과 값 바뀜
- GROUP BY의 확장된 형태
- 함수의 인자로 주어진 칼럼의 순서에 따라 다른 결과를 추출하게 됨
- 나열된 칼럼에 대해 계층 구조로 집계를 출력
* GROUP BY ROLLUP(A) : 전체 합계, 칼럼 A소계
* GROUP BY ROLLUP(A,B) : 전체 합계, 칼럼 A소계, 칼럼 (A,B) 조합 소계
* GROUP BY ROLLUP(A,B,C) : 전체 함계, 칼럼 A소계, 칼럼 (A,B) 조합 소계, (A,B,C) 조합 소계
* GROUP BY ROLLUP(A,(B,C)) : 전체 합계, 칼럼 A소계, 칼럼 (A,(B,C)) 조합 소계
* GROUP BY A, ROLLUP(B) : A그룹별 집계, A그룹 내부에서 B칼럼별 집계
CUBE 함수
결합 가능한 모든 값에 대한 다차원 집계
* GROUP BY CUBE(A) : 전체 합계, 칼럼 A소계
* GROUP BY CUBE(B) : 전체 합계, 칼럼 A소계, 칼럼 B소계, 칼럼 (A,B) 조합 소계
SELECT 상품ID, 월, SUM(매출액) AS 매출액
FROM 월별매출
GROUP BY CUBE(상품ID, 월);
GROUPING SETS 함수
특정 항목에 대한 소계 계산, GROUP BY 칼럼 순서와 무관하게 개별적으로 처리
내가 보고싶은 것만 소계를 생성
* Group By Grouping Sets(A) : 컬럼 A소계
* Group By Grouping Sets(A, B) : 컬럼 A소계, 컬럼 B소계
* Group By Grouping Sets(A, B) : 컬럼 (A, B)소계
GROUPING SETS는 특정 항목에 대한 소계를 계산하는 함수입니다.
SELECT 상품ID, 월, SUM(매출액) AS 매출액
FROM 월별매출
GROUP BY GROUPING SETS(상품ID, 월);
윈도우 함수
여러 행 간의 관계 정의 함수, 중첩 불가
순위함수
- RANK : 중복 순위 포함
- DENSE_RANK : 중복 순위 무시 (중간 순위를 비우지 않음)
- ROW_NUMBER : 단순히 행 번호 표시, 값 무관하게 고유한 순위 부여
윈도우 일반 집계 (aggregate) 함수
SUM, MAX, MIN, AVG 등
행 순서 함수
- FIRST_VALUE / LAST_VALUE 함수 : 첫 값 / 끝 값
SELECT Name, Gender, Salary,
FIRST_VALUE(Name) OVER (ORDER BY Salary) AS FirstValue
FROM Employees
- LAG / LEAD : 이전 값 / 이후 값
- LEAD(E,A)는 E에서 A번째 행의 값을 호출하는 형태로도 쓰임 (A의 기본값은 1)
DCL
- GRANT: GRANT 권한 ON 오브젝트 TO 유저명
- REVOKE: REVOKE 권한 ON 오브젝트 TO 유저명
권한
- SELECT, INSERT UPDATE DELETE ALTER ALL
- REFERENCES
- INDEX
ROLE 종류
CONNECT: CREATE SESSION과 같은 로그인 권한
RESOURCE: CREATE TABLE과 같은 오브젝트(리소스) 생성 권한
절차형 SQL
DBMS 벤더별로 절차별 SQL 제공
SQL문의 연속적인 실행이나 조건에 따른 분기처리를 이용하여 특정 기능을 수행하는 저장 모듈을 생성
PL/SQL (Oracle)
Block 구조로 되어있고 Block 내에는 DML 문장과 QUERY 문장 그리고 절차형 언어(IF, LOOP)등을 사용할 수 있음
절차적 프로그래밍을 가능하게 하는 트랜잭션 언어
CREATE OR REPLACE Procedure 프로시저명 (argument1 mode data_type1, ... ) is as
BEGIN ..
EXCEPTION
END
-- 삭제
DROP Procedure 프로시저명
프로시저
- 주로 DML을 사용해 주기적으로 진행해야 되는 작업을 저장
- 별도의 호출을 통해 실행
- CREATE OR REPLACE PROCEDURE 문으로 프로시저를 생성
* OR REPLACE는 기존에 같은 이름의 프로시저가 있으면 새로운 내용으로 덮어쓴다
- 작업의 결과를 DB에 저장(트랜잭션 처리)
- BEGIN~END문 사이에 작업 영역 생성 (1~3은 섞어서 사용하고, 4번만 마지막에 작성)
→ 1) 조건/반복 영역
→ 2) SQL을 사용해 데이터 관리하는 영역
→ 3) 예외 처리 영역
→ 4) 트랜잭션 영역 (작업 결과를 실제로 반영하거나 취소하는 영역)
사용자 정의 함수
- 절차형 SQL을 로직과 함께 DB내에 저장해 놓은 명령문 집합
- RETURN 을 통해 반드시 하나의 값 반환 (↔ 프로시저는 DB에 저장)
트리거 (Trigger)
- DML문이 수행되었을 때 자동으로 동작하는 프로그램(↔ 프로시저는 EXCUTE로 실행)
- DCL과 TCL사용불가 (↔ 프로시저는 사용 가능)
- 데이터의 무결성과 일관성을 위해서 사용
- Trigger는 데이터베이스 보안의 적용, 유효하지 않은 트랜잭션의 예방, 업무 규칙 자동 적용 제공 등에 사용
과목2-3. SQL 최적화 기본 원리
옵티마이저
최적의 실행계획 결정
종류
- 비용기반 옵티마이저 (CBO) (대부분 사용)
- 테이블, 인덱스 등의 통계정보 활용
- SQL문을 실행하는데 소요될 처리시간, CPU, I/O 자원량 등을 계산 → 효율적이라 예상되는 실행계획 선택
- 전체 테이블 스캔이 유리하다고 판단할 수도 있다.
- 규칙기반 옵티마이저
- 우선순위를 기반으로 실행계획 생성
- 제일 높은 우선순위 : ROWID 활용 (고유주소)
- 제일 낮은 우선순위는 전체 테이블 스캔
- 규칙에 따라 인덱스가 존재하면 항상 인덱스를 사용하려고 함.
- 1. ROWID를 사용한 단일 행
- 2. 클러스터 조인에 의한 단일 행 등등
- 우선순위를 기반으로 실행계획 생성
실행계획 (예상 정보)
알 수 있는 정보:
- 조인 순서
- 조인기법
- 액세스기법
- INDEX SCAN, FULL TABLE SCAN
- 최적화 정보
- 예상되는 비용 COST, CARD, BYTES
- 연산
실행순서
안에서 밖으로 , 위에서 아래로
SQL 처리 흐름도
SQL 문의 처리 절차를 시각적으로 표현
- 인덱스 스캔, 테이블 스캔 등과 같은 액세스 기법 표현
- 성능적인 측면 표현
인덱스
인덱스는 조회만을 위한 오브젝트, 목적은 조회 성능 최적화
삽입 ,삭제, 갱신의 경우 오히려 부하 가중
→ 매번 인덱스 정렬이 일어남
인덱스는 UPDATE 작업에는 부하가 없을 수도 있음
보조인덱스는 중복 데이터 입력 가능
테이블의 전체 데이터 읽는 경우 인덱스 사용 X, FTS(Full Text Search) 사용
검색어를 인덱싱하여 검색 성능을 향상시켜 주고, 유사어 처리와 같이 검색에 필요한 기능을 제공
인덱스를 스캔하여 테이블로 찾아가는 방식은 랜덤 엑세스
랜덤 엑세스의 부하가 크기 때문에 , 매우 많은 양의 데이터를 읽을 경우 → 인덱스 스캔보다 테이블 전체 스캔이 유리
SQL Server의 클러스터형 인덱스는 ORACLE의 IOT와 매우 유사
종류
- B-Tree 인덱스 (주요 인덱스) :
- 브랜치 블록과 리프 블록으로 구성, 일치 및 범위 검색에 적합한 구조
- OLTP (On-Line Transaction Processing) : 여러 과정의 연산이 하나의 트랜잭션으로 실행하는 프로세스
- 블록은 인덱스를 구성하는 칼럼값으로 정렬
- BITMAP 인덱스
- 하나의 인덱스 키 엔트리가 많은 행에 대한 포인터를 저장
- DW (Data Warehouse) 및 AD-HOC(비정형) 질의 환경 위해 설계
- CLUSTERED 인덱스
- 인덱스의 리프 페이지가 곧 데이터 페이지
- 리프페이지의 모든 데이터는 인덱스 키 칼럼 순으로 물리적으로 정렬되어 저장
- REVERSE KEY 인덱스
[Create Index]
CREATE INDEX IDX_EMP_01 ON EMP (REGIST_DATE, DEPTNO);
[SQL 실행]
SELECT *
FROM EMP
WHERE DEPTNO = 20
AND REGIST_DATE BETWEEN '2023.05.22' AND '2023.08.30'
인덱스의 칼럼을 변경하는 것이 좋다.
REGIST_DATE 칼럼에 동등 검색 조건으로 변경하면 인덱스를 더 효율적으로 활용
B*Tree index 는 데이터 중 10% 이하의 데이터를 검색할 때 유리
JOIN 종류
SORT MERGE JOIN
비동등 조인에 대해서도 조인 작업 가능
Non-EQUI JOIN
인덱스의 유무에 영향 받지 않음
조인 칼럼에 적당한 인덱스 없음
Driving Table 개념 중요하지 않음
NL JOIN (NESTED LOOP JOIN)
FOR 선행 테이블 읽음 → 외부테이블(OUTER TABLE)
FOR 후행테이블 읽음 → 내부 테이블(INNER TABLE) (선행 테이블과 후행 테이블조인)
NL JOIN은 OLTP의 목록 처리 업무에 많이 사용
조인 칼럼에 적당한 인덱스가 있어서 자연조인이 효율적일 때 유용
유니크 인덱스를 활용하여 수행시간이 적게 걸리는 소량 테이블을 온라인 조회하는 경우 유용
Nested loop semi join은 서브쿼리를 nested-loop join으로 변경하는 경우에 사용되는 nested-loop join의 변형
SELECT * FROM A WHERE A.id IN (SELECT B.id FROM B WHERE B.value > 100);
서브쿼리 : nested-loop
EXISTS, IN : semi join
HASH JOIN
Hash Join, Sort Merge Join 은 DW등의 데이터 집계 업무에서 많이 사용
두 테이블이 너무 커서 Sort 부하가 심할 때 Hash Join 유용
EQUI JOIN(=) 에서만 동작
일반적으로 Hash Join > Sort Merge Join
정렬되어 있을 때 Sort Merge Join 유리
HASH JOIN이 더 효과적일 수 있는 조건
- 한쪽 테이블이 주메모리의 가용메모리에 담길 정도로 충분히 작고 해시키 속성에 중복값이 적을때 효과적
- 조인 컬럼에 적당한 인덱스가 없어서 자연조인이 비효율적일 때
- 자연조인시, 드라이빙(DRIVING) 집합 쪽으로 조인 액세스량이 많아 RANDOM 액세스 부하가 심할 때
- SORT MERGE JOIN을 하기에는 두 테이블이 너무 커서 소트부하가 심할 때
'소프트웨어공학 > SQLD' 카테고리의 다른 글
SQLD 데이터 모델링의 이해 , 데이터 모델과 성능 오답노트 (0) | 2023.09.03 |
---|
댓글