MariaDB/SQL Tuning

[MariaDB][성능] 실행계획 분석2

DBA_JSH 2016. 8. 8. 13:17
[테스트 환경]
서버: CentOs7
DB : MariaDB 10.1.12 
DB엔진 : INNODB

1.TYPE컬럼 의미

  - Type컬럼은 각 테이블의 레코드를 인덱스로 읽었는지 풀 테이블 스캔으로 읽었는지를 의미

--테스트에서 사용하게 될  테이블 스크립트 정보 
MariaDB [DA]> DESC EMP;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| EMPNO    | int(4)      | NO   | PRI | NULL    |       |
| ENAME    | varchar(10) | YES  | MUL | NULL    |       |
| JOB      | varchar(9)  | YES  |     | NULL    |       |
| MGR      | int(4)      | YES  |     | NULL    |       |
| HIREDATE | date        | YES  |     | NULL    |       |
| SAL      | int(7)      | YES  |     | NULL    |       |
| COMM     | int(7)      | YES  |     | NULL    |       |
| DEPTNO   | int(2)      | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
8 rows in set (0.00 sec)

MariaDB [DA]> DESC DEPT;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| DEPTNO | int(2)      | NO   | PRI | NULL    |       |
| DNAME  | varchar(14) | YES  |     | NULL    |       |
| LOC    | varchar(13) | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

MariaDB [DA]> DESC DA_EMP_DEPT;
+------------+---------+------+-----+---------+-------+
| Field      | Type    | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+-------+
| EMPNO      | int(11) | NO   | PRI | NULL    |       |
| DEPTNO     | char(4) | NO   | PRI | NULL    |       |
| START_DATE | date    | NO   |     | NULL    |       |
| END_DATE   | date    | NO   |     | NULL    |       |
+------------+---------+------+-----+---------+-------+
4 rows in set (0.00 sec)

1.SYSTEM  
  - 레코드가 1건만 존재하는 테이블 또는 한 건도 존재하지 않는 테이블을 참조하는 형태의 접근 방식 (InnoDB 발생 X) 

--데이터 베이스 생성 및 케릭터 셋 설정 
MariaDB [(none)]> CREATE DATABASE DA default character set utf8mb4;
Query OK, 1 row affected (0.01 sec)

--MYISAM 테이블 생성 
MariaDB [DA]> CREATE TABLE TEST( ID INT(11) NOT NULL, NAME VARCHAR(20)) ENGINE =MYISAM;
Query OK, 0 rows affected (0.00 sec)

--MYISAM 테이블에서 데이터가 미존재 할 경우 TYPE컬럼 값 : system
MariaDB [DA]> EXPLAIN SELECT * FROM TEST;
+------+-------------+-------+--------+---------------+------+---------+------+------+---------------------+
| id   | select_type | table | type   | possible_keys | key  | key_len | ref  | rows | Extra               |
+------+-------------+-------+--------+---------------+------+---------+------+------+---------------------+
|    1 | SIMPLE      | TEST  | system | NULL          | NULL | NULL    | NULL |    0 | const row not found |
+------+-------------+-------+--------+---------------+------+---------+------+------+---------------------+
1 row in set (0.01 sec)

--데이터 삽입 1건 삽입 
MariaDB [DA]> INSERT INTO TEST(ID,NAME) VALUES(1,'JSH');
Query OK, 1 row affected (0.00 sec)

--MYISAM 테이블에서 데이터가 1 건 존재 할 경우 TYPE컬럼 값 : system
MariaDB [DA]> EXPLAIN SELECT * FROM TEST;
+------+-------------+-------+--------+---------------+------+---------+------+------+-------+
| id   | select_type | table | type   | possible_keys | key  | key_len | ref  | rows | Extra |
+------+-------------+-------+--------+---------------+------+---------+------+------+-------+
|    1 | SIMPLE      | TEST  | system | NULL          | NULL | NULL    | NULL |    1 |       |
+------+-------------+-------+--------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)

--데이터 삽입 2건 삽입 
MariaDB [DA]> INSERT INTO TEST(ID,NAME) VALUES(2,'YHM');
Query OK, 1 row affected (0.00 sec)

--MYISAM 테이블에서 데이터가 2 건 존재 할 경우 TYPE컬럼 값 : ALL
MariaDB [DA]> EXPLAIN SELECT * FROM TEST;
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
| id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
|    1 | SIMPLE      | TEST  | ALL  | NULL          | NULL | NULL    | NULL |    2 |       |
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)

--I엔진 변경 - > INNODB
MariaDB [DA]> ALTER TABLE TEST ENGINE=INNODB;
Query OK, 2 rows affected (0.03 sec)    

--기존의 입력 데이터 모두 삭제 
MariaDB [DA]> DELETE FROM TEST;
Query OK, 2 rows affected (0.02 sec)

--INNODB엔진에서는 데이터가 미존재하여도 TYPE컬럼 값 : ALL 
MariaDB [DA]> EXPLAIN SELECT * FROM TEST;
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
| id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
|    1 | SIMPLE      | TEST  | ALL  | NULL          | NULL | NULL    | NULL |    1 |       |
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.01 sec)


2 CONST(UNIQUE INDEX SCAN)
  - 쿼리가 프라이머리 키나 유니크 키 컬럼을 이용하는 WHERE조건을 가지고 있으며, 반드시 1건을 반환하는 쿼리의 처리 방식
  - 인덱스 컬럼이 두개 일 때 일부의 컬럼만을 조회 조건으로 사용 한다만 CONST아닌 REF로 표기
  - CONST 실행 계획은 옵티마이저가 퀴리를 최적화하는 단계에서 통째로 상수화 한다. 상수(CONST)라고 표시되는 것

--단일키 인덱스
  -- id2번의 서브쿼리에서 인덱스 컬럼인 EMPNO로 조회하였기 때문에  const이며, 
  -- id1번의 ENMAE컬럼의 인덱스는 NON-UNIQUE인덱스 이기 때문에  ref로 읽는다. 

MariaDB [DA]>  EXPLAIN
    -> SELECT COUNT(*)
    -> FROM EMP E
    -> WHERE ENAME=(SELECT ENAME FROM EMP E1 WHERE EMPNO=7369);
	
+------+-------------+-------+-------+-----------------+-----------------+---------+-------+------+--------------------------+
| id   | select_type | table | type  | possible_keys   | key             | key_len | ref   | rows | Extra                    |
+------+-------------+-------+-------+-----------------+-----------------+---------+-------+------+--------------------------+
|    1 | PRIMARY     | E     | ref   | EMP_ENAME_IDX01 | EMP_ENAME_IDX01 | 33      | const |    1 | Using where; Using index |
|    2 | SUBQUERY    | E1    | const | PRIMARY         | PRIMARY         | 4       | const |    1 |                          |
+------+-------------+-------+-------+-----------------+-----------------+---------+-------+------+--------------------------+
2 rows in set (0.00 sec)

-복합키 인덱스 
--유니크 인덱스의 컬럼을 모두 조회 조건에서 사용하였기 때문에 const로 읽는다. 
MariaDB [DA]> EXPLAIN SELECT * FROM DA_EMP_DEPT WHERE EMPNO='1000' AND DEPTNO='A111';
+------+-------------+-------------+-------+---------------+---------+---------+-------------+------+-------+
| id   | select_type | table       | type  | possible_keys | key     | key_len | ref         | rows | Extra |
+------+-------------+-------------+-------+---------------+---------+---------+-------------+------+-------+
|    1 | SIMPLE      | DA_EMP_DEPT | const | PRIMARY       | PRIMARY | 16      | const,const |    1 |       |
+------+-------------+-------------+-------+---------------+---------+---------+-------------+------+-------+
1 row in set (0.00 sec)



3 EQ_REF
  - 여러 테이블이 조인되는 쿼리의 실행 계획에서만 표시되며, 조인에서 처음 읽는 테이블의 컬럼 값이 , 그 다음 읽어야 할 테이블의 프라이머리 키나 유니크 키 컬럼의 검색 조건 일 때.

--DA_EMP_DEPT테이블의 DEPTNO컬럼으로 조회 후 EMP테이블의 EMPNO컬럼과 조인 하였기 때문에 eq_ref로 읽는다. 
--만약 E.EMPNO = D.EMPNO가 아닌 E.DEPTNO = D.EMPNO로 조인 하였다면, REF로 읽게 될 것이다.
 
MariaDB [DA]EXPLAIN
  SELECT  E.*
  FROM    DA_EMP_DEPT D
  INNER JOIN  EMP E ON (E.EMPNO = D.EMPNO)
  WHERE   D.DEPTNO =20;
+------+-------------+-------+--------+---------------+---------+---------+------------+------+-------------+
| id   | select_type | table | type   | possible_keys | key     | key_len | ref        | rows | Extra       |
+------+-------------+-------+--------+---------------+---------+---------+------------+------+-------------+
|    1 | SIMPLE      | D     | ALL    | PRIMARY       | NULL    | NULL    | NULL       |   11 | Using where |
|    1 | SIMPLE      | E     | eq_ref | PRIMARY       | PRIMARY | 4       | DA.D.EMPNO |    1 |             |
+------+-------------+-------+--------+---------------+---------+---------+------------+------+-------------+
2 rows in set (0.00 sec)

4 REF
  - 인덱스 종류와 관계 없이 동등 조건으로 검색 할 때 사용. 레코드가 반드시 1건이라는 보장이 없음

--DA_EMP_DEPT 테이블의 인덱스 컬럼은 EMPNO,DEPTNO 복합 키 이며, EMPNO 컬럼만 조회 조건에 사용하였기 때문에 유일함을 보장 할수 없다. 
--따라서 REF로 읽는다. 
MariaDB [DA]> EXPLAIN SELECT * FROM DA_EMP_DEPT WHERE EMPNO='1000';
+------+-------------+-------------+------+---------------+---------+---------+-------+------+-------+
| id   | select_type | table       | type | possible_keys | key     | key_len | ref   | rows | Extra |
+------+-------------+-------------+------+---------------+---------+---------+-------+------+-------+
|    1 | SIMPLE      | DA_EMP_DEPT | ref  | PRIMARY       | PRIMARY | 4       | const |    1 |       |
+------+-------------+-------------+------+---------------+---------+---------+-------+------+-------+
1 row in set (0.00 sec)

--ENAME 컬럼의 인덱스는 NON-UNIQUE인덱스 이기 때문에 REF로 읽는다.
MariaDB [DA]> EXPLAIN SELECT *  FROM EMP E WHERE  E.ENAME ='SMITH';
+------+-------------+-------+------+-----------------+-----------------+---------+-------+------+-----------------------+
| id   | select_type | table | type | possible_keys   | key             | key_len | ref   | rows | Extra                 |
+------+-------------+-------+------+-----------------+-----------------+---------+-------+------+-----------------------+
|    1 | SIMPLE      | E     | ref  | EMP_ENAME_IDX01 | EMP_ENAME_IDX01 | 33      | const |    1 | Using index condition |
+------+-------------+-------+------+-----------------+-----------------+---------+-------+------+-----------------------+
1 row in set (0.00 sec)

5. FULLTEXT
  - 전문 검색 인덱스를 사용해 레코드를 읽는 접근 방식을 의미
  - 전문 검색 인덱스는 통계 정보가 관리되지 않으며, 전혀 다른 SQL문법을 사용해야 한다.(MATCH…AGAINST)
  - 전문 검색을 사용 할 때는 반드시 해당 테이블에 전문 검색용 인덱스가 준비돼 있어야만 한다. 그렇지 않으면 오류가 발생 한다.
  - MariaDB는 전문 검색 방식을 선호 하는 성향이 있으나 각 조건 별로 성능을 확인해 보고 사용 해야 한다.

--FULLTEXT  검색 전용 인덱스 생성 
MariaDB [DA]> ALTER TABLE EMP ADD FULLTEXT(ENAME);
Query OK, 0 rows affected (0.08 sec)
Records: 0  Duplicates: 0  Warnings: 0

--FULLTEXT를 이요한 검색 
MariaDB [DA]> EXPLAIN
    -> SELECT * FROM EMP A
    -> WHERE MATCH(A.ENAME) AGAINST('SCOTT in ') LIMIT 10;
+------+-------------+-------+----------+---------------+-------+---------+------+------+-------------+
| id   | select_type | table | type     | possible_keys | key   | key_len | ref  | rows | Extra       |
+------+-------------+-------+----------+---------------+-------+---------+------+------+-------------+
|    1 | SIMPLE      | A     | fulltext | ENAME         | ENAME | 0       |      |    1 | Using where |
+------+-------------+-------+----------+---------------+-------+---------+------+------+-------------+
1 row in set (0.01 sec)

--CONST(unique index) 조회 조건이 존재 할 경우 , CONST가 더 우선순위가 높다. 
MariaDB [DA]> EXPLAIN
    -> SELECT * FROM EMP A
    -> WHERE MATCH(A.ENAME) AGAINST('SC') 
    -> AND EMPNO =7788 
    -> LIMIT 10;
+------+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
+------+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
|    1 | SIMPLE      | A     | const | PRIMARY,ENAME | PRIMARY | 4       | const |    1 | Using where |
+------+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)

--FULLTEXT 검색 엔진 파라미터 조회  
--검색어가4글자 이하일 경우 아무런 검색결과도 나오지 않는다. 
MariaDB [(none)]> show variables like '%t_min_word_len%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| ft_min_word_len | 4     |
+-----------------+-------+
1 row in set (0.01 sec)

--My.cnf 파일을 통해서만 변경 가능
MariaDB [(none)]> SET ft_min_word_len = 2;
ERROR 1238 (HY000): Variable 'ft_min_word_len' is a read only variable

--기존의 생성 된 인덱스라면 파라미터 값을 바꾸고 재생성 또는 갱신을 해줘야 한다. 

단점 :  단어의 일부만 검색은 불가능(LIKE 검색) , 완전한 단어검색만 가능( 현재 10.1.12 MariaDB) 

6 UNIQUE_SUBQUERY, INDEX_SUBQUERY
 -과거 버전 
  - UNIQUE SUBQUERY : WHERE 조건절에서 사용 될 수 있는 IN(서브쿼리)의 접근 방식.서브 쿼리의 결과 값이 유니크한 값을 반환할 때 사용.
  - INDEX SUBQUERY : WHERE 조건절에서 사용 될 수 있는 IN(서브쿼리)의 접근 방식.서브 쿼리의 결과 값이 중복 된 값이 있을 수 있지만 인덱스를 이용해 중복 값을 제거 .

-현재 버전 
  - MariaDB 10.0 UNIQUE_SUBQUERY 와 INDEX_SUBQUERY를 옵티마이저가 조인 형태로 쿼리를 실행하도록 개선함.

--IN조건의 실행 계획이 메인쿼리와 같은 ID1인 것으로 보아 , 조인 조건으로 실행 된 것을 확인 
MariaDB [DA]> EXPLAIN
    -> SELECT * FROM DEPT D WHERE D.DEPTNO IN ( SELECT DEPTNO FROM EMP E WHERE E.EMPNO =7499);
+------+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+------+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
|    1 | PRIMARY     | E     | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |
|    1 | PRIMARY     | D     | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |
+------+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
2 rows in set (0.00 sec)


7 RANGE
  - 동등 조건을 검색 할 때가 아닌 범위로 검색 할 때 사용.(BETWEEN, IN,LIKE 등)을 연산자를 이용해 인덱스를 검색 할 때 사용.
  - INDEX RANGE SCAN이라고 하면 CONST,REF,RANGE 세 가지 접근 방법을 모두 묶어서 지칭함을 유의(특이한 점)

MariaDB [DA]> EXPLAIN
    -> SELECT * FROM EMP E WHERE E.EMPNO BETWEEN 1000 AND 10000;
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|    1 | SIMPLE      | E     | range | PRIMARY       | PRIMARY | 4       | NULL |   14 | Using where |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)


8 INDEX_MERGE
  - 2개의 인덱스를 이용해 검색 결과를 만들어낸 후 그 결과를 병합처리
  - 특징 
     1.여러 인덱스를 읽어야함( 효율성 떨어짐)
     2.AND OR 연산이 복잡한 경우(최적화 불가능)
     3.전문 검색 인덱스를 사용하는 쿼리에서 사용 불가능
     4.처리 결과 2개 이상이기 때문에 부가 작업 필요
 
9 INDEX(INDEX FULL SCAN)
  - INDEX 접근 방식은 INDEX를 처음부터 끝까지 읽는 INDEX FULL SCAN을 의미.
  - 일반적으로 FULL TABLE SCAN보다는 크기가 작고 정렬 되어 있기 때문에 더 효율적이다.
  - INDEX 컬럼으로 정렬 작업을 할 때, INDEX에 포함 된 컬럼만으로 처리 할 수 있는 쿼리(TABLE RANDOM ACCESS 발생 X)

MariaDB [DA]> EXPLAIN
    -> SELECT * FROM DEPT ORDER BY DEPTNO DESC LIMIT 10;
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------+
|    1 | SIMPLE      | DEPT  | index | NULL          | PRIMARY | 4       | NULL |    4 |       |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------+
1 row in set (0.00 sec)
 
10 ALL
  - FULL TABLE SCAN을 의미 . INNODB도 FULL TABLE SCAN이나 INDEX FULL SCAN과 같은 대량의 디스크 I/O를 유발하는 작업을 위해 한꺼번에 많은 페이지를 읽어드리는 기능을 제공.
  - 리드 어헤드(Read Ahead) : 연속적으로 인접한 페이지가 연속해서 몇 번 읽히게 되면 백그라운드로 작동하는 읽기 스레드가 최대 한번에 64개의 페이지씩 한꺼번에 디스크로부터 읽어드리는 방식


2. 테스트 스크립트
1.테스트 테이블 DDL 스크립트 

CREATE TABLE DA_EMP_DEPT 
(
  EMPNO INT(11) NOT NULL,
  DEPTNO CHAR(4) NOT NULL,
  START_DATE DATE NOT NULL,
  END_DATE   DATE NOT NULL,
  PRIMARY KEY (EMPNO,DEPTNO)
 )
ENGINE =INNODB;

CREATE TABLE EMP
(
  EMPNO     INT(4) NOT NULL PRIMARY KEY,
  ENAME     VARCHAR(10),
  JOB       VARCHAR(9),
  MGR       INT(4),
  HIREDATE  DATE,
  SAL       INT(7),
  COMM      INT(7),
  DEPTNO    INT(2)
)
ENGINE =INNODB;


CREATE TABLE DEPT
(
  DEPTNO  INT(2) NOT NULL PRIMARY KEY ,
  DNAME   VARCHAR(14 ),
  LOC     VARCHAR(13 )
)
ENGINE =INNODB;


2.테스트 데이터 DML 스크립트 

INSERT INTO DA_EMP_DEPT(EMPNO,DEPTNO,START_DATE,END_DATE)
VALUES('7369','10',CURRENT_DATE,CURRENT_DATE+1);
INSERT INTO DA_EMP_DEPT(EMPNO,DEPTNO,START_DATE,END_DATE)
VALUES('7499','20',CURRENT_DATE,CURRENT_DATE+2);
INSERT INTO DA_EMP_DEPT(EMPNO,DEPTNO,START_DATE,END_DATE)
VALUES('7521','20',CURRENT_DATE,CURRENT_DATE+3);
INSERT INTO DA_EMP_DEPT(EMPNO,DEPTNO,START_DATE,END_DATE)
VALUES('7566','40',CURRENT_DATE,CURRENT_DATE+4);
INSERT INTO DA_EMP_DEPT(EMPNO,DEPTNO,START_DATE,END_DATE)
VALUES('7654','50',CURRENT_DATE,CURRENT_DATE+5);
INSERT INTO DA_EMP_DEPT(EMPNO,DEPTNO,START_DATE,END_DATE)
VALUES('7698','60',CURRENT_DATE,CURRENT_DATE+6);
INSERT INTO DA_EMP_DEPT(EMPNO,DEPTNO,START_DATE,END_DATE)
VALUES('7782','70',CURRENT_DATE,CURRENT_DATE+7);
INSERT INTO DA_EMP_DEPT(EMPNO,DEPTNO,START_DATE,END_DATE)
VALUES('7788','80',CURRENT_DATE,CURRENT_DATE+8);
INSERT INTO DA_EMP_DEPT(EMPNO,DEPTNO,START_DATE,END_DATE)
VALUES('7839','90',CURRENT_DATE,CURRENT_DATE+9);
INSERT INTO DA_EMP_DEPT(EMPNO,DEPTNO,START_DATE,END_DATE)
VALUES('7844','100',CURRENT_DATE,CURRENT_DATE+10);
INSERT INTO DA_EMP_DEPT(EMPNO,DEPTNO,START_DATE,END_DATE)
VALUES('7876','110',CURRENT_DATE,CURRENT_DATE+11);


CREATE INDEX EMP_ENAME_IDX01 ON EMP(ENAME);

Insert into EMP
   (EMPNO, ENAME, JOB, MGR, HIREDATE, 
    SAL, DEPTNO)
 Values
   (7369, 'SMITH', 'CLERK', 7902, CURRENT_DATE, 
    800, 20);
Insert into EMP
   (EMPNO, ENAME, JOB, MGR, HIREDATE, 
    SAL, COMM, DEPTNO)
 Values
   (7499, 'ALLEN', 'SALESMAN', 7698, CURRENT_DATE, 
    1600, 300, 30);
Insert into EMP
   (EMPNO, ENAME, JOB, MGR, HIREDATE, 
    SAL, COMM, DEPTNO)
 Values
   (7521, 'WARD', 'SALESMAN', 7698, CURRENT_DATE, 
    1250, 500, 30);
Insert into EMP
   (EMPNO, ENAME, JOB, MGR, HIREDATE, 
    SAL, DEPTNO)
 Values
   (7566, 'JONES', 'MANAGER', 7839, CURRENT_DATE, 
    2975, 20);
Insert into EMP
   (EMPNO, ENAME, JOB, MGR, HIREDATE, 
    SAL, COMM, DEPTNO)
 Values
   (7654, 'MARTIN', 'SALESMAN', 7698, CURRENT_DATE, 
    1250, 1400, 30);
Insert into EMP
   (EMPNO, ENAME, JOB, MGR, HIREDATE, 
    SAL, DEPTNO)
 Values
   (7698, 'BLAKE', 'MANAGER', 7839, CURRENT_DATE, 
    2850, 30);
Insert into EMP
   (EMPNO, ENAME, JOB, MGR, HIREDATE, 
    SAL, DEPTNO)
 Values
   (7782, 'CLARK', 'MANAGER', 7839, CURRENT_DATE, 
    2450, 10);
Insert into EMP
   (EMPNO, ENAME, JOB, MGR, HIREDATE, 
    SAL, DEPTNO)
 Values
   (7788, 'SCOTT', 'ANALYST', 7566, CURRENT_DATE, 
    3000, 20);
Insert into EMP
   (EMPNO, ENAME, JOB, HIREDATE, SAL, 
    DEPTNO)
 Values
   (7839, 'KING', 'PRESIDENT', CURRENT_DATE, 5000, 
    10);
Insert into EMP
   (EMPNO, ENAME, JOB, MGR, HIREDATE, 
    SAL, COMM, DEPTNO)
 Values
   (7844, 'TURNER', 'SALESMAN', 7698, CURRENT_DATE, 
    1500, 0, 30);
Insert into EMP
   (EMPNO, ENAME, JOB, MGR, HIREDATE, 
    SAL, DEPTNO)
 Values
   (7876, 'ADAMS', 'CLERK', 7788, CURRENT_DATE, 
    1100, 20);
Insert into EMP
   (EMPNO, ENAME, JOB, MGR, HIREDATE, 
    SAL, DEPTNO)
 Values
   (7900, 'JAMES', 'CLERK', 7698, CURRENT_DATE, 
    950, 30);
Insert into EMP
   (EMPNO, ENAME, JOB, MGR, HIREDATE, 
    SAL, DEPTNO)
 Values
   (7902, 'FORD', 'ANALYST', 7566, CURRENT_DATE, 
    3000, 20);
Insert into EMP
   (EMPNO, ENAME, JOB, MGR, HIREDATE, 
    SAL, DEPTNO)
 Values
   (7934, 'MILLER', 'CLERK', 7782, CURRENT_DATE, 
    1300, 10);


Insert into DEPT
   (DEPTNO, DNAME, LOC)
 Values
   (10, 'ACCOUNTING', 'NEW YORK');
Insert into DEPT
   (DEPTNO, DNAME, LOC)
 Values
   (20, 'RESEARCH', 'DALLAS');
Insert into DEPT
   (DEPTNO, DNAME, LOC)
 Values
   (30, 'SALES', 'CHICAGO');
Insert into DEPT
   (DEPTNO, DNAME, LOC)
 Values
   (40, 'OPERATIONS', 'BOSTON');