执行计划(execution plan,也叫查询计划或者解释计划)是数据库执行 SQL 语句的具体步骤,例如通过索引还是全表扫描访问表中的数据,连接查询的实现方式和连接的顺序等。如果 SQL 语句性能不够理想,我们首先应该查看它的执行计划。本文使用的示例表结构如下:
示例数据:
INSERT INTO departments VALUES ( 10 , 'Administration' , 200 , 1700 ); INSERT INTO departments VALUES ( 20 , 'Marketing' , 201 , 1800 ); INSERT INTO departments VALUES ( 30 , 'Purchasing' , 114 , 1700 ); INSERT INTO departments VALUES ( 40 , 'Human Resources' , 203 , 2400 ); INSERT INTO departments VALUES ( 50 , 'Shipping' , 121 , 1500 ); INSERT INTO departments VALUES ( 60 , 'IT' , 103 , 1400 ); INSERT INTO departments VALUES ( 70 , 'Public Relations' , 204 , 2700 ); INSERT INTO departments VALUES ( 80 , 'Sales' , 145 , 2500 ); INSERT INTO departments VALUES ( 90 , 'Executive' , 100 , 1700 ); INSERT INTO departments VALUES ( 100 , 'Finance' , 108 , 1700 ); INSERT INTO departments VALUES ( 110 , 'Accounting' , 205 , 1700 ); INSERT INTO departments VALUES ( 120 , 'Treasury' , NULL , 1700 ); INSERT INTO departments VALUES ( 130 , 'Corporate Tax' , NULL , 1700 ); INSERT INTO departments VALUES ( 140 , 'Control And Credit' , NULL , 1700 ); INSERT INTO departments VALUES ( 150 , 'Shareholder Services' , NULL , 1700 ); INSERT INTO departments VALUES ( 160 , 'Benefits' , NULL , 1700 ); INSERT INTO departments VALUES ( 170 , 'Manufacturing' , NULL , 1700 ); INSERT INTO departments VALUES ( 180 , 'Construction' , NULL , 1700 ); INSERT INTO departments VALUES ( 190 , 'Contracting' , NULL , 1700 ); INSERT INTO departments VALUES ( 200 , 'Operations' , NULL , 1700 ); INSERT INTO departments VALUES ( 210 , 'IT Support' , NULL , 1700 ); INSERT INTO departments VALUES ( 220 , 'NOC' , NULL , 1700 ); INSERT INTO departments VALUES ( 230 , 'IT Helpdesk' , NULL , 1700 ); INSERT INTO departments VALUES ( 240 , 'Government Sales' , NULL , 1700 ); INSERT INTO departments VALUES ( 250 , 'Retail Sales' , NULL , 1700 ); INSERT INTO departments VALUES ( 260 , 'Recruiting' , NULL , 1700 ); INSERT INTO departments VALUES ( 270 , 'Payroll' , NULL , 1700 ); INSERT INTO jobs VALUES ( 'AD_PRES' , 'President' , 20080 , 40000 ); INSERT INTO jobs VALUES ( 'AD_VP' , 'Administration Vice President' , 15000 , 30000 ); INSERT INTO jobs VALUES ( 'AD_ASST' , 'Administration Assistant' , 3000 , 6000 ); INSERT INTO jobs VALUES ( 'FI_MGR' , 'Finance Manager' , 8200 , 16000 ); INSERT INTO jobs VALUES ( 'FI_ACCOUNT' , 'Accountant' , 4200 , 9000 ); INSERT INTO jobs VALUES ( 'AC_MGR' , 'Accounting Manager' , 8200 , 16000 ); INSERT INTO jobs VALUES ( 'AC_ACCOUNT' , 'Public Accountant' , 4200 , 9000 ); INSERT INTO jobs VALUES ( 'SA_MAN' , 'Sales Manager' , 10000 , 20080 ); INSERT INTO jobs VALUES ( 'SA_REP' , 'Sales Representative' , 6000 , 12008 ); INSERT INTO jobs VALUES ( 'PU_MAN' , 'Purchasing Manager' , 8000 , 15000 ); INSERT INTO jobs VALUES ( 'PU_CLERK' , 'Purchasing Clerk' , 2500 , 5500 ); INSERT INTO jobs VALUES ( 'ST_MAN' , 'Stock Manager' , 5500 , 8500 ); INSERT INTO jobs VALUES ( 'ST_CLERK' , 'Stock Clerk' , 2008 , 5000 ); INSERT INTO jobs VALUES ( 'SH_CLERK' , 'Shipping Clerk' , 2500 , 5500 ); INSERT INTO jobs VALUES ( 'IT_PROG' , 'Programmer' , 4000 , 10000 ); INSERT INTO jobs VALUES ( 'MK_MAN' , 'Marketing Manager' , 9000 , 15000 ); INSERT INTO jobs VALUES ( 'MK_REP' , 'Marketing Representative' , 4000 , 9000 ); INSERT INTO jobs VALUES ( 'HR_REP' , 'Human Resources Representative' , 4000 , 9000 ); INSERT INTO jobs VALUES ( 'PR_REP' , 'Public Relations Representative' , 4500 , 10500 ); INSERT INTO employees VALUES ( 100 , 'Steven' , 'King' , 'SKING' , '515.123.4567' , DATE('2003-06-17') , 'AD_PRES' , 24000 , NULL , NULL , 90 ); INSERT INTO employees VALUES ( 101 , 'Neena' , 'Kochhar' , 'NKOCHHAR' , '515.123.4568' , DATE('2005-09-21') , 'AD_VP' , 17000 , NULL , 100 , 90 ); INSERT INTO employees VALUES ( 102 , 'Lex' , 'De Haan' , 'LDEHAAN' , '515.123.4569' , DATE('2001-01-13') , 'AD_VP' , 17000 , NULL , 100 , 90 ); INSERT INTO employees VALUES ( 103 , 'Alexander' , 'Hunold' , 'AHUNOLD' , '590.423.4567' , DATE('2006-01-03') , 'IT_PROG' , 9000 , NULL , 102 , 60 ); INSERT INTO employees VALUES ( 104 , 'Bruce' , 'Ernst' , 'BERNST' , '590.423.4568' , DATE('2007-05-21') , 'IT_PROG' , 6000 , NULL , 103 , 60 ); INSERT INTO employees VALUES ( 105 , 'David' , 'Austin' , 'DAUSTIN' , '590.423.4569' , DATE('2005-06-25') , 'IT_PROG' , 4800 , NULL , 103 , 60 ); INSERT INTO employees VALUES ( 106 , 'Valli' , 'Pataballa' , 'VPATABAL' , '590.423.4560' , DATE('2006-02-05') , 'IT_PROG' , 4800 , NULL , 103 , 60 ); INSERT INTO employees VALUES ( 107 , 'Diana' , 'Lorentz' , 'DLORENTZ' , '590.423.5567' , DATE('2007-02-07') , 'IT_PROG' , 4200 , NULL , 103 , 60 ); INSERT INTO employees VALUES ( 108 , 'Nancy' , 'Greenberg' , 'NGREENBE' , '515.124.4569' , DATE('2002-08-17') , 'FI_MGR' , 12008 , NULL , 101 , 100 ); INSERT INTO employees VALUES ( 109 , 'Daniel' , 'Faviet' , 'DFAVIET' , '515.124.4169' , DATE('2002-08-16') , 'FI_ACCOUNT' , 9000 , NULL , 108 , 100 ); INSERT INTO employees VALUES ( 110 , 'John' , 'Chen' , 'JCHEN' , '515.124.4269' , DATE('2005-09-28') , 'FI_ACCOUNT' , 8200 , NULL , 108 , 100 ); INSERT INTO employees VALUES ( 111 , 'Ismael' , 'Sciarra' , 'ISCIARRA' , '515.124.4369' , DATE('2005-09-30') , 'FI_ACCOUNT' , 7700 , NULL , 108 , 100 ); INSERT INTO employees VALUES ( 112 , 'Jose Manuel' , 'Urman' , 'JMURMAN' , '515.124.4469' , DATE('2006-03-07') , 'FI_ACCOUNT' , 7800 , NULL , 108 , 100 ); INSERT INTO employees VALUES ( 113 , 'Luis' , 'Popp' , 'LPOPP' , '515.124.4567' , DATE('2007-12-07') , 'FI_ACCOUNT' , 6900 , NULL , 108 , 100 ); INSERT INTO employees VALUES ( 114 , 'Den' , 'Raphaely' , 'DRAPHEAL' , '515.127.4561' , DATE('2002-12-07') , 'PU_MAN' , 11000 , NULL , 100 , 30 ); INSERT INTO employees VALUES ( 115 , 'Alexander' , 'Khoo' , 'AKHOO' , '515.127.4562' , DATE('2003-05-18') , 'PU_CLERK' , 3100 , NULL , 114 , 30 ); INSERT INTO employees VALUES ( 116 , 'Shelli' , 'Baida' , 'SBAIDA' , '515.127.4563' , DATE('2005-12-24') , 'PU_CLERK' , 2900 , NULL , 114 , 30 ); INSERT INTO employees VALUES ( 117 , 'Sigal' , 'Tobias' , 'STOBIAS' , '515.127.4564' , DATE('2005-07-24') , 'PU_CLERK' , 2800 , NULL , 114 , 30 ); INSERT INTO employees VALUES ( 118 , 'Guy' , 'Himuro' , 'GHIMURO' , '515.127.4565' , DATE('2006-11-15') , 'PU_CLERK' , 2600 , NULL , 114 , 30 ); INSERT INTO employees VALUES ( 119 , 'Karen' , 'Colmenares' , 'KCOLMENA' , '515.127.4566' , DATE('2007-08-10') , 'PU_CLERK' , 2500 , NULL , 114 , 30 ); INSERT INTO employees VALUES ( 120 , 'Matthew' , 'Weiss' , 'MWEISS' , '650.123.1234' , DATE('2004-07-18') , 'ST_MAN' , 8000 , NULL , 100 , 50 ); INSERT INTO employees VALUES ( 121 , 'Adam' , 'Fripp' , 'AFRIPP' , '650.123.2234' , DATE('2005-04-10') , 'ST_MAN' , 8200 , NULL , 100 , 50 ); INSERT INTO employees VALUES ( 122 , 'Payam' , 'Kaufling' , 'PKAUFLIN' , '650.123.3234' , DATE('2003-05-01') , 'ST_MAN' , 7900 , NULL , 100 , 50 ); INSERT INTO employees VALUES ( 123 , 'Shanta' , 'Vollman' , 'SVOLLMAN' , '650.123.4234' , DATE('2005-10-10') , 'ST_MAN' , 6500 , NULL , 100 , 50 ); INSERT INTO employees VALUES ( 124 , 'Kevin' , 'Mourgos' , 'KMOURGOS' , '650.123.5234' , DATE('2007-11-16') , 'ST_MAN' , 5800 , NULL , 100 , 50 ); INSERT INTO employees VALUES ( 125 , 'Julia' , 'Nayer' , 'JNAYER' , '650.124.1214' , DATE('2005-07-16') , 'ST_CLERK' , 3200 , NULL , 120 , 50 ); INSERT INTO employees VALUES ( 126 , 'Irene' , 'Mikkilineni' , 'IMIKKILI' , '650.124.1224' , DATE('2006-09-28') , 'ST_CLERK' , 2700 , NULL , 120 , 50 ); INSERT INTO employees VALUES ( 127 , 'James' , 'Landry' , 'JLANDRY' , '650.124.1334' , DATE('2007-01-14') , 'ST_CLERK' , 2400 , NULL , 120 , 50 ); INSERT INTO employees VALUES ( 128 , 'Steven' , 'Markle' , 'SMARKLE' , '650.124.1434' , DATE('2008-03-08') , 'ST_CLERK' , 2200 , NULL , 120 , 50 ); INSERT INTO employees VALUES ( 129 , 'Laura' , 'Bissot' , 'LBISSOT' , '650.124.5234' , DATE('2005-08-20') , 'ST_CLERK' , 3300 , NULL , 121 , 50 ); INSERT INTO employees VALUES ( 130 , 'Mozhe' , 'Atkinson' , 'MATKINSO' , '650.124.6234' , DATE('2005-10-30') , 'ST_CLERK' , 2800 , NULL , 121 , 50 ); INSERT INTO employees VALUES ( 131 , 'James' , 'Marlow' , 'JAMRLOW' , '650.124.7234' , DATE('2005-02-16') , 'ST_CLERK' , 2500 , NULL , 121 , 50 ); INSERT INTO employees VALUES ( 132 , 'TJ' , 'Olson' , 'TJOLSON' , '650.124.8234' , DATE('2007-04-10') , 'ST_CLERK' , 2100 , NULL , 121 , 50 ); INSERT INTO employees VALUES ( 133 , 'Jason' , 'Mallin' , 'JMALLIN' , '650.127.1934' , DATE('2004-06-14') , 'ST_CLERK' , 3300 , NULL , 122 , 50 ); INSERT INTO employees VALUES ( 134 , 'Michael' , 'Rogers' , 'MROGERS' , '650.127.1834' , DATE('2006-08-26') , 'ST_CLERK' , 2900 , NULL , 122 , 50 ); INSERT INTO employees VALUES ( 135 , 'Ki' , 'Gee' , 'KGEE' , '650.127.1734' , DATE('2007-12-12') , 'ST_CLERK' , 2400 , NULL , 122 , 50 ); INSERT INTO employees VALUES ( 136 , 'Hazel' , 'Philtanker' , 'HPHILTAN' , '650.127.1634' , DATE('2008-02-06') , 'ST_CLERK' , 2200 , NULL , 122 , 50 ); INSERT INTO employees VALUES ( 137 , 'Renske' , 'Ladwig' , 'RLADWIG' , '650.121.1234' , DATE('2003-07-14') , 'ST_CLERK' , 3600 , NULL , 123 , 50 ); INSERT INTO employees VALUES ( 138 , 'Stephen' , 'Stiles' , 'SSTILES' , '650.121.2034' , DATE('2005-10-26') , 'ST_CLERK' , 3200 , NULL , 123 , 50 ); INSERT INTO employees VALUES ( 139 , 'John' , 'Seo' , 'JSEO' , '650.121.2019' , DATE('2006-02-12') , 'ST_CLERK' , 2700 , NULL , 123 , 50 ); INSERT INTO employees VALUES ( 140 , 'Joshua' , 'Patel' , 'JPATEL' , '650.121.1834' , DATE('2006-04-06') , 'ST_CLERK' , 2500 , NULL , 123 , 50 ); INSERT INTO employees VALUES ( 141 , 'Trenna' , 'Rajs' , 'TRAJS' , '650.121.8009' , DATE('2003-10-17') , 'ST_CLERK' , 3500 , NULL , 124 , 50 ); INSERT INTO employees VALUES ( 142 , 'Curtis' , 'Davies' , 'CDAVIES' , '650.121.2994' , DATE('2005-01-29') , 'ST_CLERK' , 3100 , NULL , 124 , 50 ); INSERT INTO employees VALUES ( 143 , 'Randall' , 'Matos' , 'RMATOS' , '650.121.2874' , DATE('2006-03-15') , 'ST_CLERK' , 2600 , NULL , 124 , 50 ); INSERT INTO employees VALUES ( 144 , 'Peter' , 'Vargas' , 'PVARGAS' , '650.121.2004' , DATE('2006-07-09') , 'ST_CLERK' , 2500 , NULL , 124 , 50 ); INSERT INTO employees VALUES ( 145 , 'John' , 'Russell' , 'JRUSSEL' , '011.44.1344.429268' , DATE('2004-10-01') , 'SA_MAN' , 14000 , .4 , 100 , 80 ); INSERT INTO employees VALUES ( 146 , 'Karen' , 'Partners' , 'KPARTNER' , '011.44.1344.467268' , DATE('2005-01-05') , 'SA_MAN' , 13500 , .3 , 100 , 80 ); INSERT INTO employees VALUES ( 147 , 'Alberto' , 'Errazuriz' , 'AERRAZUR' , '011.44.1344.429278' , DATE('2005-03-10') , 'SA_MAN' , 12000 , .3 , 100 , 80 ); INSERT INTO employees VALUES ( 148 , 'Gerald' , 'Cambrault' , 'GCAMBRAU' , '011.44.1344.619268' , DATE('2007-10-15') , 'SA_MAN' , 11000 , .3 , 100 , 80 ); INSERT INTO employees VALUES ( 149 , 'Eleni' , 'Zlotkey' , 'EZLOTKEY' , '011.44.1344.429018' , DATE('2008-01-29') , 'SA_MAN' , 10500 , .2 , 100 , 80 ); INSERT INTO employees VALUES ( 150 , 'Peter' , 'Tucker' , 'PTUCKER' , '011.44.1344.129268' , DATE('2005-01-30') , 'SA_REP' , 10000 , .3 , 145 , 80 ); INSERT INTO employees VALUES ( 151 , 'David' , 'Bernstein' , 'DBERNSTE' , '011.44.1344.345268' , DATE('2005-03-24') , 'SA_REP' , 9500 , .25 , 145 , 80 ); INSERT INTO employees VALUES ( 152 , 'Peter' , 'Hall' , 'PHALL' , '011.44.1344.478968' , DATE('2005-08-20') , 'SA_REP' , 9000 , .25 , 145 , 80 ); INSERT INTO employees VALUES ( 153 , 'Christopher' , 'Olsen' , 'COLSEN' , '011.44.1344.498718' , DATE('2006-03-30') , 'SA_REP' , 8000 , .2 , 145 , 80 ); INSERT INTO employees VALUES ( 154 , 'Nanette' , 'Cambrault' , 'NCAMBRAU' , '011.44.1344.987668' , DATE('2006-12-09') , 'SA_REP' , 7500 , .2 , 145 , 80 ); INSERT INTO employees VALUES ( 155 , 'Oliver' , 'Tuvault' , 'OTUVAULT' , '011.44.1344.486508' , DATE('2007-11-23') , 'SA_REP' , 7000 , .15 , 145 , 80 ); INSERT INTO employees VALUES ( 156 , 'Janette' , 'King' , 'JKING' , '011.44.1345.429268' , DATE('2004-01-30') , 'SA_REP' , 10000 , .35 , 146 , 80 ); INSERT INTO employees VALUES ( 157 , 'Patrick' , 'Sully' , 'PSULLY' , '011.44.1345.929268' , DATE('2004-03-04') , 'SA_REP' , 9500 , .35 , 146 , 80 ); INSERT INTO employees VALUES ( 158 , 'Allan' , 'McEwen' , 'AMCEWEN' , '011.44.1345.829268' , DATE('2004-08-01') , 'SA_REP' , 9000 , .35 , 146 , 80 ); INSERT INTO employees VALUES ( 159 , 'Lindsey' , 'Smith' , 'LSMITH' , '011.44.1345.729268' , DATE('2005-03-10') , 'SA_REP' , 8000 , .3 , 146 , 80 ); INSERT INTO employees VALUES ( 160 , 'Louise' , 'Doran' , 'LDORAN' , '011.44.1345.629268' , DATE('2005-12-15') , 'SA_REP' , 7500 , .3 , 146 , 80 ); INSERT INTO employees VALUES ( 161 , 'Sarath' , 'Sewall' , 'SSEWALL' , '011.44.1345.529268' , DATE('2006-11-03') , 'SA_REP' , 7000 , .25 , 146 , 80 ); INSERT INTO employees VALUES ( 162 , 'Clara' , 'Vishney' , 'CVISHNEY' , '011.44.1346.129268' , DATE('2005-11-11') , 'SA_REP' , 10500 , .25 , 147 , 80 ); INSERT INTO employees VALUES ( 163 , 'Danielle' , 'Greene' , 'DGREENE' , '011.44.1346.229268' , DATE('2007-03-19') , 'SA_REP' , 9500 , .15 , 147 , 80 ); INSERT INTO employees VALUES ( 164 , 'Mattea' , 'Marvins' , 'MMARVINS' , '011.44.1346.329268' , DATE('2008-01-24') , 'SA_REP' , 7200 , .10 , 147 , 80 ); INSERT INTO employees VALUES ( 165 , 'David' , 'Lee' , 'DLEE' , '011.44.1346.529268' , DATE('2008-02-23') , 'SA_REP' , 6800 , .1 , 147 , 80 ); INSERT INTO employees VALUES ( 166 , 'Sundar' , 'Ande' , 'SANDE' , '011.44.1346.629268' , DATE('2008-03-24') , 'SA_REP' , 6400 , .10 , 147 , 80 ); INSERT INTO employees VALUES ( 167 , 'Amit' , 'Banda' , 'ABANDA' , '011.44.1346.729268' , DATE('2008-04-21') , 'SA_REP' , 6200 , .10 , 147 , 80 ); INSERT INTO employees VALUES ( 168 , 'Lisa' , 'Ozer' , 'LOZER' , '011.44.1343.929268' , DATE('2005-03-11') , 'SA_REP' , 11500 , .25 , 148 , 80 ); INSERT INTO employees VALUES ( 169 , 'Harrison' , 'Bloom' , 'HBLOOM' , '011.44.1343.829268' , DATE('2006-03-23') , 'SA_REP' , 10000 , .20 , 148 , 80 ); INSERT INTO employees VALUES ( 170 , 'Tayler' , 'Fox' , 'TFOX' , '011.44.1343.729268' , DATE('2006-01-24') , 'SA_REP' , 9600 , .20 , 148 , 80 ); INSERT INTO employees VALUES ( 171 , 'William' , 'Smith' , 'WSMITH' , '011.44.1343.629268' , DATE('2007-02-23') , 'SA_REP' , 7400 , .15 , 148 , 80 ); INSERT INTO employees VALUES ( 172 , 'Elizabeth' , 'Bates' , 'EBATES' , '011.44.1343.529268' , DATE('2007-03-24') , 'SA_REP' , 7300 , .15 , 148 , 80 ); INSERT INTO employees VALUES ( 173 , 'Sundita' , 'Kumar' , 'SKUMAR' , '011.44.1343.329268' , DATE('2008-04-21') , 'SA_REP' , 6100 , .10 , 148 , 80 ); INSERT INTO employees VALUES ( 174 , 'Ellen' , 'Abel' , 'EABEL' , '011.44.1644.429267' , DATE('2004-05-11') , 'SA_REP' , 11000 , .30 , 149 , 80 ); INSERT INTO employees VALUES ( 175 , 'Alyssa' , 'Hutton' , 'AHUTTON' , '011.44.1644.429266' , DATE('2005-03-19') , 'SA_REP' , 8800 , .25 , 149 , 80 ); INSERT INTO employees VALUES ( 176 , 'Jonathon' , 'Taylor' , 'JTAYLOR' , '011.44.1644.429265' , DATE('2006-03-24') , 'SA_REP' , 8600 , .20 , 149 , 80 ); INSERT INTO employees VALUES ( 177 , 'Jack' , 'Livingston' , 'JLIVINGS' , '011.44.1644.429264' , DATE('2006-04-23') , 'SA_REP' , 8400 , .20 , 149 , 80 ); INSERT INTO employees VALUES ( 178 , 'Kimberely' , 'Grant' , 'KGRANT' , '011.44.1644.429263' , DATE('2007-05-24') , 'SA_REP' , 7000 , .15 , 149 , NULL ); INSERT INTO employees VALUES ( 179 , 'Charles' , 'Johnson' , 'CJOHNSON' , '011.44.1644.429262' , DATE('2008-01-04') , 'SA_REP' , 6200 , .10 , 149 , 80 ); INSERT INTO employees VALUES ( 180 , 'Winston' , 'Taylor' , 'WTAYLOR' , '650.507.9876' , DATE('2006-01-24') , 'SH_CLERK' , 3200 , NULL , 120 , 50 ); INSERT INTO employees VALUES ( 181 , 'Jean' , 'Fleaur' , 'JFLEAUR' , '650.507.9877' , DATE('2006-02-23') , 'SH_CLERK' , 3100 , NULL , 120 , 50 ); INSERT INTO employees VALUES ( 182 , 'Martha' , 'Sullivan' , 'MSULLIVA' , '650.507.9878' , DATE('2007-06-21') , 'SH_CLERK' , 2500 , NULL , 120 , 50 ); INSERT INTO employees VALUES ( 183 , 'Girard' , 'Geoni' , 'GGEONI' , '650.507.9879' , DATE('2008-02-03') , 'SH_CLERK' , 2800 , NULL , 120 , 50 ); INSERT INTO employees VALUES ( 184 , 'Nandita' , 'Sarchand' , 'NSARCHAN' , '650.509.1876' , DATE('2004-01-27') , 'SH_CLERK' , 4200 , NULL , 121 , 50 ); INSERT INTO employees VALUES ( 185 , 'Alexis' , 'Bull' , 'ABULL' , '650.509.2876' , DATE('2005-02-20') , 'SH_CLERK' , 4100 , NULL , 121 , 50 ); INSERT INTO employees VALUES ( 186 , 'Julia' , 'Dellinger' , 'JDELLING' , '650.509.3876' , DATE('2006-06-24') , 'SH_CLERK' , 3400 , NULL , 121 , 50 ); INSERT INTO employees VALUES ( 187 , 'Anthony' , 'Cabrio' , 'ACABRIO' , '650.509.4876' , DATE('2007-02-07') , 'SH_CLERK' , 3000 , NULL , 121 , 50 ); INSERT INTO employees VALUES ( 188 , 'Kelly' , 'Chung' , 'KCHUNG' , '650.505.1876' , DATE('2005-06-14') , 'SH_CLERK' , 3800 , NULL , 122 , 50 ); INSERT INTO employees VALUES ( 189 , 'Jennifer' , 'Dilly' , 'JDILLY' , '650.505.2876' , DATE('2005-08-13') , 'SH_CLERK' , 3600 , NULL , 122 , 50 ); INSERT INTO employees VALUES ( 190 , 'Timothy' , 'Gates' , 'TGATES' , '650.505.3876' , DATE('2006-07-11') , 'SH_CLERK' , 2900 , NULL , 122 , 50 ); INSERT INTO employees VALUES ( 191 , 'Randall' , 'Perkins' , 'RPERKINS' , '650.505.4876' , DATE('2007-12-19') , 'SH_CLERK' , 2500 , NULL , 122 , 50 ); INSERT INTO employees VALUES ( 192 , 'Sarah' , 'Bell' , 'SBELL' , '650.501.1876' , DATE('2004-02-04') , 'SH_CLERK' , 4000 , NULL , 123 , 50 ); INSERT INTO employees VALUES ( 193 , 'Britney' , 'Everett' , 'BEVERETT' , '650.501.2876' , DATE('2005-03-03') , 'SH_CLERK' , 3900 , NULL , 123 , 50 ); INSERT INTO employees VALUES ( 194 , 'Samuel' , 'McCain' , 'SMCCAIN' , '650.501.3876' , DATE('2006-07-01') , 'SH_CLERK' , 3200 , NULL , 123 , 50 ); INSERT INTO employees VALUES ( 195 , 'Vance' , 'Jones' , 'VJONES' , '650.501.4876' , DATE('2007-03-17') , 'SH_CLERK' , 2800 , NULL , 123 , 50 ); INSERT INTO employees VALUES ( 196 , 'Alana' , 'Walsh' , 'AWALSH' , '650.507.9811' , DATE('2006-04-24') , 'SH_CLERK' , 3100 , NULL , 124 , 50 ); INSERT INTO employees VALUES ( 197 , 'Kevin' , 'Feeney' , 'KFEENEY' , '650.507.9822' , DATE('2006-05-23') , 'SH_CLERK' , 3000 , NULL , 124 , 50 ); INSERT INTO employees VALUES ( 198 , 'Donald' , 'OConnell' , 'DOCONNEL' , '650.507.9833' , DATE('2007-06-21') , 'SH_CLERK' , 2600 , NULL , 124 , 50 ); INSERT INTO employees VALUES ( 199 , 'Douglas' , 'Grant' , 'DGRANT' , '650.507.9844' , DATE('2008-01-13') , 'SH_CLERK' , 2600 , NULL , 124 , 50 ); INSERT INTO employees VALUES ( 200 , 'Jennifer' , 'Whalen' , 'JWHALEN' , '515.123.4444' , DATE('2003-09-17') , 'AD_ASST' , 4400 , NULL , 101 , 10 ); INSERT INTO employees VALUES ( 201 , 'Michael' , 'Hartstein' , 'MHARTSTE' , '515.123.5555' , DATE('2004-02-17') , 'MK_MAN' , 13000 , NULL , 100 , 20 ); INSERT INTO employees VALUES ( 202 , 'Pat' , 'Fay' , 'PFAY' , '603.123.6666' , DATE('2005-08-17') , 'MK_REP' , 6000 , NULL , 201 , 20 ); INSERT INTO employees VALUES ( 203 , 'Susan' , 'Mavris' , 'SMAVRIS' , '515.123.7777' , DATE('2002-06-07') , 'HR_REP' , 6500 , NULL , 101 , 40 ); INSERT INTO employees VALUES ( 204 , 'Hermann' , 'Baer' , 'HBAER' , '515.123.8888' , DATE('2002-06-07') , 'PR_REP' , 10000 , NULL , 101 , 70 ); INSERT INTO employees VALUES ( 205 , 'Shelley' , 'Higgins' , 'SHIGGINS' , '515.123.8080' , DATE('2002-06-07') , 'AC_MGR' , 12008 , NULL , 101 , 110 ); INSERT INTO employees VALUES ( 206 , 'William' , 'Gietz' , 'WGIETZ' , '515.123.8181' , DATE('2002-06-07') , 'AC_ACCOUNT' , 8300 , NULL , 205 , 110 );
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 列信息:
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 表示迭代器循环的次数。
Oracle 执行计划
Oracle 中提供了多种查看执行计划的方法,可以使用以下方式:
- 使用EXPLAIN PLAN FOR命令生成并保存执行计划;
- 显示保存的执行计划。
首先,生成执行计划:
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 中的存储过程格式化显示该表中的执行计划。以下语句可以查看当前会话中的最后一个执行计划:
ELECT * 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 选择了排序合并连接的方式实现两个表的连接。