在微信公众号“我是程序汪”21年9月7日的文章“一张900w的数据表,16s执行的SQL优化到300ms”中,作者讲述了一种变常规查询到右连的优化方法,但他用的是MySQL数据库,今天我就来用本机的Oracle数据库来试试。
前提:准备一个千万级大表,可以参考 https://www.cnblogs.com/heyang78/p/15239683.html 创建,下文中用到的是一千六百万大表。
常规SQL:
select * from emp_final a
where a.name like 'AK%' and
a.age between 30 and 50 and
a.salary>20000 and a.salary<30000 and
rownum<10;
这句就是从符合筛选条件的记录里找出前十条。
执行完耗时3.36秒,这个仅为实现需求未经雕琢的SQL比作者的MySQL数据库强四倍,Oracle受追捧不是没有原因的。
优化后先筛选后直连的SQL:
select a.* from emp_final a,(select id from emp_final where name like 'AK%' and age between 30 and 50 and salary>20000 and salary<30000 and rownum<10) b
where a.id=b.id
执行完耗时0.26秒,这个和作者优化后差不多,但我用的是一千六百万的表,接近作者九百万的表两倍了,再一次证明了Oracle的强大。
两句SQL比较,大家就知道先筛选单表数据再做连接的好处了,就本例而言效率有十倍的提升。
左联SQL:
select b.* from (select id from emp_final where name like 'AK%' and age between 30 and 50 and salary>20000 and salary<30000 and rownum<10) a left join emp_final b
on a.id=b.id
执行完耗时0.35秒,这个稍长点。
再换一种SQL:
select * from emp_final where id in (select id from emp_final where name like 'AK%' and age between 30 and 50 and salary>20000 and salary<30000 and rownum<10)
耗时0.31秒,这个就比左联强一点。
其实直连、左联、半联结都是秒出,考虑到优化器和缓存,它们的性能在伯仲之间,不必厚彼薄此。
SQL优化的核心思想就是及时抛却无用记录和无关列,此思想在本例得到了一定程度的体现。
上文用到的执行结果(为简便有删减):
SQL> select a.* from emp_final a,(select id from emp_final where name like 'AK%' and age between 30 and 50 and salary>20000 and salary<30000 and rownum<10) b 2 where a.id=b.id; ID NAME AGE SALARY ---------- ---------------------------------------- ---------- ---------- CREATE_TIME --------------------------------------------------------------------------- 4208001 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208002 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208003 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 ID NAME AGE SALARY ---------- ---------------------------------------- ---------- ---------- CREATE_TIME --------------------------------------------------------------------------- 4208004 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208005 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208006 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 ID NAME AGE SALARY ---------- ---------------------------------------- ---------- ---------- CREATE_TIME --------------------------------------------------------------------------- 4208007 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208008 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208009 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 已选择9行。 已用时间: 00: 00: 00.23 SQL> select b.* from (select id from emp_final where name like 'AK%' and age between 30 and 50 and salary>20000 and salary<30000 and rownum<10) a left join emp_final b 2 on a.id=b.id; ID NAME AGE SALARY ---------- ---------------------------------------- ---------- ---------- CREATE_TIME --------------------------------------------------------------------------- 4208001 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208002 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208003 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 ID NAME AGE SALARY ---------- ---------------------------------------- ---------- ---------- CREATE_TIME --------------------------------------------------------------------------- 4208004 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208005 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208006 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 ID NAME AGE SALARY ---------- ---------------------------------------- ---------- ---------- CREATE_TIME --------------------------------------------------------------------------- 4208007 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208008 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208009 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 已选择9行。 已用时间: 00: 00: 00.21 SQL> select * from emp_final where id in (select id from emp_final where name like 'AK%' and age between 30 and 50 and salary>20000 and salary<30000 and rownum<10); ID NAME AGE SALARY ---------- ---------------------------------------- ---------- ---------- CREATE_TIME --------------------------------------------------------------------------- 4208004 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208007 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208009 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 ID NAME AGE SALARY ---------- ---------------------------------------- ---------- ---------- CREATE_TIME --------------------------------------------------------------------------- 4208002 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208003 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208001 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 ID NAME AGE SALARY ---------- ---------------------------------------- ---------- ---------- CREATE_TIME --------------------------------------------------------------------------- 4208005 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208006 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 4208008 AKUHVUGWHQ 41 29372 07-9月 -21 06.32.42.000000 下午 已选择9行。 已用时间: 00: 00: 00.21 SQL>
--END--