最近的一次面试,面试官提到了一个 MySQL 场景,如下
表 t 只有两个字段,主键 id 和 varchar 类型的 name ,现在有一条 SQL:select id,name from t limit 2; 这条语句执行过程中很慢,问大概的原因。
1 JasonLaw 2023-05-31 18:04:41 +08:00 ![]() 这是一个很傻逼的问题,我想不出任何理由会导致 select id, name from t limit 2 慢。 |
2 JasonLaw 2023-05-31 18:06:05 +08:00 ta 说负载导致的锁的问题,那具体是什么呢?什么负载?造成了什么锁? |
![]() | 3 bk201 2023-05-31 18:09:26 +08:00 select 还能导致锁问题? |
4 gps32251070 OP @JasonLaw 意思是 mysql 负载大,具体锁没说,就说查询会加锁,我看他不怎么想继续就没细问 |
6 gps32251070 OP @himly1 这个语句是快照读,没有加任何锁 |
8 himly1 2023-05-31 18:19:44 +08:00 可能是 innodb 且负载太大,其中大部分都是写操作,那么就有可能是因为 x 锁导致 select 语句无法读取 s 锁, 导致一直处于阻塞状态,所以会慢。 |
9 gps32251070 OP @himly1 语句没有加 lock in share mode 啊,怎么会加锁 |
10 himly1 2023-05-31 18:22:50 +08:00 @gps32251070 学到了 |
11 wangnimabenma 2023-05-31 18:26:23 +08:00 刷脏页会抖一下,但是和这个好像没关系 |
![]() | 12 admol 2023-05-31 18:31:18 +08:00 这个 MySQL 45 讲 里面好像有讲到。 1 、 如果是数据库本身就有很大的压力,那所有的 SQL 都会很慢,不仅是你这个 SQL 2 、表被锁了(等 MDL 锁、等 flush 、等行锁) 3 、慢查询(有其他 SQL 影响) |
![]() | 13 xuanbg 2023-05-31 18:47:03 +08:00 就是记录数太多了且没有任何索引。譬如上亿条数据里面查 2 条,也是是全表扫描,自然慢得一逼。 |
14 |
15 gps32251070 OP @xuanbg 没索引也没有任何关系吧,没有任何 where 条件 |
16 gps32251070 OP @xuanbg 而且面试官给我的方向是锁导致的问题 |
17 gps32251070 OP @admol 我考虑到 1 ,3 点了,所以说了数据页问题。第二点 MDL 可能性很低,谁会高并发改表结构?行锁问题这个语句没有加任何锁,所以也不需要等锁吧,快照读 |
![]() | 19 xuanbg 2023-05-31 19:27:47 +08:00 @gps32251070 没索引不是一定有问题,但记录数多还没索引就遭不住。。。 |
20 gps32251070 OP @xuanbg 忘了补充,面试官给的数据量是 20W ,这数据量不加读锁顺序 limit 2 我想不出导致性能问题的底层原因 |
![]() | 21 xuanbg 2023-05-31 19:56:36 +08:00 @gps32251070 limit 2 是顺序读 2 条没错,可顺序怎么来的?不得排序先? 20 万数据没索引你排序一个试试看慢不慢就完了。 |
![]() | 22 xuanbg 2023-05-31 19:58:40 +08:00 20 万里取 2 条的意思是先读 20 万,然后取 2 条啊,不是直接取 2 条! |
23 JasonLaw 2023-05-31 20:09:20 +08:00 ![]() |
![]() | 25 wushigejiajia01 2023-05-31 20:27:17 +08:00 关注一下 |
26 taogen 2023-05-31 20:37:44 +08:00 ![]() @xuanbg explain 中 type=ALL 的意思是全表扫描直到查到符合条件的数据。这里 limit 2 ,且没有 order ,扫到第二条数据的时候就满足要求,然后就返回了。我用 OP 的语句查了我生产数据库中一个 1.2G 的表,瞬间就返回了。 |
27 zengguibo 2023-05-31 20:41:58 +08:00 最大的可能是锁表了,可以使用 show processlist 看一下 |
28 fredcc 2023-05-31 20:43:43 +08:00 via Android 面试官没提到是什么表引擎吗 |
29 tutudou 2023-05-31 20:45:48 +08:00 数据多了,也会导致慢呀,嘴在他身上,他喜欢说什么就什么好了。 |
30 taogen 2023-05-31 20:52:37 +08:00 面试官可能是这个意思:一条看似不可能慢的查询 SQL ,在什么情况下会变慢? |
![]() | 31 chaleaochexist 2023-05-31 21:18:18 +08:00 如果数据库服务器的负载较高,例如同时有其他大量查询或者写操作,那么查询的执行时间可能会延长。这可能是因为数据库服务器资源不足,导致查询需要等待资源的可用性。 |
![]() | 32 chaleaochexist 2023-05-31 21:18:31 +08:00 @chaleaochexist #31 GPT 说的. |
33 koloonps 2023-05-31 21:20:06 +08:00 mark 下,我之前就遇到过 join 查询结果直接超时,换一台服务器就好的情况 |
![]() | 34 xiangyuecn 2023-05-31 21:26:01 +08:00 什么负载不负载的,加钱皆可解决 所以,原因是钱给少了 |
35 ccde8259 2023-05-31 21:26:23 +08:00 意味着执行计划不会有问题的情况下,下层结构会带来哪些可能的问题。 如果是 InnoDB 的话,首先是 Buffer Pool 本身访问就是需要 Mutex 的,有没有可能是等锁导致的慢呢? 进一步的,如果 Buffer Pool 没有命中就需要从磁盘拖数据,磁盘 IO 导致的慢呢? 从磁盘拖回来的数据如果是有问题的,比如刷出来了个 Crash 完以后 LSN 高于 Checkpoint 的脏页,从 Redo-Log 恢复数据导致的慢呢? |
36 xiaofan2 2023-05-31 21:29:43 +08:00 1. 什么执行引擎? |
![]() | 37 sadfQED2 2023-05-31 21:30:01 +08:00 via Android @JasonLaw 还真有可能慢,而且是我们线上真实遇到过的问题。我们最终查到的原因是因为我们机房交换机有问题,mysql 和业务服务器通讯过程中出现了丢包,丢包引起一系列问题,最终导致查询很慢。 面试官问这种目测他们也是遇到这种问题了吧,让他们排查网络问题 |
![]() | 39 sadfQED2 2023-05-31 21:33:24 +08:00 via Android 面试官说了是负载问题,但是没说是什么负载啊,网络 io 打满,传输慢成狗,那无论什么查询都超慢是有可能的。 而且他也没说是 mysql 自己的问题,网络 io 打满,或者磁盘 io 打满,都有可能 |
![]() | 40 yianing 2023-05-31 21:34:05 +08:00 via Android MySQL 快照读不加锁 |
![]() | 41 ModStart 2023-05-31 21:34:37 +08:00 1. 数据量过大:如果表 t 中的数据量非常庞大,那么执行这条 SQL 语句会涉及大量的数据读取操作,导致执行时间变长。 2. 索引缺失:如果在表 t 上没有合适的索引,数据库系统将需要进行全表扫描来查找满足条件的数据,这会导致执行时间延长。 3. 硬件性能问题:如果数据库服务器的硬件性能较低,如 CPU 、内存、磁盘速度等方面的限制,可能导致执行 SQL 语句的速度变慢。 4. 锁竞争:如果在执行这条 SQL 语句的同时,有其他的查询或写操作正在对表 t 进行操作,并且涉及到了相同的数据行,那么就可能发生锁竞争,导致执行速度变慢。 |
42 gps32251070 OP @xiaofan2 innodb ,RR 级别,面试官意思强调是锁导致的,我理解这个语句锁是不会导致慢的,唯一可能的是数据页 buffer 频繁被替换 |
43 gps32251070 OP @sadfQED2 他意思是高负载导致的锁等待 |
![]() | 45 hangszhang 2023-05-31 22:15:13 +08:00 锁表可还行,快照读又不加锁 |
46 doraf 2023-05-31 22:21:11 +08:00 也可能有这种情况: https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html , SERIALIZABLE 这段,This level is like REPEATABLE READ, but InnoDB implicitly converts all plain SELECT statements to SELECT ... FOR SHARE if autocommit is disabled. |
![]() | 47 rekulas 2023-05-31 23:25:21 +08:00 锁导致的问题。。。有没可能是这样 面试官也是技术,内部系统某些逻辑设计不合理为了避免冲突直接锁表更新数据,完了再解锁 负载上来之后面试官发现这样的频繁加解锁操作会导致 select 明显变慢,一时狂喜,又发现一个 mysql 缺陷,于是用来作为考题测试来面试的“小白”们能否快速分析出原因 |
48 urnoob 2023-05-31 23:32:09 +08:00 via Android 首先说没索引导致肯定不对,因为主键默认就是索引的。 除了网络等外部情况,可能性最大的是大量比当前 id 还小的数据插入,特别是插入的 id 还是递减的,导致树最左边的节点在不断分裂,一直会有锁。 |
49 yagamil 2023-06-01 00:11:49 +08:00 可能是索引 id 是乱序的? 然后面试其实想考的 limit x,y ; 在数量巨大的情况下的性能问题? |
![]() | 50 Weixiao0725 2023-06-01 00:22:18 +08:00 要我回答就说这个 mysql 一定是运行在 20 年前的机器上 |
![]() | 51 Euthpic 2023-06-01 01:36:46 +08:00 via Android ![]() 这个问题有点傻 x ,因为慢的原因和 sql 无关,原因可能出在 mysql ,网络,硬盘等系统方面。给出具体 sql 的目的是觉得这个 sql 可以优化吗? |
![]() | 52 nuk 2023-06-01 03:01:29 +08:00 遇到过两种情况,一种是卡 io ,还有一种很奇怪,是某个客户端执行语句,sql 协议出问题,一直在等几个 byte ,然后整个表就处于锁死的状态。 |
![]() | 53 akira 2023-06-01 05:33:53 +08:00 ![]() 其实问题是问,一个明显不可能慢的 sql 执行很慢,有什么可能。 |
![]() | 54 dog82 2023-06-01 09:19:04 +08:00 如果 mysql 的事务隔离级别被设置成串行化,会频繁出现! 但是谁傻到设置成串行化呢 |
55 leorealman 2023-06-01 09:46:09 +08:00 磁盘 IO 被打满是可能会这样的 |
![]() | 56 plutome 2023-06-01 10:29:48 +08:00 @xuanbg “ 20 万里取 2 条的意思是先读 20 万,然后取 2 条啊,不是直接取 2 条!” “ limit 2 是顺序读 2 条没错,可顺序怎么来的?不得排序先?” 虽然我自己也经常犯这种“眼高手低”的错误,但是这两句话说得还是离谱。 可能还是要多学习一下。 |
![]() | 57 Pythoner666666 2023-06-01 13:54:24 +08:00 @xuanbg 兄弟 这个说法就很离谱啊 ,你一边让别人去尝试,可是你自己就是不去真的尝试一下 |
![]() | 58 8355 2023-06-01 18:38:38 +08:00 可能是面试官沟通能力有问题. 这样问法绝大部分正常人的理解应该是在场景正常的情况下因为这条 sql 本身执行慢是什么原因, 如果说因为其他原因的慢是过于开放性的答案了.面试官应该给予合理引导. 可以从负载和 io 上回答 也可以从锁上回答. 也可以从各种不合理应用回答. 也可以从数据量上回答,也可以从表引擎上回答,也可以从数据库配置回答 还可以通过网络原因上回答. 都他妈可能影响慢. |