
1. 数据库到底是什么先搞懂最核心的概念大概每个人第一次接触数据库都是从这么几个词开始的增删改查、SQL、表、字段、主键。但如果你去问一个刚入行的朋友“数据库是什么”他十有八九会给你甩一句“就是存数据的”。这话对但等于没说。你拿 Excel 也能存数据拿一个文本文件也能存数据为什么还要专门搞一套数据库系统出来我做了这么多年数据库运维和开发最常给新人打的比方是这样的Excel 就像你家的抽屉你往里塞东西自己心里有数拿取的时候也自己动手数据库则像一个专业的档案室有专人管理有登记编号有借阅制度甚至还有安保和备份。它解决的不只是“把数据放进去”这么简单而是“在数据越来越多、访问的人越来越多、出错的代价越来越高之后怎么保证数据不乱、不丢、不快访问”的问题。所以真正要理解数据库你先得把两个概念拆开一个是数据本身就是那些躺在硬盘上的“值”另一个是数据库管理系统也就是我们常说的 DBMS像 Oracle、MySQL、达梦、SQLite 这些它们是负责读写、校验、并发控制、权限管理的软件系统。我们平时说“用一下数据库”其实绝大部分时间是在跟 DBMS 打交道而不是直接跟硬盘上的文件打交道。1.1 从一张表看懂关系型数据库的底层逻辑关系型数据库最核心的单元是三样东西表、行、列。表你可以理解成一张二维表格每一行是一条完整记录每一列是一个属性。比如一张“员工表”列是“员工编号、姓名、部门、工资”那插入一条数据就是往表里加一行。这里有一个非常容易忽略但又极其重要的概念——主键。主键的作用是唯一标识一行记录。你可能会想“没有主键我也能查到数据啊”能查但会在很多场景里埋雷。举个典型例子一个订单表里同一个用户下了两笔一模一样的订单如果表里没有主键这两条数据在你看来是完全一样的数据库也觉得它们一样。后续做修改、做删除你要定位“到底改哪一条”的时候就会非常痛苦。所以主键的设计几乎是一个表能不能用得长久的分水岭。还有外键它是用来建立表与表之间关系的比如订单表里的“用户ID”指向用户表的主键。很多人为了所谓的性能干脆不用外键但对于绝大多数业务系统来说外键是一种约束它能让数据库在源头帮你挡住脏数据。我见过太多因为没有外键最后出现“订单关联的用户根本不存在”这种问题的项目查起来简直要命。1.2 数据库和文件存储的差别到底在哪很多人不理解我直接往文件里写数据不也一样吗确实如果你的系统只有一个用户数据量就几百条进程还不怎么重启那直接写文件完全没问题。但一旦出现下面这几种情况文件方案就不灵了。第一种是并发。两个用户同时往同一个文件里写数据谁也不让谁最后文件就可能写坏。数据库在底层做了大量的并发控制机制它通过锁、事务、日志等手段来保证多个用户同时读写也不会出乱子。第二种是崩溃恢复。老板刚给你发了工资结果系统突然断电你那份数据如果只写在内存里就丢了如果只写在文件里可能写到一半坏了。数据库通过预写日志WAL等机制保证重启之后可以恢复到一个一致的状态要么全部完成要么全部回滚不存在“写了一半”的中间状态。第三种是查询效率。文件存储要按某一条件找数据只能一行一行扫过去数据量到百万条之后速度会慢到你怀疑人生。数据库用索引这种“伪目录”机制把查找范围从全表缩小到一个很小的区间查询效率完全不是一个量级。所以数据库不是“存数据”这么简单而是在复杂环境下保证数据安全、一致和高效访问的一整套基础设施。你理解了这个定位后续学任何数据库产品都会轻松很多。2. 关系型数据库与非关系型数据库到底怎么选数据库这个领域这么多年下来其实已经分成了好几条路线。你要是刚接触可能会被各种名词砸晕MySQL、Oracle、PostgreSQL、达梦、人大金仓、SQLite、MongoDB、Redis、向量数据库……每个听起来都很厉害但你要知道它们解决的问题其实是有明确分工的。用对了场景事半功倍用错了就是给自己找麻烦。2.1 关系型数据库的“老牌选手”们关系型数据库的主流大家应该都熟MySQL 是互联网创业公司的标配开源、生态好、招人容易Oracle 是传统大企业和金融系统的最爱稳定性和功能丰富度都是顶级的但成本也高PostgreSQL 这几年凭强大的功能口碑飙升很多人称它是“开源界的 Oracle”。这里我必须提一下国产数据库比如达梦和人大金仓。很多人一听到国产数据库就下意识觉得“是不是不成熟”这是一个挺大的误解。我实际用过之后的感觉是它们很多设计理念和用法都能对标 Oracle/MySQL尤其适合政企项目因为合规要求你只能用国产化产品而且它们大多做得相当扎实。比如达梦它跟 Oracle 的兼容性做得非常到位语法、数据类型、存储过程很多都能直接搬过来。如果你有 Oracle 的项目经验再接触达梦会非常顺。SQLite 则是一个另类它是单文件关系型数据库整库就是一个文件。这个特性让它特别适合做桌面软件、移动端应用的内嵌存储比如微信客户端的聊天记录底层就是 SQLite。它的优点是零配置、即插即用缺点则是并发写的能力相对弱不太适合高并发的服务端场景。2.2 非关系型数据库的真正适用场景非关系型数据库统称 NoSQL它里面的流派也很多。Redis 适合做缓存MongoDB 适合存结构灵活、变化频繁的数据图数据库适合做社交关系等强关联分析而最近这波 AI 热潮带火的向量数据库则是用来做相似度检索的比如人脸识别、智能推荐、知识库语义搜索这种场景。我给一些还在纠结的朋友一个很实用的建议没有特殊需求你就老老实实用关系型数据库别把 NoSQL 当成万能药。很多人一听说 MongoDB 不用定义表结构上手一顿乱用最后发现要做跨表关联查询时特别难受。NoSQL 的强大恰恰体现在它“舍弃了什么”上它舍弃了强一致和复杂关联换来了横向扩展能力和灵活的数据模型你只有在明确知道自己要的是这些时才应该选它。2.3 数据库同步到底是什么概念热搜词里有“数据库同步软件”“数据库同步工具”很多新手会问同步到底是在同步什么简单来说数据库同步就是把一份数据从源库复制到目标库并尽可能让两边保持一致。常见有几种用途一是高可用主库挂掉之后备库能顶上二是读写分离主库负责写从库负责读分担压力三是数据迁移和灾备把数据从旧库搬到新库或者复制一份到异地机房。实现方式上最底层的原理是日志同步。主库在写入数据时会把每一次变更记录到日志里比如 MySQL 的 binlog从库去读这个日志然后在本地重新“播放”一遍这些变更最终达到数据一致。市面上那些 xx 同步工具不管界面多么花哨核心做的还是抓取日志、解析日志、拿到新库去执行的操作。理解了这个底层逻辑你再去看同步工具报错、延迟这些问题都有据可循。3. 数据库的增删改查与事务写代码前必懂的底层原理你要想动手操作数据库绕不开的就是 SQL而 SQL 用得最多的就是增删改查。这四个字谁都会说但真正写得好尤其是在并发环境下写得好不是一件容易的事。3.1 一条 SQL 从发出到执行到底做了什么以 MySQL 为例你执行一条 select 查询数据库内部大致要跑一遍连接器先看看你的账号密码对不对→ 分析器把你的 SQL 文本解析成语法树→ 优化器决定用哪个索引、哪张表先查→ 执行器真正去数据文件里取数据返回。很多人以为查询慢就是索引没建好其实有时候还卡在连接器上比如连接数满了马路上全是车但出入口被封死了。这也是为什么数据库连接池会成为一个热门搜索词它的作用就是提前建立一批连接备用避免每次访问都经历“新开连接-认证-使用-关闭”的损耗。增删改查本身并不难难的是在数据互相有关系、业务有流程的时候保证这些操作不出错。你可以想一想一个最简单的转账业务A 扣钱B 加钱。如果 A 扣完了钱B 加钱那一步数据库突然崩溃了会发生什么钱凭空消失。所以数据库引入了事务机制把这几个操作归拢成一个整体要么全部成功要么全部失败。这个就是事务的原子性。教科书上的 ACID 四个特性原子性、一致性、隔离性、持久性都是围绕“让多个操作安全地组合成一件事”来展开的。3.2 事务隔离级别并发场景下的四大屏障ACID 里最难理解的是隔离性。简单说事务和事务同时执行的时候彼此影响的程度有多大。这里必须提几个经典问题脏读、不可重复读、幻读。脏读事务 A 读到事务 B 没提交的数据结果 B 回滚了A 读到的是空气。不可重复读事务 A 先查余额是 100再查一次变成了 90因为期间被事务 B 提交了修改。幻读事务 A 查询“工资大于 8000 的员工”第一次查到 5 条第二次查到 6 条因为事务 B 插入了新数据。为了防这些问题数据库提供了四种隔离级别从低到高依次是读未提交、读已提交、可重复读、串行化。隔离级别越高干扰越小但并发性能越差。MySQL 默认是“可重复读”Oracle 默认是“读已提交”。我见过不少系统上线后出现诡异的数据对不上问题排查到最后往往是隔离级别选错或者代码里根本没用事务。3.3 连接池别让你的数据库被连上“毛刺”连接池是很多新手容易忽略的一点。数据库建立连接的过程是要握手、认证、分配资源的很重。如果每次操作都现连现断在高并发下会出现大量的 TIME_WAIT 连接数据库服务器可能直接被拖垮。连接池的作用就是在数据库前面架一个“服务台”有一批固定数量的连接常驻池子里谁要用谁去领用完归还。主流的有 HikariCP、Druid、dbcp 等它们对性能的提升是非常可观的。关于连接池的大小设置我的经验和网上很多文章不太一样。不要盲目调大因为连接数是会消耗数据库内存和 CPU 的连接越多切换开销越大。一般经验是连接数 核数 × 2 加机械硬盘上的一些额外余量比如 4 核 16G 的实例核心业务池 20 个左右就够用了。真正到了瓶颈你会发现加连接远不如优化 SQL 有效。4. 数据库并发与锁机制死锁是怎么产生的如何避免死锁数据库一旦开始被多个业务同时访问锁就成了不可避免的话题。很多人第一次在日志里看到“Deadlock found when trying to get lock; try restarting transaction”时心里是慌的。其实死锁并不可怕可怕的是你不知道它怎么发生的也不知道怎么处理。4.1 共享锁和排他锁是所有的底层基础锁可以分很多类但最核心的是两种共享锁英文缩写 S 锁排他锁X 锁。你可以这么理解共享锁是“大家一起看一本书”谁都可以同时看但谁都不能涂改排他锁是“这本书我拿走了”只有我能看我能改你们只能等我。数据库在执行 select 语句时默认一般不加锁在执行 update/delete/insert 时必须加排他锁。两个事务同时想改同一行后到的那个就只能排队等待。死锁的典型场景是这样的事务 A 先锁了表 1 的一行想再锁表 2 的一行事务 B 先锁了表 2 的一行又想锁表 1 的一行。两个事务谁都不让谁结果就卡死了。数据库的死锁检测机制会发现这种状态然后强制回滚其中一个事务让你在业务层重试。所以遇到死锁报错一定不要慌它是数据库在“主动止损”。4.2 排查死锁和避免死锁的几个实用招数我在实际项目中总结了一套跟死锁“和解”的方法分享给大家所有事务访问多张表时尽量按相同的顺序。比如先操作订单表、再操作用户表别一个事务是“订单→用户”另一个是“用户→订单”。缩短事务的持锁时间。不必要的查询、外部接口调用、慢日志分析一律挪到事务外面去。用更低粒度的索引条件让锁影响的行数尽量少而不是动不动锁整张表。出现死锁后业务代码要做重试机制而不是直接报错给用户。关于“先写数据库还是先写 MQ”这个问题也是热搜词里被问爆的。我直接说结论对于大多数需要保证最终一致性的场景先写数据库再发消息是相对稳妥的顺序。因为数据库是业务的“事实来源”写入成功代表业务本身成功了消息只是后续动作的触发器。你先发消息再写数据库一旦写库失败下游已经去处理了一个根本不存在的业务问题会变得非常难以追踪。极端情况下如果想做得更严谨可以考虑事务发消息的模式比如把消息写入数据库表再通过一个后台任务扫描发送这个后面有机会再展开。5. 数据库常用工具、驱动与连接实战这个话题看着琐碎但在搜索词里占比奇高。大家平时遇到很多问题其实不是 SQL 不会写而是卡在工具连接、驱动安装、环境配置这些“最后一公里”上。5.1 用 Navicat 连接达梦或人大金仓别被默认库迷惑国产化浪潮来了之后很多人以前只用过 MySQL现在要连达梦第一反应是打开 Navicat 发现“咦没有达梦选项”。其实 Navicat 新版本已经支持达梦了选择数据库类型时找到“DM”即可。连接参数中主机、端口、用户名、口令照填有些版本需要在“高级”里选模式Schema对应 Oracle 用户的那个概念。有几个坑我帮你提前排掉达梦数据库默认会给安装用户带一坨系统库你连接上去后看列表会眼花一定要分清用户自己建的业务库和系统库别傻傻地在系统库里建表然后权限报错。另外达梦区分大小写是有讲究的默认情况下表名、字段名会被转成大写你在 SQL 里写小写可能查不到这个习惯跟 Oracle 很像习惯了就好。5.2 最折磨人的 Access 数据库 64 位驱动问题热搜词里有个非常典型的“请先安装 access 数据库 64 位系统驱动程序”这绝对是很多人碰到过的噩梦。Access 的驱动分 32 位和 64 位如果你的应用是 32 位的系统是 64 位的你装了 64 位驱动还是不认。反过来64 位应用去连 Access也要求装 64 位驱动但你的 Office 可能装的是 32 位它的驱动是 32 位两边又对不上。解决思路非常简单粗暴确认你最终要跑的进程是多少位的然后安装对应位数的驱动。如果你的应用是 32 位的强制装 64 位驱动是没用的。这里有个实用技巧不一定非要装微软官方的 Access 驱动可以用 “Microsoft Access Database Engine 2016 Redistributable” 对应位数版本。装完后再检查一下是不是“ Microsoft.ACE.OLEDB.12.0 ”或者“ Microsoft.ACE.OLEDB.16.0 ”这个 Provider 在列表里能看得见能看见基本就成功了。5.3 SQLite 数据库零配置的单文件神器SQLite 的热度搜出来也是常青树。它最大的优势是零配置文件整个数据库就是一个 .db 或 .sqlite 文件。用 Python 操作时只需要sqlite3.connect(test.db)就能创建一个库建表、插入、查询全部走标准 SQL。不过要注意SQLite 的并发写能力很弱同一时刻只允许一个进程写如果你做的是网站后端用户量稍微上来一点就不太合适。但如果是桌面软件、教学演示、临时数据处理它能帮你省掉一整台服务器的成本。我还经常拿它做开发环境的替身本地先用 SQLite 跑通逻辑上线再切 MySQL接口层代码几乎不用改。5.4 sqlplus 登录 Oracle 缓慢问题热搜词里有那么一条很长的“sqlplus 登录 oracle 数据库出现缓慢或者错误的原因可能很多”。这个我深有体会最常见的原因其实不是什么性能问题而是 Oracle 在登录时要解析 DNS反查客户端主机名。如果你的网络环境里 DNS 解析很慢甚至不通登录就能卡很久最后要么报错要么超时。解决办法在 Oracle 服务器的/etc/hostsLinux或hosts文件Windows里把本机主机名和 IP 对应关系写好可以极大程度减少解析等待。另外检查一下监听器配置里有没有使用主机名而非 IP用的 IP 会更直接。5.5 云数据库和托管数据库服务能省心多少现在很多人不太喜欢自建数据库直接用云数据库托管服务比如云厂商提供的 RDS 云数据库。这类服务的核心价值是把备份、高可用、监控、升级这些运维杂活都干了你只需要关心业务 SQL。但是自己玩和用托管差的其实是“掌控感”托管实例的网络隔离、参数调优很多是受限的有些特殊参数你想调还要开工单。所以我的建议是学习阶段在自己电脑上部署原生数据库把原理摸透正式项目优先用托管把精力留给业务。6. 那些日常踩过的坑常见问题排查与实战技巧这个部分我把自己这些年处理过的高频问题整理成了一个速查笔记希望对你有帮助。6.1 MySQL 里已有重复数据但想加唯一约束怎么办热搜里有个“mysql 设置唯一已经存在重复数据”这几乎是每个做数据治理的人都遇到过的问题。你想给某个字段加唯一索引但数据库报错说里面有重复值索引建不起来。思路很简单先用 SQL 查出来哪些组是重复的比如按姓名分组 having count(*)1然后把重复的旧数据清理掉只保留每组里 ID 最小或最新的那一条清干净之后再创建唯一索引。有些项目数据不能直接删那就把重复数据挪到一个备份表再回来建索引。6.2 数据库只能用 40 个核心是怎么回事搜索结果里还有个“数据库只能使用 40 个核心”这个一看就知道是 Oracle 的 CPU 使用权问题。Oracle 商业版是按处理器核心数计费的某些授权模式下限制使用 40 个核心服务器虽然 96 核但数据库只用到 40 核。这是产品许可证的授权策略不是配置错了。类似场景还会出现在 SQL Server 的版本里标准版对 CPU 核数也有上限。遇到这种问题不要纠结调参本质是许可证成本问题找业务评估要不要换更高授权版本或者改用开源数据库。6.3 select 里用了 group by 却报错热搜里有“数据库 group 不允许”。这个十有八九是 SQL 模式里ONLY_FULL_GROUP_BY惹的祸。在 MySQL 5.7 之后默认开启了ONLY_FULL_GROUP_BY意思是 select 的字段必须全部出现在 group by 里或者被聚合函数包裹。以前 MySQL 比较宽松你 select 一个不在 group by 里的字段它能猜着选一个。现在为了语义正确直接不允许。处理办法有两种一是改 SQL把所有要展示的字段都加到 group by 尾部二是临时关闭这个模式但不建议长期关因为宽松模式容易产出“看似正确但语义诡异”的结果。6.4 数据库死锁和慢 SQL 怎么快速定位数据库一旦出现大量死锁或者某条 SQL 明显变慢我常用的三板斧先看数据库当前的阻塞情况在 MySQL 里执行show engine innodb status看最近死锁记录再看慢查询日志把执行时间超过 1 秒的 SQL 抓出来最后用explain命令解析慢 SQL 的执行计划看它是不是走了全表扫描、没走索引或者索引选择性太差。这套流程走下来80% 的性能问题都能找到根因。6.5 不知道怎么选择数据库同步工具时怎么办同步工具在小公司经常被用来解决主从复制、灾备、异构迁移。如果只是同构同步比如 MySQL 主从直接用自带的 binlog 复制就好不用引入第三方。如果是异构同步比如 Oracle 同步到 MySQL或者 MySQL 同步到达梦这时候才需要考虑第三方同步工具。选工具的时候我优先看三点一是看它支持不支持源库的日志解析方式二是看它能不能在不停业务的情况下做初始化全量同步三是看它有没有比较成熟的冲突处理机制。千万别用一个不够成熟的工具跑核心同步链路出了问题数据不一致恢复起来极其痛苦。7. 数据库的学习路径和面试考点怎么学才能少走弯路热搜词里还有“数据库 知识点 概念”“数据库课程设计”“数据库面试题”说明很多人正处于学习阶段。我结合这些年的经历说说新手怎么学数据库效率最高。7.1 学习数据库的正确顺序很多新手上来就背面试题今天被问“聚簇索引和非聚簇索引的区别”明天被问“B 树是什么”说实话这些东西背了也容易忘因为它们是建立在实践之上的。我的建议顺序是这样的先在一台虚拟机上装一个 MySQL亲手把增删改查写一遍把数据类型、主键、索引、事务这些基础概念用起来。不用纠结版本5.7 或 8.0 都行。然后造一份假数据规模往百万级去搞去体验那条 SQL 是怎么慢下来的慢下来后再去建索引对比一下效果。接着去接触数据库的备份恢复。备份是很多人忽略但工作后最重要的部分你至少要亲手做一次备份再模拟把库删了再恢复回来。再往后再去研究锁、隔离级别、主从复制。有了前面的基础这些概念会好理解得多。最后才是去啃底层原理比如索引用 B 树而不红黑树、查询优化器怎么工作。这些东西是拿来给你的判断兜底的不是拿来背的。7.2 面试中最容易被追问到底的知识点按我面试候选人的习惯最常问的是这几个方向而且喜欢一问到底索引失效的场景。你说了“like % 开头不走索引”他会继续问“为什么”答案要走到优化器怎么评估成本、索引怎么存储这个深度。事务隔离级别和 MVCC 的关系。MySQL 的可重复读是怎么实现的undo log 和版本链怎么配合这部分一定要看源码级别的解读。主从复制的延迟问题。解释一下为什么从库会延迟怎么解决很多人只会说“提高配置”但面试官想听的是半同步复制、并行复制这些机制。一条 update 语句是怎么执行的。这能带出 redo log、binlog、两阶段提交是一个经典的主线题。7.3 把“数据库课程设计”做成加分项如果你是在校生正在做数据库课程设计我的忠告是千万不要只交一个“能跑”的界面。真正的加分项是表结构设计合理、有索引、有事务、有备份方案。哪怕你做一个最简单的图书管理系统能写清楚“为什么订单表要拆成主表和明细表”“为什么库存更新要用事务”就已经足够让别人看出你是懂数据库的而不是只会拖控件。8. 一个老运维的收尾建议写了这么多最后分享一点个人体会。数据库这个领域知识更新没有前端那么快它的核心从几十年前就是这些原理所以学起来“性价比”很高。但它的坑又特别深很多问题看起来毫无头绪比如“为什么查询突然变慢”“为什么数据突然不一致”排查到最后往往都是小细节。我在实际项目中养成了一个习惯每当遇到一个数据库报错不急着搜答案先自己尝试解释这个报错到底在说哪一层的什么问题。是驱动连不上是权限不够是锁冲突还是磁盘满了把问题归因到正确的层解决起来就很容易。这个习惯帮我省了很多时间也建议你从今天开始学数据库的时候就带着这个思路去碰问题。数据库的知识体系是典型的“越学越觉得自己不会”但你不必焦虑。把基础打牢把工具用熟遇到问题知道去哪里查、用什么手段查就已经比大多数人强了。如果你现在还是零基础别急着找一堆资料装一个 MySQL敲几行 SQL比看任何教程都管用。