ITPub博客

首页 > 数据库 > 数据库开发技术 > SQL优化思想③--时间都去哪儿了

SQL优化思想③--时间都去哪儿了

原创 数据库开发技术 作者:梁敬彬 时间:2024-11-05 08:06:26 0 删除 编辑



SQL优化思想系列

SQL优化思想⓵--不优化或许是最好的优化!

SQL优化思想⓶--让SQL跑得更慢一些!


引言

SQL优化思想已经讨论了两集,不论是“ 不优化是最好的优化 ”,还是“ 变慢是更好的选择” ,都在强调做事要有 批判性思维,三思而后行。

接下来,将 探讨SQL优化本身的思路,看看如何让SQL跑得更快。毕竟, 衡量SQL快慢的标准就是 其运行时间的长短 。

围绕 “时间” 这个主题,结合超市购物 的 生活场景, 让我们步入正文,共同探寻在XXX平台优化案例中,SQL的 时间都去哪儿了 。





0



时间都去哪儿了( 等待时间 +工作时间)

Q:L老师,听说您刚解决了困扰XXX平台许久的问题,到底是怎么做的?
L:我与他们一起分析SQL执行慢时, 时间都花在哪些环节 ,然后有的放矢地进行优化,最终成功解决问题。
M:哦,时间花在哪些环节呢?不就是执行环节吗?还有其他环节?
L:前些日子你抱怨在超市购物时,买单的时间比购物过程花的时间还长。其实,这事便能解答你的疑问。
M:哦,是吗?
L:你在超市买单时,通常会在收银台 排队,这就类似于SQL的 等待时长。等到轮到你时,才能与收银员进行面对面 结算,这就类似于SQL的 工作时长。 超市买单时间=等待时间 +工作时间 。 当你抱怨买单慢时,需明确耗时主要是在等待上还是在工作上。
M:我购物时,收银台的结算倒是很快,时间主要耗在排队上,也就是等待时间太长了。

L:是的,数据库的SQL也是如此。 SQL执行时间= 等待时间+工作时间。接下来,我们就通过类比超市买单的场景,来探讨XXX平台的SQL优化案例。





1



减少CPU持有等待时间(增加收银台)

L:倘若我们期望让买单的时间加快,却发现收银柜台的队伍排得很长,顾客们等得非常焦虑,该如何是好?

W:可以考虑增加收银台的数量,假如收银台由1个变成10个, 排队等候买单的时间自然就减少了。

L:没错!有点类似数据库中的 减少CPU持有等待时长的思路,在 ZZZ平台的A模块中 ,部分SQL就是这么优化提速的,具体示例如下。
SELECT calculate_total(order_id)FROM ordersWHERE status = 'pending';

在高并发情况下,CPU持有等待时间显著增加。解决方案可以是增加CPU个数,或者采用分布式数据库架构来分担压力。

-- 在分布式架构中分片查询
SELECT calculate_total(order_id) 
FROM shard_1.orders 
WHERE status = 
'pending';
SELECT calculate_total(order_id) 
FROM shard_2.orders 
WHERE status = 
'pending';
...


通过将查询分布到多个分片,能够有效减少单个CPU的负担,从而降低持有等待时长,提高整体查询效率。

2

减少硬解析等待时间(单件再相乘)

L:排队是需要等待,其实在收银台结算交易时也存在等待时长。你购买的多个货物不可能同时结算,要一件一件来,这间隙时间便是等待时间。比如 你买了5袋相同的洗衣液(品牌批次价格均一致),如果收银员够聪明的话,他会怎么做?

W:他结算时不需要刷5遍条形码,而是只刷1次,然后数量乘以5即可。

L:聪明!这与 数据库中减少硬解析等待时长的思路类似。在 XXX平台的B模块 中,部分SQL就是这么优化提速的 ,请看示例。

原始查询(导致硬解析)。

SELECT * 
FROM users 
WHERE username = 
'user1';
SELECT * 
FROM users 
WHERE username = 
'user2';...


-- 每次都重新解析

优化后查询(使用绑定变量)。

SELECT * 
FROM users 
WHERE username = :username;
-- 只需解析一次

通过使用绑定变量,SQL可以复用执行计划,减少硬解析次数,从而降低等待时长,提高查询效率。

3

减少日志切换等待时间(多鱼装一袋)

L:再举一个和洗衣液不同的例子, 你买了5只相同品种的鱼,分别包装称重(重量不同,价位不一样),收银员就不得不进行5次结算, 有没有提高效率的办法呢?
M:如果这5只鱼放在一起称重,那就从5袋变成1袋,收银员就会从 结算5次缩减为只结算1次 了。
L:很棒!这类似 数据库中减少日志切换等待时长的思路,在 XXX平台的C模块 中,部分SQL就是这么优化提速的 , 请看示例。

原始代码示例(循环内提交):

FOR i 
IN 1..1000 LOOP
INSERT INTO orders 
VALUES (i, 
'Order_' || i);
COMMIT; 
-- 这里就是问题所在
END LOOP;


优化后代码示例(循环外提交):

FOR i 
IN 1..1000 LOOP
INSERT INTO orders 
VALUES (i, 
'Order_' || i);
END LOOP;
COMMIT; 
-- 只提交一次


通过 将COMMIT操作移出循环内,让该SQL从 提交多次变成了只提交1次, 减少了不必要的日志切换等待,让SQL执行得更快。


4

减少锁相关等待时间(开老人通道)

L:有些老年人在 从购物车拿出货物时,可能会因为阿尔茨海默等各种原因 忽然就 发呆 了,此时收银台的 结算交易就会停滞,后面的顾客就不得不进行长时间等待,对此你有什么好办法吗?

Q:可以为老人们开通特殊收银通道,由工作人员帮助其完成结算。

L:机智!这类似于 数据库中的减少 锁相关等待时长的思路,在 XXX平台的D模块 中,部分SQL就是这么优化提速的 , 请看示例。

原始查询(其他事务更新相同account记录时,可能存在锁等待):

UPDATE accounts
SET balance = balance - 
100 
WHERE account_id = 
123;
-- 其他事务也更新account


优化思路则是要考虑 尽快释锁资源,除了 及时的提交外,还包括在account_id字段上建立恰当的索引等,以 加快更新速度,从而缩减锁等待时间。

结语

SQL运行中的相关等待事件远不止上述四个, 限于篇幅,就不一一展开了。如果让大家觉得意犹未尽,敬请谅解。以下是对执行时间的一个脑图总结。

值得一提的是,在某一个SQL中,等待时长和工作时长往往是多段的。 如 T_等待=T_cpu等待+T_硬解析+T_日志切换+T_锁等待.... 同理,T_工作也是如此,往往是 多个子工作时间的集合 。

通过减少等待时长,我们已经显著提升了SQL的执行效率。然而,在等待时长已经得到充分优化的情况下 ,如何进一步 降低工作时间,也就是加快交易本身的速度呢?敬请期待。



未完待续...


注

  1. 本集的SQL优化以OLTP领域的 事务型SQL为主。因为OLAP领域的分析型SQL任务本身较大, 这些等待事件对其整体性能的影响就不大了;

  2. 这是SQL优化思想系列,目的是希望能在思想层面给读者带来启发,提升其大局观。所以具体的 技术细节本文就不做深究,点到为止。




公众号:收获不止数据库

微信:ljbyxl1213

系列回顾



原文作者:收获不止数据库;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论
历任中电福富研究院副理事长、中盾安信研究院副院长、宁德时代技术顾问等职务,受聘电信集团专家和国家十四五课题负责人,著有《收获,不止Oracle》《收获,不止SQL优化》等多本畅销数据库技术书籍。

注册时间:2024-02-06

  • 博文量
    162
  • 访问量
    197946