【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--
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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与艺术】绘制等速螺线表盘