【Oracle】单表先自行筛选后连接是SQL优化的必要步骤

在微信公众号“我是程序汪”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--

原文地址:https://www.cnblogs.com/heyang78/p/15239787.html