2026/1/15 19:34:13
网站建设
项目流程
网站上线需要多久,百度网站名称和网址,市场营销最有效的手段,自媒体采集网站建设3.那既然括号里的数字#xff0c;不是用来限制取值范围的那为什么要设置长度呢#xff0c;我不设置行不行
4.如果表中有INT(11)#xff0c;而插入的是100#xff0c;你会看到什么样的显示效果#xff1f;INT(11) 是不是就是存储11位的数字#xff0c;如果你插入了一个大于…3.那既然括号里的数字不是用来限制取值范围的那为什么要设置长度呢我不设置行不行4.如果表中有INT(11)而插入的是100你会看到什么样的显示效果INT(11) 是不是就是存储11位的数字如果你插入了一个大于99999 的数字如100000你认为INT(5) 会如何显示5.MySQL里面datedatetimeTIMESTAMP有什么区别假设这个时候我要做一个跨国的系统那么你觉得选哪个字段会更合适为什么6.varcahr最大长度是多少能设置多少就括号里面那个数值7.唯一索引和普通索引mysql综合读写来看哪个更快8.唯一索引他是怎么做那个唯一检查的9.Doublewrite机制了解么10.mysql 的主从复制它的流程11Ok那这个时候有问题了就是说我从库拉到了binlog之后转成Relaylog准备重放的时候那么它的执行是单线程还是多线程12.它怎么执行到区分不同的group去复制呢13. 那mysql在做双主复制时双主它会不会导致循环复制就是a给BB又给A这种如果会该怎么去避免这种情况呢14你基础确实掌握的挺好的然后我来问一下你设计相关的就像我们做系统经常有那个菜单树的概念比如左边有个菜单有很多层级。对吧那现在我不设置比如最深要求多少级如果说让你设置一个菜单表尽可能的少的层级也不要care他的性能的前提下最少需要多少列15如果我这时候又要考虑性能呢比如说我有两个场景第一个场景是我选择一个父节点父菜单我能查出全部的子孙然后第二种呢是我选一个子孙我能查询出全部他的父和爷爷以及所有的先祖你觉得应该怎么设计16第二个设计题如果我想要设计一个浏览用户的历史记录比如说淘宝那种历史记录我可以看我过去看到的是什么这个浏览得有两个维度第一个维度是以个人C端的角度去看这是我自己的历史记录第二个角度是用供应商的角度去看这个商品被哪些人浏览了必须要用到分库分表你决定应该怎么设计问题3INT括号里的长度为什么设置不设置行不行核心回答可以完全不设置且日常开发中建议不设置因为显示宽度几乎无实际价值。为什么会有这个“长度”显示宽度这是 MySQL 的历史设计残留早期数据库工具如 mysql 命令行依赖显示宽度做格式化展示核心场景只有一个——配合ZEROFILL做零填充补位比如 INT(5) ZEROFILL 插 123 显示 00123此外显示宽度可作为“字段注释”让维护者直观知道该字段预期显示的位数比如 INT(5) 暗示该字段存 5 位以内的编号但仅为可读性无强制约束。不设置的后果不设置时 MySQL 会用默认显示宽度INT 默认 11TINYINT 默认 4SMALLINT 默认 6MEDIUMINT 默认 9BIGINT 默认 20。这些默认值仅为“能完整显示该类型所有数值的最小宽度”比如 INT 最小负数 -2147483648 是 11 位不影响任何存储/计算逻辑。总结显示宽度是“非必要设计”不设置完全没问题现代业务中更推荐靠注释说明字段用途而非依赖显示宽度。问题4INT(11)插100的显示效果INT(11)是否存11位INT(5)插100000的显示核心结论先破误区INT(11) 绝对不是“存储11位数字”INT 类型固定4字节最多存 10 位正数2147483647或 11 位负数-2147483648括号内数字仅影响零填充场景的显示。INT(11) 插入 100 的显示效果不加 ZEROFILL显示100和 INT(5)/INT(20) 无区别加 ZEROFILL显示00000000100补0到11位且自动转为无符号数。INT(5) 插入 1000006位数字的显示效果不加 ZEROFILL显示100000位数超过5也正常显示无截断/报错加 ZEROFILL显示100000零填充仅补位“不足显示宽度”的情况超过则原样显示。问题5date/datetime/TIMESTAMP区别跨国系统选哪个第一步三者核心区别表格更清晰面试口述可简化特性datedatetimeTIMESTAMP存储格式‘YYYY-MM-DD’‘YYYY-MM-DD HH:MM:SS’时间戳秒级4字节取值范围1000-01-01 ~ 9999-12-311000-01-01 00:00:00 ~ 9999-12-31 23:59:591970-01-01 00:00:01 ~ 2038-01-19 03:14:07时区感知否纯日期无时区否固定时间不转换是存储时转UTC查询时转当前会话时区存储字节3字节8字节4字节5.6支持毫秒7字节自动赋值无无可设为 CURRENT_TIMESTAMP更新/插入自动填当前时间第二步跨国系统选型优先选 TIMESTAMP需注意范围其次用 datetime 应用层时区转换。理由跨国系统核心痛点是时区不一致比如中国用户UTC8和美国用户UTC-5操作同一条数据时间需自动适配本地时区TIMESTAMP 天然支持时区转换存储时会将会话时区的时间转为 UTC 存到库中查询时再根据当前会话的时区转回本地时间无需应用层做复杂的时区计算注意事项TIMESTAMP 范围有限到2038年如果业务需要存储超过2038年的时间可改用datetime 应用层维护时区比如额外加一个timezone字段记录用户时区查询时应用层转换。问题6varchar最大长度括号内的数值核心结论分“理论最大值”和“实际可用值”核心受3个因素限制底层限制MySQL 规定行的最大字节数为 65535所有列的总字节含字段长度标识、NULL标记等varchar 本身的“长度”是字符数但存储时占用“字符字节数 1/2字节长度标识”。分场景说明字符集影响utf83字节/字符理论最大字符数 (65535 - 2) / 3 ≈ 21844减2是长度标识utf8mb44字节/字符理论最大字符数 (65535 - 2) / 4 ≈ 16383InnoDB 额外限制若 varchar 是表的唯一可变长度列且行格式为 COMPACT/DYNAMIC超过768字节的 varchar 会存到溢出页此时“实际常用值”utf8mb4 下建议设 191避免索引长度超限utf8 下建议设 255括号内数值直接填“字符数”如 varchar(20) 表示存20个字符无论utf8/utf8mb4。总结括号内可设的最大值受字符集和行总字节限制utf8mb4 下理论最大16383实际开发中建议按业务需求设如手机号设11姓名设50而非拉满。问题7唯一索引 vs 普通索引 综合读写速度核心结论读几乎无差写普通索引更快综合看普通索引更优写多场景读性能几乎无区别唯一索引微优但可忽略普通索引找到匹配行后会继续往后扫一小段确认是否有下一个匹配行唯一索引找到匹配行后直接返回无需确认下一行实际场景中这个差异极小尤其是InnoDB的聚簇索引结构用户感知不到。写性能普通索引显著更快唯一索引写入/更新时必须先做“唯一性检查”加锁索引查找且无法使用“变更缓冲Change Buffer”变更缓冲仅对普通索引生效可延迟写入磁盘提升写性能普通索引无需唯一性检查可利用变更缓冲写操作的磁盘IO更少。综合读写读多写少两者几乎无差唯一索引可避免重复数据略优写多读少普通索引优势明显综合速度更快。问题8唯一索引的唯一检查机制核心流程分插入/更新场景检查时机写操作INSERT/UPDATE的“执行阶段”而非提交阶段先检查唯一性再执行写入。检查步骤步骤1根据要写入的值走唯一索引快速查找B树查找O(logn)确认是否存在相同值步骤2加锁防止并发冲突关键避免幻读导致重复插入场景加“间隙锁/Next-Key锁”隔离级别≥RR锁定要插入的位置防止其他会话同时插入相同值更新场景先锁定旧值行再检查新值的唯一性步骤3若找到重复值直接返回报错1062 Duplicate entry若未找到执行写入。特殊情况批量插入INSERT … VALUES (…)逐行检查唯一性一行失败则整个语句回滚5.7可设innodb_duplicate_key_error_is_recoverable1跳过错误行联合唯一索引检查所有索引列的组合值是否唯一。问题9Doublewrite机制双写缓冲区核心解决InnoDB“部分写页”崩溃问题比如写页时断电页只写了一半为什么需要InnoDB 页大小默认16KB写入磁盘时若只写了一部分如8KB页会损坏且redo log仅记录“页的修改”无法修复损坏的页。核心流程步骤1InnoDB 准备将内存中的脏页刷到磁盘时先把页内容写入“双写缓冲区”内存中2MB对应磁盘共享表空间的doublewrite区连续的128个页步骤2双写缓冲区刷到磁盘顺序写性能高确保页完整写入步骤3再将双写缓冲区的页刷到数据文件的对应位置随机写步骤4崩溃恢复时检查数据文件的页是否完整若完整则正常恢复若损坏从doublewrite区读取完整页覆盖再用redo log恢复数据。性能影响看似多写一次但doublewrite区是顺序写实际性能损耗仅5%-10%换来了页的完整性。问题10MySQL主从复制流程核心三步面试可分阶段讲逻辑更清晰阶段1主库生成Binlog主库执行增删改操作事务提交时将修改记录按顺序写入Binlog二进制日志主库维护一个 dump 线程等待从库连接并请求Binlog。阶段2从库拉取Binlog从库启动 IO 线程连接主库的 dump 线程从库向主库请求“指定位置后的Binlog”主库 dump 线程推送Binlog到从库从库 IO 线程将收到的Binlog写入本地 Relaylog中继日志并记录主库的Binlog位置master_log_file master_log_pos。阶段3从库重放Relaylog从库启动 SQL 线程读取Relaylog中的日志事件按顺序执行日志中的增删改操作还原主库的数据保持主从数据一致。总结主库Binlog dump线程→ 从库IO线程拉取→写Relaylog→ 从库SQL线程重放Relaylog。问题11Relaylog重放是单线程还是多线程核心分MySQL版本从单线程进化到多线程5.6及之前单线程SQL线程→ 性能瓶颈主库高并发时从库重放慢导致主从延迟5.6支持“基于库的并行复制”→ 多线程每个库一个线程但如果所有写操作都在一个库还是单线程5.7支持“基于GTID的并行复制”逻辑时钟→ 无冲突的事务可并行执行按事务的提交顺序同一组的事务并行8.0支持“基于写集Write Set的并行复制”→ 更智能按事务修改的数据行哈希分组无冲突的事务跨库/跨表并行性能大幅提升。总结现代MySQL5.7默认多线程重放老版本单线程。问题12如何区分不同group复制MySQL Group ReplicationMGR核心基于“事务的冲突检测”和“逻辑时钟/写集”分组核心原理MGR 是分布式一致性复制Paxos协议将事务分为“可并行”和“需串行”的组步骤1每个事务提交前生成“写集”Write Set即事务修改的行的哈希值步骤2节点间交换写集检测事务是否冲突比如两个事务修改同一行则冲突步骤3无冲突的事务分到同一个“组”Logical Clock可并行执行有冲突的事务分到不同组串行执行。传统并行复制非MGR5.6按库分组不同库的事务并行5.7按GTID的“事务序列号”分组同一逻辑时钟的事务并行。总结核心是“冲突检测”无冲突的事务归为同一group并行冲突的串行。问题13双主复制的循环复制及避免第一步会导致循环复制双主复制A←→B中A的Binlog同步到BB执行后生成新的Binlog又会同步回AA执行后再同步到B无限循环。第二步避免方案核心是“识别并丢弃自己生成的Binlog”核心方案设置唯一的server_id 过滤自身server_id的Binlog给主库A和B设置不同的server_id如A1B2开启log_slave_updates从库执行Relaylog后将操作写入自己的Binlog时主库收到Binlog后先检查Binlog中的server_id如果是自己的server_id则丢弃该Binlog不执行辅助方案1使用GTIDMySQL 5.6的GTID全局事务ID包含server_id从库执行Relaylog时会记录已执行的GTID若收到的Binlog的GTID已存在则跳过执行天然避免循环辅助方案2业务层面隔离比如A主库写奇数ID的数据B主库写偶数ID的数据Binlog同步后对方执行时无匹配数据不会产生新的Binlog。问题14菜单树表 最少列不考虑性能核心最少3列满足任意层级无性能要求列名类型说明idBIGINT菜单主键唯一标识menu_nameVARCHAR(50)菜单名称必选展示用parent_idBIGINT父菜单ID顶级菜单设为0或NULL理由id唯一标识每个菜单是层级关联的基础menu_name菜单的核心业务属性必须有parent_id通过“子菜单的parent_id父菜单的id”维护层级关系无论多少层仅靠这一列就能递归遍历比如顶级菜单parent_id0一级菜单parent_id0二级菜单parent_id一级菜单id以此类推无其他必选列比如排序、状态等属于业务扩展题目要求“最少列”可省略。问题15菜单树表 考虑性能查子孙/查先祖核心方案放弃纯递归改用“物化路径法”最优平衡方案第一步表结构设计新增1列共4列列名类型说明idBIGINT菜单主键menu_nameVARCHAR(50)菜单名称parent_idBIGINT父菜单ID兼容旧逻辑pathVARCHAR(1000)物化路径如“0,1,5,8”path字段规则用分隔符如逗号拼接所有祖先ID从根到当前菜单顶级菜单path“0”一级菜单父0path“0,1”二级菜单父1path“0,1,5”三级菜单父5path“0,1,5,8”。第二步满足两个性能场景查父节点的所有子孙SQLSELECT * FROM menu WHERE path LIKE CONCAT(#{parentPath}, ,%)示例查父节点1的子孙 →path LIKE 0,1,%直接命中所有子、孙、曾孙无需递归一次查询搞定查子孙的所有先祖SQL拆分path字符串按分隔符分割后直接查询所有ID对应的菜单示例path“0,1,5,8” → 拆分出[0,1,5,8]查询id in (0,1,5) 就是所有先祖拆分可在应用层做如Java用split或用MySQL的SUBSTRING_INDEX函数。进阶方案极致性能闭包表如果数据量极大可新增“闭包表”menu_closure存储所有祖先-后代关系列名类型说明ancestor_idBIGINT祖先菜单IDdescendant_idBIGINT后代菜单IDdepthINT祖先到后代的层级可选查子孙SELECT descendant_id FROM menu_closure WHERE ancestor_id#{parentId}查先祖SELECT ancestor_id FROM menu_closure WHERE descendant_id#{childId}缺点新增/删除菜单时需维护闭包表比如新增二级菜单要给所有祖先添加一条关联记录但查询性能极致。问题16用户浏览历史记录 分库分表设计C端供应商端核心思路双维度分片 双写保证一致性第一步核心诉求拆解C端按用户ID查自己的浏览记录用户维度高频读供应商端按商品ID查浏览用户商品维度低频读需全局视角分库分表解决单表数据量过大如亿级浏览记录的问题。第二步表结构设计基础表CREATETABLEuser_browse_record(idBIGINTNOTNULLAUTO_INCREMENTCOMMENT主键,user_idBIGINTNOTNULLCOMMENT用户IDC端分片键,goods_idBIGINTNOTNULLCOMMENT商品ID供应商端分片键,supplier_idBIGINTNOTNULLCOMMENT供应商ID快速过滤,browse_timeDATETIMENOTNULLCOMMENT浏览时间,goods_nameVARCHAR(100)COMMENT商品名称冗余避免联表,PRIMARYKEY(id),KEYidx_user_time(user_id,browse_time)COMMENTC端查询索引,KEYidx_goods_time(goods_id,browse_time)COMMENT供应商查询索引)ENGINEInnoDBDEFAULTCHARSETutf8mb4;第三步分库分表策略C端维度优先分片键user_id分片规则user_id % 分库数 库号user_id % 分表数 表号优势用户查自己的历史记录时直接定位到对应的库表查询速度极快供应商端维度方案1双写推荐→ 写入C端库表的同时通过消息队列如RocketMQ异步写入“商品维度”的分库分表分片键goods_id方案2全局索引 → 用Elasticsearch存储“goods_id → user_id列表”供应商查询时先查ES再到C端库表拉取详情优势供应商查商品浏览记录时直接定位到商品维度的库表无需全库扫描。第四步细节补充过期数据定时清理如超过3个月的记录避免表过大读写分离分库分表后读请求走从库写请求走主库一致性双写时用消息队列保证最终一致失败重试分片数分库数建议8/16分表数建议64/128避免后续扩容麻烦。