51Testing
怬
µçÄÔ°æ

Ò»´Î¸ã¶¨¸÷ÖÖÊý¾Ý¿â SQL Ö´Ðмƻ®

2020-2-05 13:19×÷Õߣº¶­ÐñÑôTonyDongÀ´Ô´£ºCSDN

¡¡¡¡Ö´Ðмƻ®£¨execution plan£¬Ò²½Ð²éѯ¼Æ»®»òÕß½âÊͼƻ®£©ÊÇÊý¾Ý¿âÖ´ÐÐ SQL Óï¾äµÄ¾ßÌå²½Ö裬ÀýÈçͨ¹ýË÷Òý»¹ÊÇÈ«±íɨÃè·ÃÎʱíÖеÄÊý¾Ý£¬Á¬½Ó²éѯµÄʵÏÖ·½Ê½ºÍÁ¬½ÓµÄ˳ÐòµÈ¡£Èç¹û SQL Óï¾äÐÔÄܲ»¹»ÀíÏ룬ÎÒÃÇÊ×ÏÈÓ¦¸Ã²é¿´ËüµÄÖ´Ðмƻ®¡£±¾ÎÄÖ÷Òª½éÉÜÈçºÎÔÚ¸÷ÖÖÊý¾Ý¿âÖлñÈ¡ºÍÀí½âÖ´Ðмƻ®£¬²¢¸ø³ö½øÒ»²½ÉîÈë·ÖÎöµÄ²Î¿¼Îĵµ¡£
¡¡¡¡ÏÖÔÚÐí¶à¹ÜÀíºÍ¿ª·¢¹¤¾ß¶¼ÌṩÁ˲鿴ͼÐλ¯Ö´Ðмƻ®µÄ¹¦ÄÜ£¬ÀýÈç MySQL Workbench¡¢Oracle SQL Developer¡¢SQL Server Management Studio¡¢DBeaver µÈ£»²»¹ýÎÒÃDz»´òËãʹÓÃÕâÀ๤¾ß£¬¶øÊǽéÉÜÀûÓÃÊý¾Ý¿âÌṩµÄÃüÁî²é¿´Ö´Ðмƻ®¡£
¡¡¡¡ÎÒÃÇÏȸø³öÔÚ¸÷ÖÖÊý¾Ý¿âÖв鿴ִÐмƻ®µÄÒ»¸ö¼òµ¥»ã×Ü£º
¡¡¡¡±¾ÎÄʹÓõÄʾÀý±íºÍÊý¾Ý¿ÉÒÔµã»÷Á´½Ó¡¶SQL ÈëÃŽ̡̳·Ê¾ÀýÊý¾Ý¿â£¨https://tonydong.blog.csdn.net/article/details/86518676£©¡£
¡¡¡¡1¡¢MySQL Ö´Ðмƻ®
¡¡¡¡MySQL ÖлñÈ¡Ö´Ðмƻ®µÄ·½·¨ºÜ¼òµ¥£¬¾ÍÊÇÔÚ SQL Óï¾äµÄÇ°Ãæ¼ÓÉÏEXPLAIN¹Ø¼ü×Ö£º
EXPLAIN
SELECT e.first_name,e.last_name,e.salary,d.department_name
FROM employees e
JOIN departments d ON (e.department_id = d.department_id)
WHERE e.salary > 15000;
Ö´ÐиÃÓï¾ä½«»á·µ»ØÒ»¸ö±í¸ñÐÎʽµÄÖ´Ðмƻ®£¬°üº¬ÁË 12 ÁÐÐÅÏ¢£º
id|select_type|table|partitions|type  |possible_keys    |key    |key_len|ref                 |rows|filtered|Extra      |
--|-----------|-----|----------|------|-----------------|-------|-------|--------------------|----|--------|-----------|
1|SIMPLE     |e    |          |ALL   |emp_department_ix|       |       |                    | 107|   33.33|Using where|
1|SIMPLE     |d    |          |eq_ref|PRIMARY          |PRIMARY|4      |hrdb.e.department_id|   1|     100|        |
¡¡¡¡MySQL ÖеÄEXPLAINÖ§³Ö SELECT¡¢DELETE¡¢INSERT¡¢REPLACE ÒÔ¼° UPDATE Óï¾ä¡£
¡¡¡¡½ÓÏÂÀ´£¬ÎÒÃÇÒª×öµÄ¾ÍÊÇÀí½âÖ´Ðмƻ®ÖÐÕâЩ×ֶεĺ¬Ò塣ϱíÁгöÁË MySQL Ö´Ðмƻ®Öеĸ÷¸ö×ֶεÄ×÷Óãº
¡¡¡¡¶ÔÓÚÉÏÃæµÄʾÀý£¬Ö»ÓÐÒ»¸ö SELECT ×Ӿ䣬id ¶¼Îª 1£»Ê×ÏÈ¶Ô employees ±íÖ´ÐÐÈ«±íɨÃ裨type = ALL£©£¬´¦ÀíÁË 107 ÐÐÊý¾Ý£¬Ê¹Óà WHERE Ìõ¼þ¹ýÂ˺óÔ¤¼ÆʣϠ33.33% µÄÊý¾Ý£¨¹À¼Æ²»×¼È·£©£»È»ºóÕë¶ÔÕâЩÊý¾Ý£¬ÒÀ´ÎʹÓà departments ±íµÄÖ÷¼ü£¨key = PRIMARY£©²éÕÒÒ»ÐÐÆ¥ÅäµÄÊý¾Ý£¨type = eq_ref¡¢rows = 1£©¡£
¡¡¡¡Ê¹Óà MySQL 8.0 ÐÂÔöµÄ ANALYZE Ñ¡Ïî¿ÉÒÔÏÔʾʵ¼ÊÖ´ÐÐʱ¼äµÈ¶îÍâµÄÐÅÏ¢£º
EXPLAIN ANALYZE
SELECT e.first_name,e.last_name,e.salary,d.department_name
FROM employees e
JOIN departments d ON (e.department_id = d.department_id)
WHERE e.salary > 15000;
-> Nested loop inner join  (cost=23.43 rows=36) (actual time=0.325..1.287 rows=3 loops=1)
-> Filter: ((e.salary > 15000.00) and (e.department_id is not null))  (cost=10.95 rows=36) (actual time=0.281..1.194 rows=3 loops=1)
-> Table scan on e  (cost=10.95 rows=107) (actual time=0.266..0.716 rows=107 loops=1)
-> Single-row index lookup on d using PRIMARY (department_id=e.department_id)  (cost=0.25 rows=1) (actual time=0.013..0.015 rows=1 loops=3)
¡¡¡¡ÆäÖУ¬Nested loop inner join ±íʾʹÓÃǶÌ×Ñ­»·Á¬½ÓµÄ·½Ê½Á¬½ÓÁ½¸ö±í£¬employees ΪÇý¶¯±í¡£cost ±íʾ¹ÀËãµÄ´ú¼Û£¬rows ±íʾ¹À¼Æ·µ»ØµÄÐÐÊý£»actual time ÏÔʾÁË·µ»ØµÚÒ»ÐкÍËùÓÐÊý¾ÝÐл¨·ÑµÄʵ¼Êʱ¼ä£¬ºóÃæµÄ rows ±íʾµü´úÆ÷·µ»ØµÄÐÐÊý£¬loops ±íʾµü´úÆ÷Ñ­»·µÄ´ÎÊý¡£
¡¡¡¡¹ØÓÚ MySQL EXPLAIN ÃüÁîµÄʹÓúͲÎÊý£¬¿ÉÒԲο¼ MySQL ¹Ù·½Îĵµ EXPLAIN Óï¾ä£¨https://dev.mysql.com/doc/refman/8.0/en/explain.html£©¡£
¡¡¡¡¹ØÓÚ MySQL Ö´Ðмƻ®µÄÊä³öÐÅÏ¢£¬¿ÉÒԲο¼ MySQL ¹Ù·½ÎĵµÀí½â²éѯִÐмƻ®£¨https://dev.mysql.com/doc/refman/8.0/en/execution-plan-information.html£©¡£
¡¡¡¡2¡¢Oracle Ö´Ðмƻ®
¡¡¡¡Oracle ÖÐÌṩÁ˶àÖֲ鿴ִÐмƻ®µÄ·½·¨£¬±¾ÎÄʹÓÃÒÔÏ·½Ê½£º
¡¡¡¡£¨1£©Ê¹ÓÃEXPLAIN PLAN FORÃüÁîÉú³É²¢±£´æÖ´Ðмƻ®£»
¡¡¡¡£¨2£©ÏÔʾ±£´æµÄÖ´Ðмƻ®¡£
¡¡¡¡Ê×ÏÈ£¬Éú³ÉÖ´Ðмƻ®£º
EXPLAIN PLAN FOR
SELECT e.first_name,e.last_name,e.salary,d.department_name
FROM employees e
JOIN departments d ON (e.department_id = d.department_id)
WHERE e.salary > 15000;
¡¡¡¡EXPLAIN PLAN FORÃüÁî²»»áÔËÐÐ SQL Óï¾ä£¬Òò´Ë´´½¨µÄÖ´Ðмƻ®²»Ò»¶¨ÓëÖ´ÐиÃÓï¾äʱµÄʵ¼Ê¼Æ»®Ïàͬ¡£
¡¡¡¡¸ÃÃüÁî»á½«Éú³ÉµÄÖ´Ðмƻ®±£´æµ½È«¾ÖµÄÁÙʱ±í PLAN_TABLE ÖУ¬È»ºóʹÓÃϵͳ°ü DBMS_XPLAN ÖеĴ洢¹ý³Ì¸ñʽ»¯ÏÔʾ¸Ã±íÖеÄÖ´Ðмƻ®¡£ÒÔÏÂÓï¾ä¿ÉÒԲ鿴µ±Ç°»á»°ÖеÄ×îºóÒ»¸öÖ´Ðмƻ®£º
SELECT * FROM TABLE(DBMS_XPLAN.display);
PLAN_TABLE_OUTPUT                                                                           |
--------------------------------------------------------------------------------------------|
Plan hash value: 1343509718                                                                 |
|
--------------------------------------------------------------------------------------------|
| Id  | Operation                    | Name        | Rows  | Bytes | Cost (%CPU)| Time     ||
--------------------------------------------------------------------------------------------|
|   0 | SELECT STATEMENT             |             |    44 |  1672 |     6  (17)| 00:00:01 ||
|   1 |  MERGE JOIN                  |             |    44 |  1672 |     6  (17)| 00:00:01 ||
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPARTMENTS |    27 |   432 |     2   (0)| 00:00:01 ||
|   3 |    INDEX FULL SCAN           | DEPT_ID_PK  |    27 |       |     1   (0)| 00:00:01 ||
|*  4 |   SORT JOIN                  |             |    44 |   968 |     4  (25)| 00:00:01 ||
|*  5 |    TABLE ACCESS FULL         | EMPLOYEES   |    44 |   968 |     3   (0)| 00:00:01 ||
--------------------------------------------------------------------------------------------|
|
Predicate Information (identified by operation id):                                         |
---------------------------------------------------                                         |
|
4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")                                      |
filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")                                      |
5 - filter("E"."SALARY">15000)                                                           |
¡¡¡¡Oracle ÖеÄEXPLAIN PLAN FORÖ§³Ö SELECT¡¢UPDATE¡¢INSERT ÒÔ¼° DELETE Óï¾ä¡£
¡¡¡¡½ÓÏÂÀ´£¬ÎÒÃÇͬÑùÐèÒªÀí½âÖ´Ðмƻ®Öи÷ÖÖÐÅÏ¢µÄº¬Ò壺
¡¡¡¡¡¤ Plan hash value ÊǸÃÓï¾äµÄ¹þÏ£Öµ¡£SQL Óï¾äºÍÖ´Ðмƻ®»á´æ´¢Ôڿ⻺´æÖУ¬¹þÏ£ÖµÏàͬµÄÓï¾ä¿ÉÒÔÖØÓÃÒÑÓеÄÖ´Ðмƻ®£¬Ò²¾ÍÊÇÈí½âÎö£»
¡¡¡¡¡¤ Id ÊÇÒ»¸öÐòºÅ£¬µ«²»´ú±íÖ´ÐеÄ˳Ðò¡£Ö´ÐеÄ˳Ðò°´ÕÕËõ½øÀ´Åжϣ¬Ëõ½øÔ½¶àµÄÔ½ÏÈÖ´ÐУ¬Í¬ÑùËõ½øµÄ´ÓÉÏÖÁÏÂÖ´ÐС£Id Ç°ÃæµÄÐǺűíʾʹÓÃÁËν´ÊÅжϣ¬²Î¿¼ÏÂÃæµÄ Predicate Information£»
¡¡¡¡¡¤ Operation ±íʾµ±Ç°µÄ²Ù×÷£¬Ò²¾ÍÊÇÈçºÎ·ÃÎʱíµÄÊý¾Ý¡¢ÈçºÎʵÏÖ±íµÄÁ¬½Ó¡¢ÈçºÎ½øÐÐÅÅÐò²Ù×÷µÈ£»
¡¡¡¡¡¤ Name ÏÔʾÁË·ÃÎʵıíÃû¡¢Ë÷ÒýÃû»òÕß×Ó²éѯµÈ£¬Ç°ÌáÊǵ±Ç°²Ù×÷Éæ¼°µ½ÁËÕâЩ¶ÔÏó£»
¡¡¡¡¡¤ Rows ÊÇ Oracle ¹À¼ÆµÄµ±Ç°²Ù×÷·µ»ØµÄÐÐÊý£¬Ò²½Ð»ùÊý£¨Cardinality£©£»
¡¡¡¡¡¤ Bytes ÊÇ Oracle ¹À¼ÆµÄµ±Ç°²Ù×÷Éæ¼°µÄÊý¾ÝÁ¿
¡¡¡¡¡¤ Cost (%CPU) ÊÇ Oracle ¼ÆËãÖ´ÐиòÙ×÷ËùÐèµÄ´ú¼Û£»
¡¡¡¡¡¤ Time ÊÇ Oracle ¹À¼ÆÖ´ÐиòÙ×÷ËùÐèµÄʱ¼ä£»
¡¡¡¡¡¤ Predicate Information ÏÔʾÓë Id Ïà¹ØµÄν´ÊÐÅÏ¢¡£access ÊÇ·ÃÎÊÌõ¼þ£¬Ó°Ïìµ½Êý¾ÝµÄ·ÃÎÊ·½Ê½£¨É¨Ãè±í»¹ÊÇͨ¹ýË÷Òý£©£»filter ÊǹýÂËÌõ¼þ£¬»ñÈ¡Êý¾Ýºó¸ù¾Ý¸ÃÌõ¼þ½øÐйýÂË¡£
¡¡¡¡ÔÚÉÏÃæµÄʾÀýÖУ¬Id µÄÖ´ÐÐ˳ÐòÒÀ´ÎΪ 3 -> 2 -> 5 -> 4- >1¡£Ê×ÏÈ£¬Id = 3 ɨÃèÖ÷¼üË÷Òý DEPT_ID_PK£¬Id = 2 °´Ö÷¼ü ROWID ·ÃÎʱí DEPARTMENTS£¬½á¹ûÒѾ­ÅÅÐò£»Æä´Î£¬Id = 5 È«±íɨÃè·ÃÎÊ EMPLOYEES ²¢ÇÒÀûÓà filter ¹ýÂËÊý¾Ý£¬Id = 4 »ùÓÚ²¿ÃűàºÅ½øÐÐÅÅÐòºÍ¹ýÂË£»×îºó Id = 1 Ö´Ðкϲ¢Á¬½Ó¡£ÏÔÈ»£¬´Ë´¦ Oracle Ñ¡ÔñÁËÅÅÐòºÏ²¢Á¬½ÓµÄ·½Ê½ÊµÏÖÁ½¸ö±íµÄÁ¬½Ó¡£
¡¡¡¡¹ØÓÚ Oracle Ö´Ðмƻ®ºÍ SQL µ÷ÓÅ£¬¿ÉÒԲο¼ Oracle ¹Ù·½Îĵµ¡¶SQL Tuning Guide¡·£¨https://docs.oracle.com/en/database/oracle/oracle-database/19/tgsql/£©¡£
¡¡¡¡3¡¢SQL Server Ö´Ðмƻ®
¡¡¡¡SQL Server Management Studio ÌṩÁ˲鿴ͼÐλ¯Ö´Ðмƻ®µÄ¼òµ¥·½·¨£¬ÕâÀïÎÒÃǽéÉÜÒ»ÖÖͨ¹ýÃüÁî²é¿´µÄ·½·¨£º
¡¡¡¡SET STATISTICS PROFILE ON
¡¡¡¡ÒÔÉÏÃüÁî¿ÉÒÔ´ò¿ª SQL Server Óï¾äµÄ·ÖÎö¹¦ÄÜ£¬´ò¿ªÖ®ºóÖ´ÐеÄÓï¾ä»á¶îÍâ·µ»ØÏàÓ¦µÄÖ´Ðмƻ®£º
SELECT e.first_name,e.last_name,e.salary,d.department_name
FROM employees e
JOIN departments d ON (e.department_id = d.department_id)
WHERE e.salary > 15000;
first_name|last_name|salary  |department_name|
----------|---------|--------|---------------|
Steven    |King     |24000.00|Executive      |
Neena     |Kochhar  |17000.00|Executive      |
Lex       |De Haan  |17000.00|Executive      |
Rows|Executes|StmtText                                                                                                                                                                                           |StmtId|NodeId|Parent|PhysicalOp          |LogicalOp           |Argument                                                                                                                                                           |DefinedValues                                                       |EstimateRows|EstimateIO  |EstimateCPU|AvgRowSize|TotalSubtreeCost|OutputList                                                            |Warnings|Type    |Parallel|EstimateExecutions|
----|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------|------|------|--------------------|--------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|------------|------------|-----------|----------|----------------|----------------------------------------------------------------------|--------|--------|--------|------------------|
3|       1|SELECT e.first_name,e.last_name,e.salary,d.department_name?  FROM employees e?  JOIN departments d ON (e.department_id = d.department_id)? WHERE e.salary > 15000                                  |     1|     1|     0|                    |                    |                                                                                                                                                                   |                                                                    |   2.9719627|            |           |          |     0.007803641|                                                                      |        |SELECT  |       0|                  |
3|       1|  |--Nested Loops(Inner Join, OUTER REFERENCES:([e].[department_id]))                                                                                                                              |     1|     2|     1|Nested Loops        |Inner Join          |OUTER REFERENCES:([e].[department_id])                                                                                                                             |                                                                    |   2.9719627|           0|          0|        57|     0.007803641|[e].[first_name], [e].[last_name], [e].[salary], [d].[department_name]|        |PLAN_ROW|       0|                 1|
3|       1|       |--Clustered Index Scan(OBJECT:([hrdb].[dbo].[employees].[emp_emp_id_pk] AS [e]), WHERE:([hrdb].[dbo].[employees].[salary] as [e].[salary]>(15000.00)))                                     |     1|     3|     2|Clustered Index Scan|Clustered Index Scan|OBJECT:([hrdb].[dbo].[employees].[emp_emp_id_pk] AS [e]), WHERE:([hrdb].[dbo].[employees].[salary] as [e].[salary]>(15000.00))                                     |[e].[first_name], [e].[last_name], [e].[salary], [e].[department_id]|           3|0.0038657407|   2.747E-4|        44|     0.004140441|[e].[first_name], [e].[last_name], [e].[salary], [e].[department_id]  |        |PLAN_ROW|       0|                 1|
3|       3|       |--Clustered Index Seek(OBJECT:([hrdb].[dbo].[departments].[dept_id_pk] AS [d]), SEEK:([d].[department_id]=[hrdb].[dbo].[employees].[department_id] as [e].[department_id]) ORDERED FORWARD)|     1|     4|     2|Clustered Index Seek|Clustered Index Seek|OBJECT:([hrdb].[dbo].[departments].[dept_id_pk] AS [d]), SEEK:([d].[department_id]=[hrdb].[dbo].[employees].[department_id] as [e].[department_id]) ORDERED FORWARD|[d].[department_name]                                               |           1|    0.003125|   1.581E-4|        26|       0.0035993|[d].[department_name]                                                 |        |PLAN_ROW|       0|                 3|
¡¡¡¡SQL Server ÖеÄÖ´Ðмƻ®Ö§³Ö SELECT¡¢INSERT¡¢UPDATE¡¢DELETE ÒÔ¼° EXECUTE Óï¾ä¡£
¡¡¡¡SQL Server Ö´Ðмƻ®¸÷¸ö²½ÖèµÄÖ´ÐÐ˳Ðò°´ÕÕËõ½øÀ´Åжϣ¬Ëõ½øÔ½¶àµÄÔ½ÏÈÖ´ÐУ¬Í¬ÑùËõ½øµÄ´ÓÉÏÖÁÏÂÖ´ÐС£½ÓÏÂÀ´£¬ÎÒÃÇÐèÒªÀí½âÖ´Ðмƻ®Öи÷ÖÖÐÅÏ¢µÄº¬Ò壺
¡¡¡¡¡¤ Rows ±íʾ¸Ã²½Öèʵ¼Ê²úÉúµÄ¼Ç¼Êý£»
¡¡¡¡¡¤ Executes ±íʾ¸Ã²½Öèʵ¼Ê±»Ö´ÐеĴÎÊý£»
¡¡¡¡¡¤ StmtText °üº¬ÁËÿ¸ö²½ÖèµÄ¾ßÌåÃèÊö£¬Ò²¾ÍÊÇÈçºÎ·ÃÎʺ͹ýÂ˱íµÄÊý¾Ý¡¢ÈçºÎʵÏÖ±íµÄÁ¬½Ó¡¢ÈçºÎ½øÐÐÅÅÐò²Ù×÷µÈ£»
¡¡¡¡¡¤ StmtId£¬¸ÃÓï¾äµÄ±àºÅ£»
¡¡¡¡¡¤ NodeId£¬µ±Ç°²Ù×÷²½ÖèµÄ½ÚµãºÅ£¬²»´ú±íÖ´ÐÐ˳Ðò£»
¡¡¡¡¡¤ Parent£¬µ±Ç°²Ù×÷²½ÖèµÄ¸¸½Úµã£¬ÏÈÖ´ÐÐ×ӽڵ㣬ÔÙÖ´Ðи¸½Úµã£»
¡¡¡¡¡¤ PhysicalOp£¬ÎïÀí²Ù×÷£¬ÀýÈçÁ¬½Ó²Ù×÷µÄǶÌ×Ñ­»·ÊµÏÖ£»
¡¡¡¡¡¤ LogicalOp£¬Âß¼­²Ù×÷£¬ÀýÈçÄÚÁ¬½Ó²Ù×÷£»
¡¡¡¡¡¤ Argument£¬²Ù×÷ʹÓõIJÎÊý£»
¡¡¡¡¡¤ DefinedValues£¬¶¨ÒåµÄ±äÁ¿Öµ£»
¡¡¡¡¡¤ EstimateRows£¬¹À¼Æ·µ»ØµÄÐÐÊý£»
¡¡¡¡¡¤ EstimateIO£¬¹À¼ÆµÄ IO ³É±¾£»
¡¡¡¡¡¤ EstimateCPU£¬¹À¼ÆµÄ CPU ³É±¾£»
¡¡¡¡¡¤ AvgRowSize£¬Æ½¾ù·µ»ØµÄÐдóС£»
¡¡¡¡¡¤ TotalSubtreeCost£¬µ±Ç°½ÚµãÀۼƵijɱ¾£»
¡¡¡¡¡¤ OutputList£¬µ±Ç°½ÚµãÊä³öµÄ×Ö¶ÎÁÐ±í£»
¡¡¡¡¡¤ Warnings£¬Ô¤¹ÀµÃµ½µÄ¾¯¸æÐÅÏ¢£»
¡¡¡¡¡¤ Type£¬µ±Ç°²Ù×÷²½ÖèµÄÀàÐÍ£»
¡¡¡¡¡¤ Parallel£¬ÊÇ·ñ²¢ÐÐÖ´ÐУ»
¡¡¡¡¡¤ EstimateExecutions£¬¸Ã²½ÖèÔ¤¼Æ±»Ö´ÐеĴÎÊý£»
¡¡¡¡¶ÔÓÚÉÏÃæµÄÓï¾ä£¬½ÚµãÖ´ÐеÄ˳ÐòΪ 3 -> 4 -> 2 -> 1¡£Ê×ÏÈÖ´ÐÐµÚ 3 ÐУ¬Í¨¹ý¾Û¼¯Ë÷Òý£¨Ö÷¼ü£©É¨Ãè employees ±í¼Ó¹ýÂ˵ķ½Ê½·µ»ØÁË 3 ÐÐÊý¾Ý£¬¹À¼ÆµÄÐÐÊý£¨3.0841121673583984£©Óë´Ë·Ç³£½Ó½ü£»È»ºóÖ´ÐÐµÚ 4 ÐУ¬Ñ­»·Ê¹Óþۼ¯Ë÷ÒýµÄ·½Ê½²éÕÒ departments ±í£¬Ñ­»· 3 ´Îÿ´Î·µ»Ø 1 ÐÐÊý¾Ý£»µÚ 2 ÐÐÊÇËüÃǵĸ¸½Úµã£¬±íʾʹÓà Nested Loops ·½Ê½ÊµÏÖ Inner Join£¬Argument ÁУ¨OUTER REFERENCES:([e].[department_id])£©ËµÃ÷Çý¶¯±íΪ employees £»µÚ 1 Ðдú±íÁËÕû¸ö²éѯ£¬²»Ö´ÐÐʵ¼Ê²Ù×÷¡£
¡¡¡¡×îºó£¬¿ÉÒÔʹÓÃÒÔÏÂÃüÁî¹Ø±ÕÓï¾äµÄ·ÖÎö¹¦ÄÜ£º
¡¡¡¡SET STATISTICS PROFILE OFF
¡¡¡¡¹ØÓÚ SQL Server Ö´Ðмƻ®ºÍ SQL µ÷ÓÅ£¬¿ÉÒԲο¼ SQL Server ¹Ù·½ÎĵµÖ´Ðмƻ®¡£
¡¡¡¡4¡¢PostgreSQL Ö´Ðмƻ®
¡¡¡¡PostgreSQL ÖлñÈ¡Ö´Ðмƻ®µÄ·½·¨Óë MySQL ÀàËÆ£¬Ò²¾ÍÊÇÔÚ SQL Óï¾äµÄÇ°Ãæ¼ÓÉÏEXPLAIN¹Ø¼ü×Ö£º
EXPLAIN
SELECT e.first_name,e.last_name,e.salary,d.department_name
FROM employees e
JOIN departments d ON (e.department_id = d.department_id)
WHERE e.salary > 15000;
QUERY PLAN                                                            |
----------------------------------------------------------------------|
Hash Join  (cost=3.38..4.84 rows=3 width=29)                          |
Hash Cond: (d.department_id = e.department_id)                      |
->  Seq Scan on departments d  (cost=0.00..1.27 rows=27 width=15)   |
->  Hash  (cost=3.34..3.34 rows=3 width=22)                         |
->  Seq Scan on employees e  (cost=0.00..3.34 rows=3 width=22)|
Filter: (salary > '15000'::numeric)                     |
¡¡¡¡PostgreSQL ÖеÄEXPLAINÖ§³Ö SELECT¡¢INSERT¡¢UPDATE¡¢DELETE¡¢VALUES¡¢EXECUTE¡¢DECLARE¡¢CREATE TABLE AS ÒÔ¼° CREATE MATERIALIZED VIEW AS Óï¾ä¡£
¡¡¡¡PostgreSQL Ö´Ðмƻ®µÄ˳Ðò°´ÕÕËõ½øÀ´Åжϣ¬Ëõ½øÔ½¶àµÄÔ½ÏÈÖ´ÐУ¬Í¬ÑùËõ½øµÄ´ÓÉÏÖÁÏÂÖ´ÐС£¶ÔÓÚÒÔÉÏʾÀý£¬Ê×ÏÈ¶Ô employees ±íÖ´ÐÐÈ«±íɨÃ裨Seq Scan£©£¬Ê¹Óà salary > 15000 ×÷Ϊ¹ýÂËÌõ¼þ£»cost ·Ö±ðÏÔʾÁËÔ¤¹ÀµÄ·µ»ØµÚÒ»Ðеijɱ¾£¨0.00£©ºÍ·µ»ØËùÓÐÐеijɱ¾£¨3.34£©£»rows ±íʾԤ¹À·µ»ØµÄÐÐÊý£»width ±íʾԤ¹À·µ»ØÐеĴóС£¨µ¥Î» Byte£©¡£È»ºó½«É¨Ãè½á¹û·ÅÈëµ½ÄÚ´æ¹þÏ£±íÖУ¬Á½¸ö cost ¶¼µÈÓÚ 3.34£¬ÒòΪÊÇÔÚɨÃèÍêËùÓÐÊý¾ÝºóÒ»´ÎÐÔ¼ÆËã²¢´æÈë¹þÏ£±í¡£½ÓÏÂÀ´É¨Ãè departments ²¢ÇÒ¸ù¾Ý department_id ¼ÆËã¹þÏ£Öµ£¬È»ºóºÍÇ°ÃæµÄ¹þÏ£±í½øÐÐÆ¥Å䣨d.department_id = e.department_id£©¡£×îÉÏÃæµÄÒ»ÐбíÃ÷Êý¾Ý¿â²ÉÓõÄÊÇ Hash Join ʵÏÖÁ¬½Ó²Ù×÷¡£
¡¡¡¡PostgreSQL ÖеÄEXPLAINÒ²¿ÉÒÔʹÓà ANALYZE Ñ¡ÏîÏÔʾÓï¾äµÄʵ¼ÊÔËÐÐʱ¼äºÍ¸ü¶àÐÅÏ¢£º
EXPLAIN ANALYZE
SELECT e.first_name,e.last_name,e.salary,d.department_name
FROM employees e
JOIN departments d ON (e.department_id = d.department_id)
WHERE e.salary > 15000;
QUERY PLAN                                                                                                      |
----------------------------------------------------------------------------------------------------------------|
Hash Join  (cost=3.38..4.84 rows=3 width=29) (actual time=0.347..0.382 rows=3 loops=1)                          |
Hash Cond: (d.department_id = e.department_id)                                                                |
->  Seq Scan on departments d  (cost=0.00..1.27 rows=27 width=15) (actual time=0.020..0.037 rows=27 loops=1)  |
->  Hash  (cost=3.34..3.34 rows=3 width=22) (actual time=0.291..0.292 rows=3 loops=1)                         |
Buckets: 1024  Batches: 1  Memory Usage: 9kB                                                            |
->  Seq Scan on employees e  (cost=0.00..3.34 rows=3 width=22) (actual time=0.034..0.280 rows=3 loops=1)|
Filter: (salary > '15000'::numeric)                                                               |
Rows Removed by Filter: 104                                                                       |
Planning Time: 1.053 ms                                                                                         |
Execution Time: 0.553 ms                                                                                     |
¡¡¡¡EXPLAIN ANALYZEͨ¹ýÖ´ÐÐÓï¾ä»ñµÃÁ˸ü¶àµÄÐÅÏ¢¡£ÆäÖУ¬actual time ÊÇÿ´Îµü´úʵ¼Ê»¨·ÑµÄƽ¾ùʱ¼ä£¨ms£©£¬Ò²·ÖΪÆô¶¯Ê±¼äºÍÍê³Éʱ¼ä£»loops ±íʾµü´ú´ÎÊý£»Hash ²Ù×÷»¹»áÏÔʾͰÊý£¨Buckets£©¡¢·ÖÅúÊýÁ¿£¨Batches£©ÒÔ¼°Õ¼ÓõÄÄڴ棨Memory Usage£©£¬Batches ´óÓÚ 1 Òâζ×ÅÐèҪʹÓõ½´ÅÅ̵ÄÁÙʱ´æ´¢£»Planning Time ÊÇÉú³ÉÖ´Ðмƻ®µÄʱ¼ä£»Execution Time ÊÇÖ´ÐÐÓï¾äµÄʵ¼Êʱ¼ä£¬²»°üÀ¨ Planning Time¡£
¡¡¡¡¹ØÓÚ PostgreSQL µÄÖ´Ðмƻ®ºÍÐÔÄÜÓÅ»¯£¬¿ÉÒԲο¼ PostgreSQL ¹Ù·½ÎĵµÐÔÄÜÌáʾ£¨https://www.postgresql.org/docs/12/performance-tips.html£©¡£
¡¡¡¡5¡¢SQLite Ö´Ðмƻ®
¡¡¡¡SQLite Ò²ÌṩÁËEXPLAIN QUERY PLANÃüÁÓÃÓÚ»ñÈ¡ SQL Óï¾äµÄÖ´Ðмƻ®£º
sqlite> EXPLAIN QUERY PLAN
...> SELECT e.first_name,e.last_name,e.salary,d.department_name
...>   FROM employees e
...>   JOIN departments d ON (e.department_id = d.department_id)
...>  WHERE e.salary > 15000;
QUERY PLAN
|--SCAN TABLE employees AS e
`--SEARCH TABLE departments AS d USING INTEGER PRIMARY KEY (rowid=?)
¡¡¡¡SQLite ÖеÄEXPLAIN QUERY PLANÖ§³Ö SELECT¡¢INSERT¡¢UPDATE¡¢DELETE µÈÓï¾ä¡£
¡¡¡¡SQLite Ö´Ðмƻ®Í¬Ñù°´ÕÕËõ½øÀ´ÏÔʾ£¬Ëõ½øÔ½¶àµÄÔ½ÏÈÖ´ÐУ¬Í¬ÑùËõ½øµÄ´ÓÉÏÖÁÏÂÖ´ÐС£ÒÔÉÏʾÀýÏÈɨÃè employees ±í£¬È»ºóÕë¶Ô¸Ã½á¹ûÒÀ´Îͨ¹ýÖ÷¼ü²éÕÒ departments ÖеÄÊý¾Ý¡£SQLite Ö»Ö§³ÖÒ»ÖÖÁ¬½ÓʵÏÖ£¬Ò²¾ÍÊÇ nested loops join¡£
¡¡¡¡ÁíÍ⣬SQLite Öеļòµ¥EXPLAINÒ²¿ÉÒÔÓÃÓÚÏÔʾִÐиÃÓï¾äµÄÐéÄâ»úÖ¸ÁîÐòÁУº
sqlite> EXPLAIN
...> SELECT e.first_name,e.last_name,e.salary,d.department_name
...>   FROM employees e
...>   JOIN departments d ON (e.department_id = d.department_id)
...>  WHERE e.salary > 15000;
addr  opcode         p1    p2    p3    p4             p5  comment
----  -------------  ----  ----  ----  -------------  --  -------------
0     Init           0     15    0                    00  Start at 15
1     OpenRead       0     5     0     11             00  root=5 iDb=0; employees
2     OpenRead       1     2     0     2              00  root=2 iDb=0; departments
3     Rewind         0     14    0                    00
4       Column         0     7     1                    00  r[1]=employees.salary
5       Le             2     13    1     (BINARY)       53  if r[1]<=r[2] goto 13
6       Column         0     10    3                    00  r[3]=employees.department_id
7       SeekRowid      1     13    3                    00  intkey=r[3]
8       Column         0     1     4                    00  r[4]=employees.first_name
9       Column         0     2     5                    00  r[5]=employees.last_name
10      Column         0     7     6                    00  r[6]=employees.salary
11      Column         1     1     7                    00  r[7]=departments.department_name
12      ResultRow      4     4     0                    00  output=r[4..7]
13    Next           0     4     0                    01
14    Halt           0     0     0                    00
15    Transaction    0     0     8     0              01  usesStmtJournal=0
16    Integer        15000  2     0                    00  r[2]=15000
17    Goto           0     1     0                    00
¡¡¡¡¹ØÓÚ SQLite µÄÖ´Ðмƻ®ºÍÓÅ»¯Æ÷Ïà¹ØÐÅÏ¢£¬¿ÉÒԲο¼ SQLite ¹Ù·½Îĵµ½âÊͲéѯ¼Æ»®¡£

      ±¾ÎÄÄÚÈݲ»ÓÃÓÚÉÌҵĿµÄ£¬ÈçÉ漰֪ʶ²úȨÎÊÌ⣬ÇëȨÀûÈËÁªÏµ²©Îª·åС±à(021-64471599-8017)£¬ÎÒÃǽ«Á¢¼´´¦Àí¡£
Èí¼þ¿ª·¢
µ±Ç°Ã»ÓÐÆÀÂÛµã»÷·¢±íÆÀÂÛ

Ïà¹ØÔĶÁ