【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--

posted @   逆火狂飙  阅读(697)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
历史上的今天:
2019-09-07 【Java/数学/指数函数】使用牛顿中值法求方程2^x=5-x的近似根
2017-09-07 【Canvas与艺术】把美国队长的圆盾改成海鲜店的广告牌
2017-09-07 【Canvas与标志】无底色双层安布雷拉伞公司标志
2017-09-07 转帖:励建书:数学有助于大众理性思维的培养
2017-09-07 【Canvas与化学】圆角方形白底红绿蓝同心三色环碳元素图标
2017-09-07 【Canvas技法】八扇页正方形(拓扑结构基础案例)
2017-09-07 【Canvas与艺术】绘制等速螺线表盘
生当作人杰 死亦为鬼雄 至今思项羽 不肯过江东
点击右上角即可分享
微信分享提示