SELECT /*+ MAX_EXECUTION_TIME(100)*/
FROM employees
ORDER BY last_name LIMIT 1;
join_buffer_size
시스템 변수의 경우, MySQL 서버의 옵티마이전느 조인 버퍼의 공간이 충분하면 조인 버퍼를 활용하는 형태의 실행 계획을 선택할 수 있다.optimizer_switch
시스템 변수를 제어해야 할 수도 있다.실행 계획을 바꾸는 용도
조인 버퍼나 정렬용 버퍼(소트 버퍼)의 크기를 일시적으로 증가시켜 대용량 처리 쿼리의 성능을 향상시키는 용도
SELECT /*+ SET_VAR(optimizer_switch='index_merge_intersection=off')*/ *
FROM employees
WHERE ...
최적화 전략 | 힌트 |
---|---|
Duplicate Weed-out | SEMIJOIN(DUPSWEEDOUT) |
First Match | SEMIJOIN(FIRSTMATCH) |
Loose Scan | SEMIJOIN(LOOSESCAN) |
Materialization | SEMIJOIN(MATERIALIZATION) |
Table Pull-out | 없음 |
SELECT *
FROM departments d
WHERE d.dept_no IN
(SELECT /*+ SEMIJOIN(MATERIALIZATION)*/ de.dept_no
FROM dept_emp de);
SELECT /*+ SEMIJOIN(@subq1 MATERIALIZATION)*/ *
FROM departments d
WHERE d.dept_no IN
(SELECT /*+ QB_NAME(subq1)*/ de.dept_no
FROM dept_emp de);
SELECT *
FROM departments d
WHERE d.dept_no IN
(SELECT /*+ NO_SEMIJOIN(DUPSWEEDOUT, FIRSTMATCH)*/ de.dept_no
FROM dept_emp de);
최적화 방법 | 힌트 |
---|---|
IN-to-EXISTS | SUBQUERY(INTOEXISTS) |
Materialization | SUBQUERY(MATERIALIZATION) |
SELECT /*+ BNL(e, de)*/ *
FROM employees e
INNER JOIN dept_emp de ON de.emp_no=e.emp_no;
힌트 | 설명 |
---|---|
JOIN_FIXED_ORDER | STRAIGHT 힌트와 동일하게 FROM 절의 테이블 순서대로 조인을 실행하게 하는 힌트 |
JOIN_ORDER | FROM 절에 사용된 테이블의 순서가 아니라 힌트에 명시된 테이블의 순서대로 조인을 실행하는 힌트 |
JOIN_PREFIX | 조인에서 드라이빙 테이블만 강제하는 힌트 |
JOIN_SUFFIX | 조인에서 드리븐 테이블(가장 마지막에 조인돼야 할 테이블들)만 강제하는 힌트 |
이 이외의 쿼리 블록의 이름까지 사용하면서 복잡하게 사용할 수도 있다.
-- FROM 절에 나열된 테이블의 순서대로 조인 실행
SELECT /*+ JOIN_FIXED_ORDER()*/ *
FROM employees e
INNER JOIN dept_emp de ON de.emp_no=e.emp_no
INNER JOIN departments d ON d.dept_no=de.dept_no;
-- 일부 테이블에 대해서만 조인 순서를 나열
SELECT /*+ JOIN_ORDER(d, de)*/ *
FROM employees e
INNER JOIN dept_emp de ON de.emp_no=e.emp_no
INNER JOIN departments d ON d.dept_no=de.dept_no;
-- 조인의 드라이빙 테이블에 대해서만 조인 순서를 나열
SELECT /*+ JOIN_PREFIX(e, de)*/ *
FROM employees e
INNER JOIN dept_emp de ON de.emp_no=e.emp_no
INNER JOIN departments d ON d.dept_no=de.dept_no;
-- 조인의 드리븐 테이블에 대해서만 조인 순서를 나열
SELECT /*+ JOIN_SUFFIX(de, e)*/ *
FROM employees e
INNER JOIN dept_emp de ON de.emp_no=e.emp_no
INNER JOIN departments d ON d.dept_no=de.dept_no;
SELECT /*+ MERGE(sub)*/ *
FROM (SELECT *
FROM employees
WHERE first_name='Matt') sub
LIMIT 10;
SELECT /*+ INDEX_MERGE(employees ix_firstname, PRIMARY)*/ *
FROM employees
WHERE first_name='Georgi' AND emp_no BETWEEN 10000 AND 20000;
SELECT /*+ NO_INDEX_MERGE(employees PRIMARY)*/ *
FROM employees
WHERE first_name='Georgi' AND emp_no BETWEEN 10000 AND 20000;
SELECT /*+ NO_ICP(employees ix_lastname_firstname)*/ *
FROM employees
WHERE last_name='Action' AND first_name LIKE '%sal';
SELECT /*+ NO_SKIP_SCAN(employees ix_gender_birthdate)*/ gender, birth_date
FROM employees
WHERE birth_date >= '1965-02-01';
인덱스 힌트 | 인덱스 힌트를 대체하는 옵티마이저 힌트 |
---|---|
USE INDEX | INDEX |
USE INDEX FOR GROUP BY | GROUP_INDEX |
USE INDEX FOR ORDER BY | ORDER_INDEX |
IGNORE INDEX | NO_INDEX |
IGNORE INDEX FOR GROUP BY | NO_GROUP_INDEX |
IGNORE INDEX FOR ORDER BY | NO_ORDER_INDEX |
인덱스 힌트는 특정 테이블 뒤에 사용했기 때문에 별도로 힌트 내에 테이블명 없이 인덱스 이름만 나열했다.
-- 옵티마이저 힌트 사용
SELECT /*+ INDEX(employees ix_firstname)*/ *
FROM employees
WHERE first_name='Matt';
-- 인덱스 힌트 사용
SELECT *
FROM employees USE INDEX(ix_firstname)
WHERE first_name='Matt';