关于取表中id最大值+1的select语句,哪种效率更高?
需求:取stock表中id最大值+1,作为下一个id值。
特殊情况:考虑到表中会没有值,max(id)会返回空,因此需要用case when进行判断。
实现一:select (case max(id) is null when true then 0 else max(id)+1 end) from stock
实现二:select (case (select count(*) from stock) when 0 then 0 else max(id)+1 end) from stock
效率分析:
实现一相对于实现二不取数量,在索引的帮助下也能快速取值,因此效率应该比实现二高。
分析之验证:
(MySQL数据库)
stock表中没有数据时:
mysql> explain select (case max(id) is null when true then 0 else max(id)+1 end) from stock; +----+-------------+-------+------+---------------+------+---------+------+------+-------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------------------+ | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No matching min/max row | +----+-------------+-------+------+---------------+------+---------+------+------+-------------------------+ 1 row in set (0.00 sec) mysql> explain select (case (select count(*) from stock) when 0 then 0 else max(id)+1 end) from stock; +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------------------+ | 1 | PRIMARY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No matching min/max row | | 2 | SUBQUERY | stock | index | NULL | PRIMARY | 4 | NULL | 3749 | Using index | +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------------------+ 2 rows in set (0.05 sec)
stock表中有数据时:
mysql> select count(*) from stock; +----------+ | count(*) | +----------+ | 3768 | +----------+ 1 row in set (0.00 sec) mysql> explain select (case max(id) is null when true then 0 else max(id)+1 end) from stock; +----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+ | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away | +----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+ 1 row in set (0.00 sec) mysql> desc select (case (select count(*) from stock) when 0 then 0 else max(id)+1 end) from stock; +----+-------------+-------+-------+---------------+---------+---------+------+------+------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+------+------+------------------------------+ | 1 | PRIMARY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away | | 2 | SUBQUERY | stock | index | NULL | PRIMARY | 4 | NULL | 3696 | Using index | +----+-------------+-------+-------+---------------+---------+---------+------+------+------------------------------+ 2 rows in set (0.00 sec)
分析之验证:
oracle数据库
MySQL版的SQL不能直接在oracle里使用,因此需要改写成:
方案一:select nvl(max(id)+1,0) from stock;
方案二:select (case count(*) when 0 then 0 else max(id)+1 end) from stock
然后我模拟做了3744条记录,跑解释计划确实方案二慢.
方案一的执行计划:
SQL> select nvl(max(id)+1,0) from stock; 已用时间: 00: 00: 00.00 执行计划 ---------------------------------------------------------- Plan hash value: 1547204082 -------------------------------------------------------------------------------- ----------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------- ----------- | 0 | SELECT STATEMENT | | 1 | 13 | 2 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 13 | | | | 2 | INDEX FULL SCAN (MIN/MAX)| SYS_C0011050 | 1 | 13 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------------- ----------- Note ----- - dynamic sampling used for this statement (level=2)
方案二的执行计划:
SQL> select (case count(*) when 0 then 0 else max(id)+1 end) from stock; 已用时间: 00: 00: 00.00 执行计划 ---------------------------------------------------------- Plan hash value: 916654 -------------------------------------------------------------------------------- ------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------- ------ | 0 | SELECT STATEMENT | | 1 | 13 | 5 (0)| 00:0 0:01 | | 1 | SORT AGGREGATE | | 1 | 13 | | | | 2 | INDEX FAST FULL SCAN| SYS_C0011050 | 3744 | 48672 | 5 (0)| 00:0 0:01 | -------------------------------------------------------------------------------- ------ Note ----- - dynamic sampling used for this statement (level=2)
--2020年5月2日--
分类:
Z.MySQL.性能优化
【推荐】国内首个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)
2018-05-02 【高中数学/基本不等式】已知:a>1/3,b>1/3,且ab=2/9 求证:2/3倍根号2<=a+b<1
2015-05-02 查看Linux上MySQL版本信息
2014-05-02 CardLayout使用
2014-05-02 JCheckBox使用示例
2014-05-02 【Canvas与化学】钠元素