简介本资源是一套系统化、阶梯式的MySQL与SQL学习资料包面向数据库初学者、Web开发入门者及后端工程师旨在帮助用户从零掌握关系型数据库核心技能。内容覆盖SQL基础语法、高级查询JOIN/子查询/视图、MySQL特有机制事务、触发器、权限管理及实战优化策略索引设计、查询调优、备份恢复并延伸至PHP/Python/Java等语言的集成应用。压缩包共41个文件含20份PDF教程如《MySQL数据类型精讲》《存储过程与函数》《触发器》等模块化笔记、19个配套SQL脚本按章节命名支持即学即练、2份Markdown说明文档总大小21.88MB结构清晰、理论与实操高度对应。目前已有220人下载学习资料兼具知识完整性与工程实用性可直接用于自学巩固、课程辅助或项目数据库搭建参考。1. MySQL 学习资料不是找“一堆PDF”而是搭一条能跑通 CRUD、撑住压测、查得出锁表的实战路径你搜“MySQL学习资料”页面弹出几百个链接带“零基础”“21天速成”“史上最全”的PDF、视频合集、网盘资源……但真正卡住你的从来不是“没资料”而是——建完库连不上Error 2002: Cant connect to local MySQL server through socket /tmp/mysql.sock写个 UPDATE 把整张表锁死业务报警才敢 kill 进程面试官问“主从延迟怎么查”你只能答“show slave status”——却说不清 Seconds_Behind_Master 为 NULL 到底是好是坏用 Navicat 导入 50 万行 CSV卡住不动日志里全是 “Packet too large”JDBC 连接串加了useSSLtrue生产环境 SSL handshake failed回滚又不敢动配置。这不是资料不够是资料没对齐「真实工作流」从 Linux 环境下亲手编译/安装/启动服务到用mysqldump做一致性备份再到用pt-query-digest分析慢查询、用sys.schema_table_lock_waits查谁在锁表——每一步都得亲手敲命令、看日志、改参数、验证结果。本文不推“神书”“神课”只给你一条可复现、可验证、可 debug 的学习路径以 MySQL 8.0.33当前 LTS 版本为锚点用 Docker 快速起环境、用真实 SQL 模拟高并发写入、用performance_schema和information_schema当黑匣子解剖器把“学习资料”变成你本地终端里可执行、可打断、可重试的一组命令和脚本。新手照着走能跑通增删改查备份恢复熟手能借这套路径快速定位连接异常、索引失效、事务阻塞三类高频故障。2. 用 Docker 搭一个“不翻车”的 MySQL 8.0 环境避开 socket 路径、权限、时区三大玄学坑别急着下载官网二进制包或 rpm 包——Linux 离线安装易缺依赖Windows 安装包默认绑服务名难调试Mac M 系列芯片又常因架构兼容性报错。Docker 是目前最稳的“开箱即用”方案但直接docker run mysql:8.0会踩一堆坑。下面这步是我给团队新人配环境时强制要求的最小可行命令2.1 一行命令启动带完整调试能力的 MySQL 容器docker run -d \ --name mysql8-dev \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDRoot123 \ -e TZAsia/Shanghai \ -v $(pwd)/mysql-data:/var/lib/mysql \ -v $(pwd)/mysql-conf:/etc/mysql/conf.d \ --restart unless-stopped \ -m 2g \ mysql:8.0.33 \ --max-connections200 \ --innodb-buffer-pool-size1G \ --default-time-zone08:00 \ --sql-modeSTRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION提示这条命令不是“抄了就能用”关键在参数组合逻辑——-v $(pwd)/mysql-data显式挂载数据目录避免容器删除后数据丢失-v $(pwd)/mysql-conf挂载自定义配置目录后续所有调参都在这里改不碰镜像内文件--max-connections200防止默认 151 连接数在压测时瞬间打满--innodb-buffer-pool-size1G设为宿主机内存 50%2G 容器内存这是 InnoDB 性能命脉--sql-mode关掉宽松模式让INSERT INTO t VALUES ()直接报错而非静默转成0000-00-00逼你写规范 SQL。2.2 创建可调试的配置文件让my.cnf不再是黑盒在当前目录新建mysql-conf/custom.cnf内容如下[mysqld] # 必开让 performance_schema 成为诊断核心 performance_schemaON performance_schema_instrument%ON performance_schema_consumer_events_statements_currentON performance_schema_consumer_events_statements_history_longON # 必开记录所有慢查询哪怕 0.1 秒 slow_query_logON slow_query_log_file/var/log/mysql/slow.log long_query_time0.1 # 必开让 show processlist 看清连接来源 show_compatibility_56OFF # 安全加固开发环境可关测试/生产必须开 require_secure_transportOFF # 开发暂关上线前必须设 ON default_authentication_plugincaching_sha2_password # 字符集统一避坑重点 character-set-serverutf8mb4 collation-serverutf8mb4_unicode_ci init_connectSET NAMES utf8mb4 skip-character-set-client-handshakeON参数说明performance_schema_instrument%ON是性能分析的开关总闸不开它sys库里所有视图如schema_table_lock_waits返回空long_query_time0.1把慢查询阈值压到 100ms否则你永远发现不了SELECT * FROM orders WHERE user_id ?缺索引的问题skip-character-set-client-handshakeON强制客户端用服务端字符集解决 Navicat 连接后存中文变??的经典翻车caching_sha2_password是 MySQL 8.0 默认认证插件JDBC 连接串必须加serverTimezoneGMT%2B8allowPublicKeyRetrievaltrue才能握手成功。2.3 验证环境是否真可用三步断言法# 1. 连通性断言确认端口监听且 root 可登录 mysql -h127.0.0.1 -P3306 -uroot -pRoot123 -e SELECT VERSION(); # 2. 字符集断言确认 utf8mb4 生效 mysql -h127.0.0.1 -P3306 -uroot -pRoot123 -e SHOW VARIABLES LIKE character_set%; | grep utf8mb4 # 3. 性能库断言确认 performance_schema 可查 mysql -h127.0.0.1 -P3306 -uroot -pRoot123 -e SELECT COUNT(*) FROM performance_schema.events_statements_current;逻辑说明第一步用-h127.0.0.1而非-hlocalhost强制走 TCP 协议绕过 Unix socket 路径问题Error 2002 根源第二步grep utf8mb4是硬校验比SHOW CREATE TABLE看单表字符集更可靠第三步查events_statements_current行数大于 0 才代表 performance_schema 真正启用——很多教程只写performance_schemaON却漏了instrument和consumer开关导致sys库视图全为空。3. 用真实业务场景驱动 SQL 训练从建库建表到主从同步每步都带验证命令别再背“CREATE DATABASE xxx CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci”这种孤立语句。真正的学习资料是把 SQL 放进业务流里用户注册 → 写订单 → 查历史 → 做统计 → 备份迁移。下面用电商订单场景带你走通全流程。3.1 建库建表为什么INT 5不等于TINYINT创建ecommerce库及orders表重点演示类型选择与默认值陷阱CREATE DATABASE IF NOT EXISTS ecommerce CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE ecommerce; CREATE TABLE orders ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, user_id INT UNSIGNED NOT NULL COMMENT 用户ID关联users表, amount DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 订单金额, status ENUM(created,paid,shipped,delivered,cancelled) NOT NULL DEFAULT created, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_user_status (user_id, status), INDEX idx_created_at (created_at) ) ENGINEInnoDB COMMENT订单主表;参数说明与避坑点BIGINT UNSIGNEDID 用无符号 bigint避免负数且支持更大范围超 21 亿DECIMAL(10,2)金额必须用 DECIMALFLOAT会导致0.1 0.2 ! 0.3ENUM状态字段用 ENUM 而非 VARCHAR节省空间且约束取值但注意ALTER TABLE 修改 ENUM 会锁表DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPMySQL 5.6.5 支持 DATETIME 自动更新比触发器更轻量关键避坑status ENUM(...) DEFAULT created—— 如果写成DEFAULT 0MySQL 会存成created第一个值但代码里读status 0就永远不匹配这是新手高频翻车点。3.2 插入与更新UPDATE语法里的锁与性能真相插入测试数据后模拟并发更新-- 插入 10 条测试订单 INSERT INTO orders (user_id, amount, status) VALUES (1001, 99.99, created), (1002, 199.99, paid), (1003, 299.99, shipped), (1004, 399.99, delivered), (1005, 499.99, cancelled); -- 模拟“支付成功”更新只改 status 和 updated_at UPDATE orders SET status paid, updated_at NOW() WHERE id 1;为什么这个 UPDATE 很快因为WHERE id 1走主键索引InnoDB 只锁住这一行Record Lock但如果写成UPDATE orders SET status paid WHERE user_id 1001呢user_id有索引但若该用户有多笔订单就会锁住所有匹配行Next-Key Lock甚至可能锁住间隙Gap Lock——这就是“UPDATE 语句锁表”的根源。验证方法新开一个终端执行SELECT * FROM performance_schema.data_locks\G能看到锁类型RECORD、GAP、NEXT-KEY和被锁对象。3.3 主从同步实操用mysqldumpCHANGE MASTER TO搭建最小可用链路假设你已有一个主库上面的mysql8-dev现在起一个从库容器并同步# 1. 启动从库容器注意端口不能冲突用 3307 docker run -d \ --name mysql8-slave \ -p 3307:3306 \ -e MYSQL_ROOT_PASSWORDRoot123 \ -v $(pwd)/mysql-slave-data:/var/lib/mysql \ mysql:8.0.33 \ --server-id2 \ --log-binmysql-bin \ --read_onlyON # 2. 从主库导出数据含 GTID 信息 docker exec mysql8-dev sh -c mysqldump -uroot -pRoot123 --all-databases --master-data2 --single-transaction --set-gtid-purgedON /tmp/full.sql # 3. 将 dump 文件复制到从库容器并导入 docker cp mysql8-dev:/tmp/full.sql ./ docker exec -i mysql8-slave mysql -uroot -pRoot123 full.sql # 4. 在从库上执行 CHANGE MASTER TO关键用 SHOW MASTER STATUS 获取 binlog 位置 # 先在主库查docker exec mysql8-dev mysql -uroot -pRoot123 -e SHOW MASTER STATUS\G # 输出示例File: mysql-bin.000001, Position: 154, GTID_Set: 00000000-0000-0000-0000-000000000000:1-10 docker exec -i mysql8-slave mysql -uroot -pRoot123 EOF CHANGE MASTER TO MASTER_HOSThost.docker.internal, MASTER_PORT3306, MASTER_USERroot, MASTER_PASSWORDRoot123, MASTER_AUTO_POSITION1; START SLAVE; EOF # 5. 验证同步状态 docker exec mysql8-slave mysql -uroot -pRoot123 -e SHOW SLAVE STATUS\G | grep -E (Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master)关键参数说明--server-id2主从必须不同 ID否则复制进程拒绝启动--log-binmysql-bin从库也开 binlog方便级联复制--read_onlyON防止误操作写从库但 SUPER 用户仍可写需配合super_read_onlyONMASTER_AUTO_POSITION1启用 GTID 复制比传统 fileposition 更可靠自动处理 binlog 切换host.docker.internalDocker Desktop 提供的宿主机别名Linux 需用--add-host host.docker.internal:host-gateway。4. 排查高频故障Error 2002、SSL 连接失败、锁表杀不死的 5 个血泪经验别等线上炸了才翻文档。这 5 个问题我带过的 12 个新人里10 个在第一周就撞上。每条都按「现象 → 原因 → 解决」写透不讲虚的。4.1 Error 2002: Cant connect to local MySQL server through socket /tmp/mysql.sock现象mysql -uroot -p报错但docker ps显示容器运行中telnet 127.0.0.1 3306通。原因MySQL 客户端默认走 Unix socket/tmp/mysql.sock而 Docker 容器内 socket 文件在/var/run/mysqld/mysqld.sock且宿主机没映射该路径。解决临时加-h127.0.0.1强制走 TCPmysql -h127.0.0.1 -uroot -p永久在宿主机~/.my.cnf加[client]段写host127.0.0.1根治Docker 启动时加-v /tmp/mysql.sock:/var/run/mysqld/mysqld.sock不推荐权限易错。4.2 JDBC 连接报SSL handshake failed加useSSLfalse又被警告不安全现象Spring Boot 项目启动报PKIX path building failed加?useSSLfalse启动成功但控制台刷红色警告。原因MySQL 8.0 默认要求 SSL但自签名证书未导入 JVM truststoreuseSSLfalse关闭加密不符合生产安全规范。解决正确做法生成 CA 证书 服务端证书配置 MySQLssl-ca,ssl-cert,ssl-key开发快捷法用mysql_ssl_rsa_setup生成证书再在连接串加?useSSLtrueserverTimezoneGMT%2B8allowPublicKeyRetrievaltrue注意allowPublicKeyRetrievaltrue仅限开发生产必须用serverRSAPublicKeyFile指定公钥文件。4.3SHOW PROCESSLIST里看到Killed状态但SELECT还在跑现象执行KILL 123后SHOW PROCESSLIST显示CommandKilled但StateSending data持续 10 分钟。原因KILL只是发中断信号InnoDB 需完成当前事务的 undo log 回滚大事务回滚极慢。解决立即查SELECT * FROM information_schema.INNODB_TRX\G看TRX_STATEROLLING BACK的事务用SELECT * FROM performance_schema.events_statements_current WHERE THREAD_ID 123\G看 SQL终极办法重启 MySQLdocker restart mysql8-dev但会丢未提交事务。4.4mysqldump导出大表失败Got error: 2020: Got packet bigger than max_allowed_packet bytes现象导出 1GB 表时中断日志报 packet too large。原因max_allowed_packet默认 4MBmysqldump生成的 INSERT 语句超长。解决临时mysqldump --max-allowed-packet512M ...永久在my.cnf的[mysqld]和[client]段都加max_allowed_packet512M更优用--tab参数导出为文本文件mysqldump --tab/tmp ...再用mysqlimport导入绕过 packet 限制。4.5 Navicat 连接后SELECT返回中文乱码??但命令行正常现象Navicat 执行SELECT name FROM users显示??而docker exec mysql8-dev mysql -e SELECT name FROM users正常。原因Navicat 客户端字符集未设为utf8mb4或连接串未指定charsetutf8mb4。解决Navicat 连接属性 → 高级 → 勾选“使用 MySQL 字符集”字符集选utf8mb4或连接串加;charsetutf8mb4如jdbc:mysql://127.0.0.1:3306/test?charsetutf8mb4根本服务端my.cnf已配skip-character-set-client-handshakeON强制客户端服从服务端设置。5. 用sys库和pt-query-digest定位性能瓶颈把“慢查询”从日志变成可操作的 SQL学 MySQL 最大的幻觉是以为“开了 slow_query_log”就万事大吉。真正的难点在于日志里 1000 行慢 SQL哪 3 行该优先优化为什么加了索引还是慢答案不在文档里在sys库的视图和 Percona Toolkit 的pt-query-digest里。5.1 用sys.statement_analysis找出“最伤数据库”的 5 条 SQL先确保 slow log 已开启见 2.2 节然后执行-- 查看最近 1 小时最耗资源的 SQL按平均响应时间排序 SELECT query, db, exec_count, avg_timer_wait/1000000000 AS avg_time_sec, rows_sent_avg, rows_examined_avg, digest_text FROM sys.statement_analysis WHERE last_seen DATE_SUB(NOW(), INTERVAL 1 HOUR) ORDER BY avg_timer_wait DESC LIMIT 5\G输出解读示例query: SELECT * FROM orders WHERE user_id ? AND status ?avg_time_sec: 2.3rows_examined_avg: 15000digest_text: SELECT * FROMordersWHEREuser_id ? ANDstatus ?结论该 SQL 平均查 1.5 万行才返回几条明显缺复合索引。应建INDEX idx_user_status (user_id, status)—— 这正是 3.1 节建表时已加的索引说明业务代码没走索引可能是user_id传了字符串1001而字段是 INT触发隐式转换。5.2 用pt-query-digest分析慢日志比mysqldumpslow多 3 倍有效信息安装 Percona ToolkitUbuntuwget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb sudo dpkg -i percona-release_latest.$(lsb_release -sc)_all.deb sudo apt update sudo apt install percona-toolkit分析慢日志# 先确认慢日志路径在容器内 docker exec mysql8-dev mysql -uroot -pRoot123 -e SHOW VARIABLES LIKE slow_query_log_file; # 输出/var/log/mysql/slow.log # 复制日志到宿主机 docker cp mysql8-dev:/var/log/mysql/slow.log ./slow.log # 用 pt-query-digest 分析关键参数--limit 10 取 Top10--review 把结果存入表 pt-query-digest --limit 10 --review h127.0.0.1,Dtest,tquery_review slow.logpt-query-digest输出核心字段Rank排名Query IDSQL 指纹去除了字面值相同逻辑 SQL 归为一类Response time总耗时 平均耗时Calls执行次数R/Call每次响应时间V/M变异性标准差/平均值值越大说明性能越不稳定如缓存失效导致ItemSQL 摘要如SELECT * FROM orders WHERE user_id ?。实战技巧关注V/M 1的 SQL这类往往是缓存穿透或索引失效的征兆R/Call高但Calls低的优先加索引R/Call低但Calls极高的优先合并请求或加缓存。5.3 用sys.schema_table_lock_waits实时抓“谁在锁表”当SHOW PROCESSLIST看到一堆Waiting for table metadata lock别急着KILL-- 查当前所有锁等待关系 SELECT object_name AS table_name, waiting_pid, waiting_query, blocking_pid, blocking_query FROM sys.schema_table_lock_waits\G输出示例table_name: orderswaiting_pid: 123waiting_query: UPDATE orders SET status shipped WHERE id 100blocking_pid: 456blocking_query: ALTER TABLE orders ADD COLUMN remark VARCHAR(255)结论ALTER TABLE操作需要 MDLMetadata Lock排他锁阻塞了所有 DML。解决方案紧急KILL 456但ALTER TABLE会回滚大表可能耗时长期用pt-online-schema-change在线改表不锁表。5.4 用information_schema.INNODB_METRICS监控 InnoDB 内部压力SHOW ENGINE INNODB STATUS太难读INNODB_METRICS提供结构化指标-- 查 InnoDB 缓冲池命中率低于 95% 需扩容 buffer pool SELECT NAME, COUNT, COMMENT FROM information_schema.INNODB_METRICS WHERE NAME IN (buffer_pool_hit_rate, buffer_pool_reads, buffer_pool_read_requests)\G -- 查当前未刷新脏页数超过 1000 需关注 SELECT NAME, COUNT, COMMENT FROM information_schema.INNODB_METRICS WHERE NAME buffer_pool_pages_dirty\G关键阈值buffer_pool_hit_rate理想 99% 95% 说明 buffer pool 太小或查询太随机buffer_pool_pages_dirty持续 1000 表明刷脏页跟不上写入速度可能引发FLUSH延迟innodb_row_lock_waits每秒 10 次锁等待说明并发写入设计有问题。我带团队做压测时习惯把这四类查询sys.statement_analysis、sys.schema_table_lock_waits、INNODB_METRICS、pt-query-digest写成一个check-mysql-health.sh脚本每次上线前跑一遍输出 HTML 报告。不是为了炫技而是让“性能优化”从玄学变成可量化的 checklist——比如“buffer_pool_hit_rate从 92% 提到 98%”比“优化了索引”更有说服力。希望帮到你。本文还有配套的精品资源点击获取
