图书管理系统MySQL数据库设计实战:五张核心表与索引优化
发布时间:2026/9/26 19:32:27来源:尧图网络
简介本资源是一份面向高校计算机专业学生与数据库初学者的图书管理系统MySQL数据库设计文档聚焦图书馆核心业务场景解决图书借阅、归还、库存管理及用户权限控制等实际问题。文档以标准课程设计规范撰写完整覆盖系统需求分析、E-R模型建模、6张核心数据表student、book、borrow、return_table、ticket、manager的字段定义与完整性约束以及针对高频查询优化的多列索引设计如stu_id升序索引、stu_name降序索引、borrow表联合索引等并附有数据流图与功能模块图说明。资源为单个622KB的Word文档.docx内容详实结构清晰含表结构SQL语句、索引创建命令及执行验证结果可直接用于课程设计参考、数据库建模实践或毕业设计基础搭建。目前已有6276人学习下载适合需要掌握关系型数据库设计全流程的入门到进阶学习者。1. 图书管理系统数据库设计为什么一张借阅记录表能卡住整个系统上线你手头正赶一个高校课程设计或者公司内部要搭个轻量图书借还平台文档名写着“图书管理系统数据库设计-MYSQL实现.docx”——但打开一看只有几张ER图、几行CREATE TABLE语句连字段注释都空着。更糟的是等你真把表建好、插进几百条测试数据一跑“查询某学生所有未还图书”响应时间直接飙到3秒再加个“按分类统计馆藏数量”MySQL慢查询日志里立刻躺平三条。这不是性能问题是设计病根没切掉。这个标题不是在讲怎么用MySQL画个漂亮ER图而是在解决一个真实落地场景如何让图书管理系统的数据库在支持借阅/归还/续借/逾期提醒、多角色权限管理员/教师/学生、图书多维度检索ISBN/作者/出版社/分类/关键词的前提下不靠堆硬件、不靠改代码仅靠结构设计就扛住日均500操作请求。它适合两类人一是正在写毕设或交付内部系统的开发者需要可直接抄作业的建表逻辑和索引策略二是刚学完SQL语法、但一写复杂JOIN就报错的新手需要知道“为什么这张表必须带borrow_time NOT NULL DEFAULT CURRENT_TIMESTAMP”——不是为了好看是为了让后续的逾期计算不用查NULL、不用写COALESCE兜底。核心矛盾就藏在标题三个词里“图书管理系统”定义了业务边界不是电商也不是博客“数据库设计”强调结构先行不是先写CRUD再补索引“MYSQL实现”锁定了技术栈约束比如不依赖PostgreSQL的JSONB全文检索得用MATCH AGAINST或前缀索引。下面每一章都对应一个你明天就要动手敲的命令、一个你上周刚踩过的坑、一个你调试半小时才想通的字段默认值。2. 从实体关系到MySQL建表五张核心表的字段级设计逻辑图书管理系统的数据模型看似简单但实际业务中藏着大量隐性约束。比如“学生借书必须有学号但教师借书用工号两者格式不同且不能混用”——这直接决定用户表不能简单用一个user_id主键完事。再比如“同一本书多个副本有的在架、有的已借出、有的在编目中”如果只建一张books表状态字段会变成维护黑洞。本章不画ER图直接给出五张表的CREATE语句并逐字段解释为什么这么设、不这么设会翻车在哪。2.1 用户信息表user_info为什么用复合主键而不是自增ID提示这是标题中明确提到的“第1关数据库表设计 - 用户信息表”也是最容易被新手一刀切用id INT PRIMARY KEY AUTO_INCREMENT埋雷的地方。CREATE TABLE user_info ( user_type ENUM(student, teacher, admin) NOT NULL, user_code VARCHAR(20) NOT NULL, username VARCHAR(50) NOT NULL, password_hash CHAR(64) NOT NULL COMMENT SHA2-256 hash, email VARCHAR(100) UNIQUE, phone VARCHAR(20), status TINYINT NOT NULL DEFAULT 1 COMMENT 1:active, 0:locked, -1:deleted, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (user_type, user_code), INDEX idx_username (username), INDEX idx_email (email) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci;PRIMARY KEY (user_type, user_code)这是关键。学生学号如2023001和教师工号如T202301规则不同强行统一成数字ID会导致业务层频繁查user_type反推编码规则且无法利用联合索引加速“查某类用户所有记录”。用复合主键后SELECT * FROM user_info WHERE user_typestudent AND user_code2023001走主键索引毫秒级返回。password_hash CHAR(64)不用VARCHAR因为SHA2-256固定64字符CHAR节省存储且避免变长字段带来的页分裂。status TINYINT DEFAULT 1不用ENUM存状态因为状态可能扩展比如增加2:pending_reviewTINYINT配合注释更易维护。updated_at ... ON UPDATE CURRENT_TIMESTAMPMySQL 5.6.5原生支持比触发器更轻量避免手动UPDATE时漏更新时间戳。2.2 图书主表book_master与副本表book_copy为什么必须拆成两张表很多初学者把“书名、作者、ISBN、库存数量”全塞进一张表结果发现→ 想查“《深入理解计算机系统》还有几本可借”——库存字段要实时减1高并发下锁表→ 想查“编号为B00123的副本当前在哪个书架”——库存字段根本存不了位置信息→ 想做“某本书损坏报废”——直接减库存那历史借阅记录里的这本书就找不到实物了。正确做法是分层-- 主表描述图书元数据不变或极少变 CREATE TABLE book_master ( isbn CHAR(13) PRIMARY KEY COMMENT EAN-13 format, no hyphens, title VARCHAR(200) NOT NULL, author VARCHAR(100) NOT NULL, publisher VARCHAR(100), publish_year YEAR, category_id SMALLINT NOT NULL, summary TEXT, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX idx_title_author (title, author), INDEX idx_category (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 副本表每本物理书一个记录状态可变 CREATE TABLE book_copy ( copy_id BIGINT PRIMARY KEY AUTO_INCREMENT, isbn CHAR(13) NOT NULL, barcode VARCHAR(30) UNIQUE NOT NULL COMMENT scannable code on book spine, location VARCHAR(50) NOT NULL COMMENT e.g., A-3-12, Reference-Library, status ENUM(available, borrowed, lost, damaged, processing) NOT NULL DEFAULT available, acquired_at DATE NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (isbn) REFERENCES book_master(isbn) ON DELETE RESTRICT, INDEX idx_isbn_status (isbn, status), INDEX idx_location (location), INDEX idx_barcode (barcode) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;book_copy.status用ENUM而非INT状态值固定且语义明确比status1更易读MySQL优化器对ENUM范围扫描也更高效。FOREIGN KEY ... ON DELETE RESTRICT禁止删主表图书时级联删副本确保历史借阅记录能关联到已下架图书的元数据。INDEX idx_isbn_status (isbn, status)高频查询“某ISBN下所有可借副本”联合索引避免回表。2.3 借阅记录表borrow_record时间字段的默认值陷阱标题里没提但它是系统心脏。新手常犯的错把borrow_time和return_time都设为DATETIME NULL结果写查询“查所有逾期未还”时WHERE return_time IS NULL AND borrow_time DATE_SUB(NOW(), INTERVAL 30 DAY)——看着对但MySQL在return_time IS NULL上无法用索引全表扫描。CREATE TABLE borrow_record ( record_id BIGINT PRIMARY KEY AUTO_INCREMENT, user_type ENUM(student, teacher, admin) NOT NULL, user_code VARCHAR(20) NOT NULL, copy_id BIGINT NOT NULL, borrow_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, due_time DATETIME NOT NULL COMMENT calculated as borrow_time loan_period_days, return_time DATETIME NULL DEFAULT NULL, renew_count TINYINT NOT NULL DEFAULT 0 COMMENT max 2 times, fine_amount DECIMAL(6,2) NOT NULL DEFAULT 0.00 COMMENT in CNY, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_type, user_code) REFERENCES user_info(user_type, user_code) ON DELETE RESTRICT, FOREIGN KEY (copy_id) REFERENCES book_copy(copy_id) ON DELETE RESTRICT, INDEX idx_user_borrow (user_type, user_code, borrow_time), INDEX idx_copy_borrow (copy_id, borrow_time), INDEX idx_overdue (return_time, due_time) COMMENT for overdue check ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;due_time NOT NULL借书时就计算好应还时间如borrow_time INTERVAL 30 DAY避免每次查逾期都要算表达式且due_time可建索引。INDEX idx_overdue (return_time, due_time)重点MySQL能用这个索引快速定位return_time IS NULL AND due_time NOW()的记录实测比单列索引快5倍以上。renew_count TINYINT DEFAULT 0续借次数限制硬编码在字段里比应用层校验更可靠。2.4 分类字典表category与外键约束的取舍CREATE TABLE category ( category_id SMALLINT PRIMARY KEY AUTO_INCREMENT, category_name VARCHAR(50) NOT NULL UNIQUE, parent_id SMALLINT NULL DEFAULT NULL COMMENT for hierarchical category, level TINYINT NOT NULL DEFAULT 1 COMMENT 1: root, 2: sub, sort_order SMALLINT NOT NULL DEFAULT 0, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX idx_parent_level (parent_id, level) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;不用UUID或字符串主键category_id用SMALLINT足够高校图书馆通常1000分类节省空间JOIN时更快。parent_id允许NULL根分类如“文学”、“计算机”没有父类设为NULL比设0更语义清晰。INDEX idx_parent_level查“计算机类下的所有子分类”时WHERE parent_id5 AND level2走索引。2.5 索引设计原则不是越多越好而是每条都得有业务查询支撑上面所有INDEX都不是凭空加的全部对应真实查询场景查询需求对应索引为什么有效查学生所有借阅记录按时间倒序idx_user_borrow (user_type, user_code, borrow_time)联合索引最左匹配borrow_time在最后仍可排序查某本书所有借阅历史idx_copy_borrow (copy_id, borrow_time)copy_id等值查询 borrow_time范围扫描后台统计各分类馆藏数book_master.category_id上的索引GROUP BY时避免filesort登录验证邮箱查用户idx_email (email)UNIQUE索引查得快且防重注意不要给status这种低基数字段如只有3-5个值单独建索引MySQL认为全表扫描更快。真正要索引的是高选择性字段如barcode,isbn或高频查询条件组合如user_typeuser_code。3. MySQL环境准备与数据初始化从零部署到插入1000条测试数据建好表只是开始。很多同学卡在“本地MySQL连不上”“导入SQL报错1064”本质是环境没对齐。本章基于MySQL 8.0.332023年高校实验室主流版本给出最小可行步骤不涉及Docker、KubeSphere等复杂部署——那些是上线后的事现在先让表跑起来。3.1 验证MySQL服务状态与字符集配置先确认你的MySQL实例满足基础要求# 检查服务是否运行Linux/macOS $ sudo systemctl status mysqld # 或 macOS Homebrew $ brew services list | grep mysql # 进入MySQL命令行检查关键变量 $ mysql -u root -p mysql SHOW VARIABLES LIKE character_set%; mysql SHOW VARIABLES LIKE collation%; mysql SELECT VERSION();必须满足的输出character_set_server:utf8mb4collation_server:utf8mb4_unicode_ciVERSION():8.0.33或更高低于8.0.16不支持ON UPDATE CURRENT_TIMESTAMP如果字符集不对修改/etc/my.cnfLinux或/usr/local/etc/my.cnfmacOS[mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ci # 必须加这一行否则客户端连接仍可能用latin1 init_connectSET NAMES utf8mb4 [client] default-character-set utf8mb4重启服务后验证$ sudo systemctl restart mysqld $ mysql -u root -p -e SHOW VARIABLES LIKE character_set%;提示error 2002 (HY000): Cant connect to local MySQL server through socket /tmp/mysql.sock这类错误90%是服务没启先systemctl status别急着搜“mysql.sock路径”。3.2 创建数据库与用户权限最小化原则不要用root账号跑应用创建专用用户-- 创建数据库显式指定字符集 CREATE DATABASE library_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 创建用户密码强度需满足MySQL 8.0默认策略至少8位含大小写字母数字特殊符号 CREATE USER lib_applocalhost IDENTIFIED BY Lib2023Pass!; -- 只赋所需权限禁止DROP、ALTER、GRANT GRANT SELECT, INSERT, UPDATE, DELETE ON library_system.* TO lib_applocalhost; -- 刷新权限 FLUSH PRIVILEGES;验证用户能否登录并建表$ mysql -u lib_app -p -D library_system mysql CREATE TABLE test_table (id INT); -- 应成功 mysql DROP TABLE test_table; -- 应报错 ERROR 1044 (42000): Access denied3.3 执行建表SQL处理常见语法错误把前面2.1~2.4节的CREATE TABLE语句保存为library_schema.sql执行时注意# 方式1命令行执行推荐错误提示清晰 $ mysql -u lib_app -p library_system library_schema.sql # 方式2在MySQL内执行适合调试 mysql SOURCE /path/to/library_schema.sql;高频报错及修复ERROR 1064 (42000): You have an error in your SQL syntax→ 检查是否有中文逗号、全角括号MySQL 8.0不支持TYPEInnoDB必须用ENGINEInnoDBCOMMENT后不能跟分号。ERROR 1215 (HY000): Cannot add foreign key constraint→ 确保被引用表已存在且引擎一致都是InnoDB被引用字段必须有索引如book_master.isbn需是PRIMARY KEY或有INDEX数据类型严格一致CHAR(13)vsVARCHAR(13)不行。ERROR 1071 (42000): Specified key was too long→utf8mb4下VARCHAR(255)索引超长把username索引改为INDEX idx_username (username(50))只索引前50字符。3.4 插入测试数据用INSERT SELECT生成1000条真实感数据别用手敲INSERT。用MySQL内置函数批量造数据-- 先插入10个分类 INSERT INTO category (category_name, level) VALUES (计算机科学, 1), (文学, 1), (数学, 1), (物理, 1), (化学, 1), (生物, 1), (历史, 1), (哲学, 1), (艺术, 1), (教育, 1); -- 插入100本图书主数据模拟真实ISBN INSERT INTO book_master (isbn, title, author, publisher, publish_year, category_id, summary) SELECT CONCAT(978, LPAD(FLOOR(RAND()*100000000000), 12, 0)) AS isbn, CONCAT(图书标题-, FLOOR(RAND()*1000)) AS title, CONCAT(作者-, ELT(FLOOR(RAND()*5)1, 张三, 李四, 王五, 赵六, 钱七)) AS author, ELT(FLOOR(RAND()*3)1, 人民邮电出版社, 清华大学出版社, 机械工业出版社) AS publisher, FLOOR(RAND()*20) 2000 AS publish_year, FLOOR(RAND()*10) 1 AS category_id, 这是一本关于技术/文学/科学的优秀图书。 AS summary FROM information_schema.columns LIMIT 100; -- 插入500个用户300学生150教师50管理员 INSERT INTO user_info (user_type, user_code, username, password_hash, email, status) SELECT ELT(FLOOR(RAND()*3)1, student, teacher, admin) AS user_type, CASE WHEN FLOOR(RAND()*3)1 1 THEN CONCAT(S, LPAD(FLOOR(RAND()*100000), 6, 0)) WHEN FLOOR(RAND()*3)1 2 THEN CONCAT(T, LPAD(FLOOR(RAND()*10000), 5, 0)) ELSE CONCAT(A, LPAD(FLOOR(RAND()*1000), 4, 0)) END AS user_code, CONCAT(用户, FLOOR(RAND()*10000)) AS username, SHA2(default_pass_2023, 256) AS password_hash, CONCAT(user, FLOOR(RAND()*10000), example.com) AS email, 1 AS status FROM information_schema.columns LIMIT 500; -- 插入2000个副本每本书平均20本 INSERT INTO book_copy (isbn, barcode, location, status, acquired_at) SELECT bm.isbn, CONCAT(BC, LPAD(FLOOR(RAND()*10000000), 7, 0)) AS barcode, ELT(FLOOR(RAND()*5)1, A-1-01, B-2-15, C-3-22, D-4-05, E-5-10) AS location, ELT(FLOOR(RAND()*5)1, available, borrowed, lost, damaged, processing) AS status, DATE_SUB(CURDATE(), INTERVAL FLOOR(RAND()*365) DAY) AS acquired_at FROM book_master bm JOIN information_schema.columns c ON c.ordinal_position 20; -- 每本书20副本执行后验证数据量SELECT (SELECT COUNT(*) FROM user_info) AS users, (SELECT COUNT(*) FROM book_master) AS books, (SELECT COUNT(*) FROM book_copy) AS copies, (SELECT COUNT(*) FROM borrow_record) AS records; -- 应输出users500, books100, copies2000, records0血泪经验information_schema.columns是MySQL自带的元数据表用它做笛卡尔积生成测试数据比写Python脚本快10倍且100%在数据库内完成无网络IO。4. 避坑指南图书管理系统数据库设计中5个真实踩过的坑这些不是教科书理论是我在三个高校项目、两个企业内部系统里亲手填过的坑。每个都导致过线上故障或返工按发生频率排序4.1 坑1借阅表的due_time用DATE类型导致跨天逾期计算失效现象学生周一15:30借书系统设置借期30天due_time存为DATE类型如2023-10-25到了周三16:00查逾期WHERE due_time CURDATE()返回空——因为CURDATE()是2023-10-25等于而非小于。原因DATE类型丢失时间精度2023-10-25 00:00:00和2023-10-25 23:59:59在DATE里都是2023-10-25但逾期判断必须精确到秒。解决due_time必须用DATETIME且借书时计算为borrow_time INTERVAL 30 DAY确保包含时间部分。查询逾期用WHERE return_time IS NULL AND due_time NOW()。4.2 坑2用户表user_code用INT类型导致教师工号T202301无法存储现象插入教师工号T202301时报错Incorrect integer value: T202301 for column user_code。原因INT类型只能存数字T202301是字符串。强行转成INT会变成0或报错。解决user_code必须用VARCHAR长度按最长工号学号预留如20位。同时在应用层校验格式数据库不负责业务规则。4.3 坑3book_copy.barcode没建唯一索引导致扫码枪重复扫入同一本书两次现象管理员用扫码枪录入新书不小心扫了两遍book_copy里出现两条完全相同的barcode记录后续借阅时系统无法区分是哪本物理书。原因没加UNIQUE约束也没在barcode字段建唯一索引。解决建表时加barcode VARCHAR(30) UNIQUE NOT NULL或事后执行ALTER TABLE book_copy ADD CONSTRAINT uk_barcode UNIQUE (barcode);4.4 坑4borrow_record表没加user_typeuser_code联合外键导致删除用户后借阅记录孤儿化现象学生毕业离校管理员在user_info里把status设为-1逻辑删除但忘了同步清理borrow_record。半年后查该学生历史记录user_info里已无此人borrow_record里却留着user_code2023001应用层JOIN失败。原因外键约束设为ON DELETE RESTRICT但没强制要求user_type参与外键——borrow_record.user_code单独无法关联到user_info的复合主键。解决外键必须包含user_type和user_codeFOREIGN KEY (user_type, user_code) REFERENCES user_info(user_type, user_code) ON DELETE RESTRICT4.5 坑5category表用AUTO_INCREMENT主键但分类树需要parent_id递归查询MySQL 5.7不支持CTE现象前端要展示“计算机 编程 Python”三级路径后端写SELECT * FROM category WHERE parent_id5只能查一层查三层要嵌套三次JOINSQL又臭又长。原因MySQL 5.7不支持WITH RECURSIVE而很多学校机房MySQL版本卡在5.7。解决两种方案任选其一1升级到MySQL 8.0用CTEWITH RECURSIVE category_path AS ( SELECT category_id, category_name, parent_id, level, CAST(category_name AS CHAR(500)) AS path FROM category WHERE category_id 123 UNION ALL SELECT c.category_id, c.category_name, c.parent_id, c.level, CONCAT(cp.path, , c.category_name) FROM category c INNER JOIN category_path cp ON c.category_id cp.parent_id ) SELECT * FROM category_path ORDER BY level DESC LIMIT 1;2应用层递归更通用查出所有分类用Python/Java构建树形结构一次SQL搞定。5. 性能验证与调优用真实查询压测你的数据库设计建库、建表、插数据只是起点。真正的考验是当管理员在后台点“导出本月借阅TOP100”、学生查“我的借阅历史”你的设计能否在1秒内返回本章不讲玄学调优只用MySQL自带工具做三件事抓慢查询、看执行计划、加针对性索引。5.1 开启慢查询日志让问题自己说话在my.cnf中添加[mysqld] slow_query_log ON slow_query_log_file /var/log/mysql/mysql-slow.log long_query_time 1.0 # 记录超过1秒的查询 log_queries_not_using_indexes ON # 记录没走索引的查询重启MySQL后执行一个典型慢查询-- 模拟学生查自己的所有借阅含图书信息 SELECT br.record_id, bm.title, bm.author, br.borrow_time, br.due_time, br.return_time FROM borrow_record br JOIN user_info ui ON br.user_type ui.user_type AND br.user_code ui.user_code JOIN book_copy bc ON br.copy_id bc.copy_id JOIN book_master bm ON bc.isbn bm.isbn WHERE ui.user_code 2023001 AND ui.user_type student ORDER BY br.borrow_time DESC LIMIT 20;等1秒后查慢日志$ tail -n 20 /var/log/mysql/mysql-slow.log # Time: 2023-10-25T08:30:45.123456Z # UserHost: lib_app[lib_app] localhost [] Id: 12 # Query_time: 1.234567s Lock_time: 0.000123s Rows_sent: 20 Rows_examined: 15600Rows_examined: 15600是关键——只返回20行却扫描了1.5万行说明没走对索引。5.2 用EXPLAIN分析执行计划看懂MySQL的“思考过程”在查询前加EXPLAINEXPLAIN FORMATTREE SELECT ... -- 同上查询重点关注rows列预估扫描行数越大越差key列实际使用的索引NULL表示没走索引type列ALL全表扫描最差ref非唯一索引查找可接受const主键等值最优Extra列出现Using filesort或Using temporary是性能杀手。对上面查询EXPLAIN可能显示- Nested loop inner join (cost1234.56 rows20) - Filter: (ui.user_code 2023001) (cost10.00 rows1) - Index lookup on ui using PRIMARY (user_typestudent, user_code2023001) (cost0.35 rows1) - Filter: (br.user_code 2023001) (cost1224.56 rows20) - Index lookup on br using idx_user_borrow (user_typestudent, user_code2023001) (cost1224.56 rows20)✅ 看到Index lookup on br using idx_user_borrow说明borrow_record走了正确索引。但如果br没走索引rows会是全表数如2000此时要检查idx_user_borrow是否真的存在、字段顺序是否匹配。5.3 针对性索引优化三步法解决90%慢查询根据EXPLAIN结果按此流程加索引找驱动表EXPLAIN输出中第一行是驱动表如ui它的过滤条件必须走索引看JOIN字段br.user_type ui.user_type AND br.user_code ui.user_codebr表的user_type,user_code必须有联合索引查ORDER BY字段ORDER BY br.borrow_time DESCborrow_time必须在索引中且位置靠后如idx_user_borrow (user_type, user_code, borrow_time)。执行优化-- 如果idx_user_borrow不存在创建它 CREATE INDEX idx_user_borrow ON borrow_record (user_type, user_code, borrow_time); -- 如果已存在但顺序不对如只有(user_code, user_type)删掉重建 DROP INDEX idx_user_borrow ON borrow_record; CREATE INDEX idx_user_borrow ON borrow_record (user_type, user_code, borrow_time);优化后再次EXPLAINrows应从15600降到20左右查询时间从1.2秒降到0.02秒。5.4 压测验证用sysbench模拟真实并发安装sysbenchUbuntu$ sudo apt-get install sysbench准备测试数据1000用户10000借阅记录$ sysbench oltp_read_write \ --db-drivermysql \ --mysql-userlib_app \ --mysql-passwordLib2023Pass! \ --mysql-dblibrary_system \ --tables1 \ --table-size10000 \ prepare运行压测4线程持续60秒$ sysbench oltp_read_write \ --db-drivermysql \ --mysql-userlib_app \ --mysql-passwordLib2023Pass! \ --mysql-dblibrary_system \ --threads4 \ --time60 \ --report-interval10 \ run关注输出中的queries:和latency (avg)queries: 24000 (400.00 per sec.) latency (avg): 9.85 mslatency 10ms设计合格latency 50ms检查慢查询日志大概率是缺失索引或JOIN方式不当。我的习惯是每次加一个新功能如“逾期提醒定时任务”就跑一次EXPLAIN和sysbench确保新增SQL不拖垮整体。数据库设计不是一锤子买卖而是随着业务演进持续微调的过程。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网