開始正題前,先把我的數據庫環境列出:
# | 類別 | 版本 |
1 | 操作系統 | Win10 |
2 | 數據庫 | Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production |
3 | 硬件環境 | T440p |
下面進入正題
有個員工表emp如下:
CREATE TABLE emp ( id NUMBER not null primary key, name NVARCHAR2(60) not null, salary NUMBER(6,0) NOT NULL, deptid NUMBER(2,0) not null )
可以采用以下sql來填充數據:
Insert into emp select rownum,dbms_random.string('*',dbms_random.value(6,20)),dbms_random.value(0,50000),dbms_random.value(0,10) from dual connect by level<=10000 order by dbms_random.random
可以采取下面sql來得到每個部門的最高薪水額,以便后面的分析(得出數據這是本機的結果,諸位因為隨機數的原因一定不會和我一樣):
SQL> select max(salary),deptid from emp 2 group by deptid 3 order by deptid; MAX(SALARY) DEPTID ----------- ---------- 49944 0 49991 1 49988 2 49993 3 49927 4 49988 5 49924 6 49923 7 49848 8 49934 9 49894 10 已選擇11行。 已用時間: 00: 00: 00.01
有下面三種sql都能查詢出每個部門薪水最高的員工的結果,它們是:
1. select a.id,a.name,a.salary,a.deptid from emp a where salary=(select max(salary) from emp b where a.deptid=b.deptid) order by a.id 2. select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp group by deptid ) e2 where e1.deptid=e2.deptid and e1.salary=e2.max_sal order by e1.id 3. select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e) where salary=max_sal order by id
我分別按執行時間消耗(取第二遍sql結果)和執行計划cost列出了一個對比表格如下:
# | sql | Time elapsed | Cost |
1 | select a.id,a.name,a.salary,a.deptid from emp a
where salary=(select max(salary) from emp b where a.deptid=b.deptid) order by a.id |
00: 00: 00.03 | 41 |
2 | select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp
group by deptid ) e2 where e1.deptid=e2.deptid and e1.salary=e2.max_sal order by e1.id |
00: 00: 07.92 | 641 |
3 | select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e)
where salary=max_sal order by id |
00: 00: 00.01 | 471 |
按時間消耗是3勝出,1緊隨,2差一大截;按cost是1勝出,3和2差了一個數量級;按從執行感覺來說是1,3最快,體會不出差別,而2有明顯的停頓。
我的結論是:因為時間消耗和感覺兩者可以互相對證,因此是可信的,但執行計划給出的結論在3的身上與現實有明顯差別,只好棄而不取。
這個示例證明,執行計划的cost不能單獨拿來說明哪個sql更優,即使兩者比較差一個數量級也不可貿然采信,它必須得到耗時和現實運行感覺的印證才行;反而耗時可行度很高,按我的經驗可以單獨采信。
附:耗時比較:
SQL> select a.id,a.name,a.salary,a.deptid from emp a 2 where salary=(select max(salary) from emp b where a.deptid=b.deptid) 3 order by a.id; ID NAME SALARY DEPTID ---------- ------------------------------------------------------------------------------------------------------------------------ ---------- ---------- 1073 UGJURPQV 49993 3 1356 UPHXQELWTDBLFYRBSHSF 49991 1 2946 SGSJBCABNNQXGORWPO 49924 6 3111 PQMATSYLQNZR 49848 8 3516 CBXGAVDIHITQ 49944 0 6218 LPZAQPOKQSJNAMNTOT 49923 7 7874 LBQPRRDVXUQS 49988 5 9032 OPVFSDKNZ 49988 2 9329 XRNKOKCCUORV 49934 9 9437 WQDWBTNEKJJYFL 49894 10 9979 YLXJXJPRKKBXAQIE 49927 4 已選擇11行。 已用時間: 00: 00: 00.03 SQL> select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp 2 group by deptid 3 ) e2 4 where e1.deptid=e2.deptid and e1.salary=e2.max_sal 5 order by e1.id; ID NAME SALARY DEPTID ---------- ------------------------------------------------------------------------------------------------------------------------ ---------- ---------- 1073 UGJURPQV 49993 3 1356 UPHXQELWTDBLFYRBSHSF 49991 1 2946 SGSJBCABNNQXGORWPO 49924 6 3111 PQMATSYLQNZR 49848 8 3516 CBXGAVDIHITQ 49944 0 6218 LPZAQPOKQSJNAMNTOT 49923 7 7874 LBQPRRDVXUQS 49988 5 9032 OPVFSDKNZ 49988 2 9329 XRNKOKCCUORV 49934 9 9437 WQDWBTNEKJJYFL 49894 10 9979 YLXJXJPRKKBXAQIE 49927 4 已選擇11行。 已用時間: 00: 00: 07.92 SQL> select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e) 2 where salary=max_sal 3 order by id; ID NAME SALARY DEPTID ---------- ------------------------------------------------------------------------------------------------------------------------ ---------- ---------- 1073 UGJURPQV 49993 3 1356 UPHXQELWTDBLFYRBSHSF 49991 1 2946 SGSJBCABNNQXGORWPO 49924 6 3111 PQMATSYLQNZR 49848 8 3516 CBXGAVDIHITQ 49944 0 6218 LPZAQPOKQSJNAMNTOT 49923 7 7874 LBQPRRDVXUQS 49988 5 9032 OPVFSDKNZ 49988 2 9329 XRNKOKCCUORV 49934 9 9437 WQDWBTNEKJJYFL 49894 10 9979 YLXJXJPRKKBXAQIE 49927 4 已選擇11行。 已用時間: 00: 00: 00.01
執行計划比較:
SQL> select a.id,a.name,a.salary,a.deptid from emp a 2 where salary=(select max(salary) from emp b where a.deptid=b.deptid) 3 order by a.id; 已用時間: 00: 00: 00.00 執行計划 ---------------------------------------------------------- Plan hash value: 1231226589 --------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 127 | 41 (8)| 00:00:01 | | 1 | SORT ORDER BY | | 1 | 127 | 41 (8)| 00:00:01 | |* 2 | HASH JOIN | | 1 | 127 | 40 (5)| 00:00:01 | | 3 | VIEW | VW_SQ_1 | 9121 | 231K| 21 (10)| 00:00:01 | | 4 | HASH GROUP BY | | 9121 | 231K| 21 (10)| 00:00:01 | | 5 | TABLE ACCESS FULL| EMP | 9121 | 231K| 19 (0)| 00:00:01 | | 6 | TABLE ACCESS FULL | EMP | 9121 | 899K| 19 (0)| 00:00:01 | --------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("SALARY"="MAX(SALARY)" AND "A"."DEPTID"="ITEM_1") Note ----- - dynamic sampling used for this statement (level=2) SQL> select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp 2 group by deptid 3 ) e2 4 where e1.deptid=e2.deptid and e1.salary=e2.max_sal 5 order by e1.id; 已用時間: 00: 00: 00.00 執行計划 ---------------------------------------------------------- Plan hash value: 962461943 ----------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 7562K| 1002M| 641 (95)| 00:00:08 | |* 1 | FILTER | | | | | | | 2 | SORT GROUP BY | | 7562K| 1002M| 641 (95)| 00:00:08 | |* 3 | HASH JOIN | | 7562K| 1002M| 92 (59)| 00:00:02 | | 4 | TABLE ACCESS FULL| EMP | 9121 | 231K| 19 (0)| 00:00:01 | | 5 | TABLE ACCESS FULL| EMP | 9121 | 1006K| 19 (0)| 00:00:01 | ----------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("E1"."SALARY"=MAX("SALARY")) 3 - access("E1"."DEPTID"="DEPTID") Note ----- - dynamic sampling used for this statement (level=2) SQL> select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e) 2 where salary=max_sal 3 order by id; 已用時間: 00: 00: 00.00 執行計划 ---------------------------------------------------------- Plan hash value: 3418936035 ------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | ------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 9121 | 1015K| | 471 (1)| 00:00:06 | | 1 | SORT ORDER BY | | 9121 | 1015K| 1168K| 471 (1)| 00:00:06 | |* 2 | VIEW | | 9121 | 1015K| | 234 (1)| 00:00:03 | | 3 | WINDOW SORT | | 9121 | 899K| 1056K| 234 (1)| 00:00:03 | | 4 | TABLE ACCESS FULL| EMP | 9121 | 899K| | 19 (0)| 00:00:01 | ------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("SALARY"="MAX_SAL") Note ----- - dynamic sampling used for this statement (level=2)
2020年1月19日
參考資料:https://blog.csdn.net/paul_wei2008/article/details/19565509
2020-01-20補記,下面是在oracle12上執行的解釋計划,取得第二遍結果,但結論,更讓人迷糊了,這再次說明解釋計划不能單獨采信。
Oracle版本:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production PL/SQL Release 12.2.0.1.0 - Production "CORE 12.2.0.1.0 Production" TNS for Linux: Version 12.2.0.1.0 - Production NLSRTL Version 12.2.0.1.0 - Production #1 EXPLAIN PLAN FOR select a.id,a.name,a.salary,a.deptid from emp a where salary=(select max(salary) from emp b where a.deptid=b.deptid) order by a.id Plan hash value: 1231226589 --------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 11 | 605 | 40 (5)| 00:00:01 | | 1 | SORT ORDER BY | | 11 | 605 | 40 (5)| 00:00:01 | |* 2 | HASH JOIN | | 11 | 605 | 39 (3)| 00:00:01 | | 3 | VIEW | VW_SQ_1 | 11 | 176 | 20 (5)| 00:00:01 | | 4 | HASH GROUP BY | | 11 | 88 | 20 (5)| 00:00:01 | | 5 | TABLE ACCESS FULL| EMP | 10000 | 80000 | 19 (0)| 00:00:01 | | 6 | TABLE ACCESS FULL | EMP | 10000 | 380K| 19 (0)| 00:00:01 | --------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("SALARY"="MAX(SALARY)" AND "A"."DEPTID"="ITEM_1") #2 select e1.id,e1.name,e1.salary,e1.deptid from emp e1,(select max(salary) max_sal,deptid from emp group by deptid ) e2 where e1.deptid=e2.deptid and e1.salary=e2.max_sal order by e1.id Plan hash value: 2003893481 ------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 11 | 605 | 40 (5)| 00:00:01 | | 1 | SORT ORDER BY | | 11 | 605 | 40 (5)| 00:00:01 | |* 2 | HASH JOIN | | 11 | 605 | 39 (3)| 00:00:01 | | 3 | VIEW | | 11 | 176 | 20 (5)| 00:00:01 | | 4 | HASH GROUP BY | | 11 | 88 | 20 (5)| 00:00:01 | | 5 | TABLE ACCESS FULL| EMP | 10000 | 80000 | 19 (0)| 00:00:01 | | 6 | TABLE ACCESS FULL | EMP | 10000 | 380K| 19 (0)| 00:00:01 | ------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("E1"."DEPTID"="E2"."DEPTID" AND "E1"."SALARY"="E2"."MAX_SAL") #3 select id,name,salary,deptid from (select e.*,max(salary) over (partition by deptid) max_sal from emp e) where salary=max_sal order by id Plan hash value: 3418936035 ------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | ------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 10000 | 1035K| | 365 (1)| 00:00:01 | | 1 | SORT ORDER BY | | 10000 | 1035K| 1192K| 365 (1)| 00:00:01 | |* 2 | VIEW | | 10000 | 1035K| | 121 (1)| 00:00:01 | | 3 | WINDOW SORT | | 10000 | 380K| 520K| 121 (1)| 00:00:01 | | 4 | TABLE ACCESS FULL| EMP | 10000 | 380K| | 19 (0)| 00:00:01 | ------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("SALARY"="MAX_SAL")