收获不止数据库

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

SQL优化思想系列

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

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

引言

我们常常追求"让SQL跑得更快"。然而,L老师最近的举动颠覆了这一传统观念。他特意让部分SQL运行得更慢,却大幅提升了YYY平台的整体性能。这一反常操作立即引发了大家的好奇,纷纷向他请教其中奥妙。

是的,从全局出发,适当地让部分SQL慢下来,有时还真是对的。

原本我计划直接讲解SQL优化的方法论,但鉴于这一思想很有启发性,能对后续整体方法论的理解形成铺垫,因此插入此集。接下来,让我们进入正文。

0

没听错,让SQL跑得更慢一些!

Q:L老师,听说您为YYY平台优化时,特意让一部分SQL的跑的更慢一些,这是真的吗?
L:哈哈,是真的。
M:这听起来很反直觉啊。
L:引入并行,你快他慢;增加索引,查快写慢;关闭日志,险中求快。
众人面面相觑:啥,没听懂。
Image
L:嗯,我会细细展开。其实SQL优化最要的是要有整体意识,不能拘泥于局部的得失。接下来,我就以YYY平台的A,B,C 模块为例,讲讲这背后的道理。
Q:期待!

1

案例1:引入并行,你快他慢!

L:首先说说A模块,我发现部分SQL设置了极高的并行度,初衷是提速。结果,这条SQL确实运行得很快,可惜整个系统的响应时间反而变长,语句类似如下。

-- 在大表上使用并行度执行查询
SELECT /*+ PARALLEL(t, 16) */

COUNT(*)

FROM t_large_table t

...

Q:为什么会这样?

L:高并行度意味着更多的CPU和内存资源被单个查询所占用。在资源有限的环境中,这种做法会抢占其他SQL所需的资源,导致整体系统的吞吐量下降。优化不仅是提升某一条SQL的性能,更是要平衡系统中各个部分的资源分配。

随后我取消了该SQL的并行度,虽然其执行速度有所放慢,但释放出来的系统资源可以被其他关键SQL所利用,提升整个系统的稳定性和响应速度。这是一种“以慢带快”的优化思路。

W:明白了,资源总是有限的,需要合理分配。

L:确实如此。这让我想起了战国时期的"围魏救赵"策略。当时,魏国大举进攻赵国,动用了大部分兵力,以至于留守本土的军队不多。齐国并没有直接派兵支援赵国,而是攻打魏国本土。迫使魏军撤回攻赵的大军,最终赵国获救。这与我们的SQL优化有异曲同工之妙,都是利用资源有限的道理,通过调整分配来达成目的。

W:哈哈,并行SQL和围魏救赵,真有几分相似!

2

案例2:增加索引,查快写慢!

L:再说说B模块。该业务关键且繁忙,为提升查询速度,团队在表上添加了大量索引。结果查询速度果然提升,但写入性能却大幅下降,导致入库延迟,影响了业务,语句类似如下。
-- 添加多个索引
CREATE INDEX idx_1 ON t1 (c1);
CREATE INDEX idx_2 ON t1 (c2);
CREATE INDEX idx_3 ON t1 (c3);

CREATE INDEX idx_4 ON t1 (c4);

CREATE INDEX idx_5 ON t1 (c5);

...

-- 从另一个表批量插入数据
INSERT INTO t1
SELECT * FROM t2

WHERE...

Q:为什么添加索引会导致写入变慢?

L:数据库在执行更新操作时,不仅要修改数据本身,还需同步更新所有相关的索引。这增加了额外的I/O开销,表更新的频率越高,性能影响越明显。我们需要根据实际的读写需求进行权衡。定期审查和优化现有索引,确保它们真正为业务需求服务,而不是盲目追求查询速度。
W:看来,考虑问题需要全面啊。

L:是的。这让我想起三国时期的街亭之战。马谡将军队驻扎在山上,只考虑了居高临下的优势,却忽视了缺水、补给困难和易受火攻的问题。结果被敌军切断补给并纵火,导致惨败。这与盲目增加索引很相似,专注于提高查询速度,却忽视了写入性能下降等其他重要因素。两者都是因为过于关注单一优势,而忽视了全局考虑。

X:可惜,要是马谡读了《收获,不止SQL优化》,也不至于如此啊。

3

案例3:关闭日志,险中求快!

L:最后看看C模块,该团队为提升更新速度,关闭了部分表的日志记录。虽然更新性能显著提升,但这也意味着一旦系统崩溃,数据恢复几无可能,语句类似如下。
-- 关闭日志记录(谨慎使用,仅为演示)
ALTER TABLE t1 NOLOGGING;
-- 执行批量插入操作
INSERT /*+ APPEND */ INTO t1 (c1, c2, c3)
SELECT c1, c2, c3

FROM t2

where ...

Q:关闭日志真的能带来显著的性能提升?

L:确实,关闭日志会减少I/O操作,尤其是在频繁的写操作中,性能提升明显。然而,日志是保障数据一致性和可恢复性的关键。关闭日志虽然短期内提升了性能,但长远来看,数据的安全性和可靠性遭到了严重威胁。
X:必须要在性能与安全之间找到平衡。
L:是的。这让我想起古代战争中的一个权衡。轻装上阵的士兵行军速度快,机动性强,就像关闭日志后的数据库操作。但他们在战斗中极易受伤,一旦遇到强敌就可能全军覆没。相比之下,穿戴重甲的士兵虽然行动缓慢,但在激烈的战斗中能够更好地保护自己,就像开启日志的数据库能在意外情况下恢复数据。
W:有趣,关闭日志就像抛弃盔甲,轻松一刻,危险长存。

结语

让SQL跑得慢一点来优化系统的相关案例远不止以上三个,比如“二十年目睹怪现状”提到的缓存内存、“二十年前的回忆”提到的物化视图等都是类似的,限于篇幅,就不展开了。如果让大家觉得意犹未尽,敬请谅解。

我们都知道,提升SQL速度能节约成本、增强系统稳定性和改善用户体验,但更重要的是,我们需要具备整体性思维,注重平衡系统资源、数据安全与读写性能。过度追求速度,可能掏空资源、降低数据安全性。因此,找到平衡点至关重要。有时,让SQL慢一点,反而是更高明的优化!

Image

当然,对特定的SQL任务,也有不同取舍。如果某些查询尤为关键,添加并行处理或许是最佳方案;若查询需求远大于写入,加索引或许无妨;而若某些表本身数据临时性强,关闭日志也是合理选择。

兵无常势,水无常形。SQL优化如此,做人做事亦如此。唯有具备全局视角,方能实现真正的成功。

未完待续...
更多精彩原创内容见公众号
    点关注   Image  不迷路
往期回顾,欢迎留言与转发

预告:《超融合数据库》即将出版。

Image