关于面试时面试官提出的一些疑问,求解答

2021-08-03 22:04:47 +08:00
 MrGoooo
问题 1:mysql 给表中的 a,b,c 三个列建立联合索引,select * from t where a=1 and b > 2 order by c,面试官问会不会走这个联合索引,我说:会,因为满足了最左前缀匹配。面试说让我下去好好了解了解。

问题 2:面试官问 redis 缓存和数据库一致性问题,我说:增删改的时候先删 redis 缓存再操作数据库。面试官问如果 redis 删除失败了怎么办?我说:redis 操作失败了就抛出异常,不会再对数据库操作。面试官问:如果需要 redis 操作失败的情况下也需要对数据库增删改成功,并且避免读出脏数据,改怎么做?我没想出来。
6558 次点击
所在节点    程序员
48 条回复
jorneyr
2021-08-04 09:12:40 +08:00
@MOONLIGHTT 数据库更新成功,缓存删除失败更危险
CodeCodeStudy
2021-08-04 09:19:54 +08:00
第一个问题的 a=1 and b > 2 用到索引了,符合最左前缀匹配,用到了联合索引里的 a,b,跟后面的 order by c 没有关系
CodeCodeStudy
2021-08-04 09:21:45 +08:00
这面试官也是个半吊子
EmptyDX
2021-08-04 09:27:52 +08:00
@lxy42 试过,可以命中索引。联合索引顺序是(a,b,c)

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE test1 ref idx_union idx_union 4 const 6 Using where; Using index; Using filesort
@lxy42
fkname
2021-08-04 09:41:43 +08:00
亲测第一题是走索引的。第二题一般是先更新数据库再删除缓存,先删除缓存的话可能还没更新数据库其他线程又把老数据读到缓存中去了,而后删除缓存如果失败了可以放到延迟队列重试。还有一点就是缓存一般有过期时间来兜底。
dongtingyue
2021-08-04 09:44:54 +08:00
explain 测试下不就知道了么。。。刚测试一个 type 是 ref,所以面试官硬要说没用那也没办法。my5.7,MyISAM 、InnoDB
goodboy95
2021-08-04 09:56:56 +08:00
第二题如果 web 服只有一两台机器的话可以考虑在服务器上标记这个脏数据,不过大集群就不知道咋办了
whoosy
2021-08-04 10:09:04 +08:00
第一个只能说有机会用到索引,因为是 select * 了,因为要涉及到回表拿其他列的数据,你数据量少的时候或者索引区分度不好的时候, mysql 认为走全表扫可能速度更快,所以不会走索引
whoosy
2021-08-04 10:09:40 +08:00
第二个用延迟双删就行
atalia
2021-08-04 10:27:54 +08:00
第一题不太懂意思,因为对 a,b,c 建立联合索引相当于有(a),(a,b),(a,b,c)三个索引,所以这个最起码可以用(a,b)这个索引,但是不会用( a,b,c )这个索引
第二题缓存层和持久层操作顺序都是先持久层,再缓存层把。至于面试官的要求估计只能保证单进程级别的,跨进程除非用通信去通知所有进程标记。
hq136234303
2021-08-04 10:29:48 +08:00
第二题。可以是直接走队列 强一致性的话。 直接添加队列来顺序执行。
eric96
2021-08-04 10:35:01 +08:00
面试官可能也是半吊子,他理解的用索引是用了整个索引来做查询和排序。
实际使用,是用了这个联合索引来查找的,然后由于 b>2,导致无法用这个索引来做排序,需要用到 file sort
hq136234303
2021-08-04 10:36:27 +08:00
@whoosy 如果第二次删除失败呢?
admol
2021-08-04 10:45:32 +08:00
第一题:测试是走了部分索引的
事物隔离级别:RR,引擎:innoDB ; MYSQL 版本:8.0.22

创建表:
CREATE TABLE `test` (
`id` int NOT NULL AUTO_INCREMENT,
`a` int DEFAULT NULL,
`b` int DEFAULT NULL,
`c` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `ids_a_b_c` (`a`,`b`,`c`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;


插入测试数据:
INSERT INTO `my`.`test`(`id`, `a`, `b`, `c`) VALUES (1, 1, 1, 1);
INSERT INTO `my`.`test`(`id`, `a`, `b`, `c`) VALUES (2, 2, 2, 2);
INSERT INTO `my`.`test`(`id`, `a`, `b`, `c`) VALUES (5, 2, 3, 3);
INSERT INTO `my`.`test`(`id`, `a`, `b`, `c`) VALUES (6, 2, 3, 4);
INSERT INTO `my`.`test`(`id`, `a`, `b`, `c`) VALUES (3, 3, 3, 3);
INSERT INTO `my`.`test`(`id`, `a`, `b`, `c`) VALUES (4, 4, 4, 4);


执行计划:
explain select * from test WHERE a = 2 and b > 2 ORDER BY c;

mysql> explain select * from test WHERE a = 2 and b > 2 ORDER BY c;
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+------------------------------------------+
| 1 | SIMPLE | test | NULL | range | ids_a_b_c | ids_a_b_c | 10 | NULL | 2 | 100.00 | Using where; Using index; Using filesort |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+------------------------------------------+
1 row in set (0.02 sec)


结果:
type 为 range
key 为 ids_a_b_c (建的联合索引)
Extra 为 Using where; Using index; Using filesort
Using index 说明相应的 select 操作中使用了覆盖索引
Using filesort 说明排序确实没走索引



第二题:
延迟双删,保证数据的最终一致性
“redis 操作失败的情况下也需要对数据库增删改成功,并且避免读出脏数据” 这种情况下,可以用 Canal 订阅 binlog 完成数据同步,保证数据的最终一致性。
WillLiao
2021-08-04 10:56:36 +08:00
我觉得
问题 1,楼主说满足最左匹配会使用索引没有问题,a 等值,b 范围,范围后的操作不会使用索引,但总体来看还是用到了组合索引
问题 2,就是在瞎扯,这种情况就应该说做不到,没有必要保持强一致性,要保持强一致性你还引入 redis 干嘛?
Macolor21
2021-08-04 11:03:29 +08:00
@admol 实践是检验真理的唯一标准 [:doge:]
offswitch
2021-08-04 11:14:33 +08:00
第一题,取决于你的*是什么,如果*就是 a,b,c 那么走覆盖索引,如果*不是,有可能不走索引,这个面试官大概率想问你 order by 对索引的影响,但是你这个即使有 order by 又如何?只要跟定义索引的时候同方向,即使一个索引增一个减,也会用到索引。
https://dev.mysql.com/doc/refman/8.0/en/order-by-optimization.html
第二题,操作失败也要保证增删成功,避免读出脏数据,那么你就要考虑 redis 与服务节点之间网络分区恢复的问题,考虑单节点、多节点数据的问题,要在节点标记数据为脏数据,网络恢复后,根据节点脏数据过滤,读 db.
allAboutDbmss
2021-08-04 11:38:39 +08:00
在 psql 里面尝试了一下:

```
jigao=# create table A (a int, b int, c int);
CREATE TABLE
jigao=# insert into A values (1, 2, 3);
INSERT 0 1
jigao=# insert into A values (1, 3, 4);
INSERT 0 1
jigao=# insert into A values (2, 5, 6);
INSERT 0 1
jigao=# select * from A;
a | b | c
---+---+---
1 | 2 | 3
1 | 3 | 4
2 | 5 | 6
(3 rows)

jigao=# select * from A where a=1 and b > 2 order by c;
a | b | c
---+---+---
1 | 3 | 4
(1 row)

jigao=# explain select * from A where a=1 and b > 2 order by c;
QUERY PLAN
---------------------------------------------------------
Sort (cost=40.62..40.63 rows=3 width=12)
Sort Key: c
-> Seq Scan on a (cost=0.00..40.60 rows=3 width=12)
Filter: ((b > 2) AND (a = 1))
(4 rows)

jigao=# create index id on A (a, b, c);
CREATE INDEX
jigao=# select * from A where a=1 and b > 2 order by c;
a | b | c
---+---+---
1 | 3 | 4
(1 row)

jigao=# explain select * from A where a=1 and b > 2 order by c;
QUERY PLAN
--------------------------------------------------------
Sort (cost=1.05..1.06 rows=1 width=12)
Sort Key: c
-> Seq Scan on a (cost=0.00..1.04 rows=1 width=12)
Filter: ((b > 2) AND (a = 1))
(4 rows)

jigao=# drop index id;
DROP INDEX
jigao=# explain select * from A where a=1 and b > 2 order by c;
QUERY PLAN
--------------------------------------------------------
Sort (cost=1.05..1.06 rows=1 width=12)
Sort Key: c
-> Seq Scan on a (cost=0.00..1.04 rows=1 width=12)
Filter: ((b > 2) AND (a = 1))
(4 rows)


```

观察现象是: 没用使用到 index
但是这个主要是 cost-based 这些不一定是可以这样面试情况下有一个确定答案 我觉得就是问一个思路而已
fkdog
2021-08-04 14:01:57 +08:00
缓存如果要强一致的话, 可以考虑二 /三阶段提交.
然而事实上大部分系统并不需要强一致性, 对于这类对一致性要求并不高的系统, 可以通过消息队列等手段达到最终一致性效果.
weizhen199
2021-08-04 14:24:41 +08:00
我试了下,差不多 2e row,10 col 的表。在 Oracle 上是 Index Range Scan + Sort Order 。
小表就 table scan 了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/793477

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX