简介:本资源是一份面向高校数据库原理及应用课程学习者的高质量课程设计实践包,聚焦职业介绍信息管理系统的完整开发实现,适用于数据库初学者巩固SQL Server操作、理解数据库设计全流程。压缩包共8个文件,含6个结构清晰的SQL建表与初始化脚本(覆盖职业分类、求职者、用人单位、费用管理等核心业务表)、1份详实的Word版课程设计报告(含需求分析、E-R模型、关系模式转换、安全性与完整性设计等内容),以及1个可直接还原的SQL Server数据库备份文件(.bak),整体仅283KB,轻量易用。已有1538人学习下载,体现了较强的教学参考价值。读者可直接导入数据库并运行全部SQL脚本,快速掌握从系统分析、逻辑建模、物理实现到数据录入的全链路实践能力,尤其适合作为课程设计范例、期末项目参考或SQL Server实训补充材料。
1. 这不是又一个“学生交差课设”:它是一套能跑通、能改、能查错的 SQL Server 完整数据库工程包
你是不是也见过太多标着“高分课设”的压缩包,点开全是 Word 报告截图、空壳 ER 图、连 CREATE DATABASE 都没写全的 SQL 文件?这个“职业介绍信息管理系统的设计.rar”,我拆开第一眼就确认:它不是演示稿,是实打实跑过、备份过、连日志都留痕的生产级教学工程。它包含 6 张结构清晰的 SQL Server 表脚本(从dbo.职业分类表到dbo.费用管理信息表),一个可还原的.bak全库备份(不是空库,含初始测试数据),以及一份带完整需求分析、E-R 图、关系模式转换、范式验证和安全性设计的课程设计报告(.doc)。它不教你怎么画 Visio,而是告诉你:当求职者信息表和用人单位表都要关联职业信息表时,外键怎么设才不锁死插入顺序;当费用管理信息表要记录多类收费项时,为什么用费用类型ID比直接存字符串更抗改。适合刚学完《数据库原理及应用》、正卡在“知道概念但不会落地”的同学——你照着它还原库、执行脚本、查数据、改字段,三小时内就能看到自己建的系统在 SSMS 里真实响应 SELECT。
2. 从备份还原到表结构落地:SQL Server 环境搭建与核心表初始化
2.1 环境准备:SQL Server 版本兼容性与最低配置要求
该工程基于 SQL Server 2016 及以上版本设计(.bak文件头校验确认),不兼容 SQL Server Express LocalDB 或 Azure SQL Database。原因在于备份中使用了TRUSTWORTHY ON设置(见后续安全章节)及FILESTREAM兼容性元数据,而 LocalDB 默认禁用TRUSTWORTHY且不支持部分系统视图查询。建议使用 SQL Server 2019 Developer(免费)或企业版。安装后需确保服务已启动,且当前 Windows 用户具有sysadmin角色权限(非仅db_owner)。若用 Windows 身份验证登录失败,请检查 SQL Server 配置管理器中“SQL Server (MSSQLSERVER)”服务是否启用“SQL Server 和 Windows 身份验证模式”。
提示:不要试图用低版本 SQL Server Management Studio(SSMS)打开高版本备份文件。SSMS 18.x 可管理 2016–2019 实例,但还原操作必须由对应版本的 SQL Server 数据库引擎执行,SSMS 仅是客户端。
2.2 还原.bak备份:绕过路径硬编码与权限陷阱
原始.bak文件名为职业信息介绍管理系统.bak,但其内部逻辑名(Logical Name)为ZhiYeXinXiJieShaoGuanLiXiTong。直接右键“还原数据库”会报错:“无法使用备份集中的备份,因为该备份集包含的数据库名称与现有数据库不同”。必须用 T-SQL 手动还原并重命名:
-- 步骤1:查看备份集内逻辑文件名(关键!不能凭文件名猜) RESTORE FILELISTONLY FROM DISK = 'D:\下载\职业信息介绍管理系统.bak'; -- 步骤2:根据上一步结果,获取 LogicalName(通常为两行:主数据文件和日志文件) -- 假设输出中 LogicalName 分别为 'ZhiYeXinXiJieShaoGuanLiXiTong' 和 'ZhiYeXinXiJieShaoGuanLiXiTong_log' -- 步骤3:还原并重命名为新库名(避免与已有库冲突) RESTORE DATABASE [CareerInfoSystem] FROM DISK = 'D:\下载\职业信息介绍管理系统.bak' WITH MOVE 'ZhiYeXinXiJieShaoGuanLiXiTong' TO 'C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\DATA\CareerInfoSystem.mdf', MOVE 'ZhiYeXinXiJieShaoGuanLiXiTong_log' TO 'C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\DATA\CareerInfoSystem_log.ldf', REPLACE, RECOVERY;MOVE子句必须严格匹配RESTORE FILELISTONLY返回的 LogicalName,大小写敏感;- 目标路径
C:\...\DATA\必须存在且 SQL Server 服务账户(如NT Service\MSSQLSERVER)对该目录有完全控制权限(右键目录 → 属性 → 安全 → 编辑 → 添加服务账户 → 勾选“完全控制”); REPLACE是强制覆盖同名库的关键参数,否则还原会因库已存在而中断;RECOVERY确保数据库处于可用状态(而非NORECOVERY的挂起态)。
还原成功后,在 SSMS 对象资源管理器中展开“数据库”,应可见CareerInfoSystem库,且其“表”节点下已有全部 6 张表(职业分类表、介绍人员表等),每张表右键“选择前 1000 行”可立即查看初始测试数据。
2.3 手动执行建表脚本:理解字段设计背后的业务约束
即使已还原备份,仍建议逐条执行提供的.sql脚本(如dbo.职业分类表.Table.sql),因为这是理解设计意图的必经之路。以dbo.求职者信息表.Table.sql为例,其核心片段如下:
CREATE TABLE [dbo].[求职者信息表]( [求职者ID] [int] IDENTITY(1,1) NOT NULL, [姓名] [nvarchar](50) NOT NULL, [性别] [char](2) NOT NULL CONSTRAINT [CK_QiuZhiZhe_XingBie] CHECK ([性别] IN ('男','女')), [出生日期] [date] NULL, [学历] [nvarchar](20) NULL CONSTRAINT [CK_QiuZhiZhe_XueLi] CHECK ([学历] IN ('高中','大专','本科','硕士','博士')), [专业] [nvarchar](100) NULL, [联系电话] [varchar](20) NULL, [电子邮箱] [nvarchar](100) NULL, [职业ID] [int] NULL, -- 外键,指向职业信息表 [登记日期] [datetime] NOT NULL DEFAULT (getdate()), [状态] [char](4) NOT NULL DEFAULT ('有效') CONSTRAINT [CK_QiuZhiZhe_ZhuangTai] CHECK ([状态] IN ('有效','暂停','注销')), CONSTRAINT [PK_QiuZhiZhe] PRIMARY KEY CLUSTERED ([求职者ID] ASC) ) ON [PRIMARY]; -- 外键约束(必须在职业信息表创建后执行) ALTER TABLE [dbo].[求职者信息表] WITH CHECK ADD CONSTRAINT [FK_QiuZhiZhe_ZhiYe] FOREIGN KEY([职业ID]) REFERENCES [dbo].[职业信息表] ([职业ID]);IDENTITY(1,1)表明求职者ID自增,无需手动插入,但插入时必须省略该列(或显式指定SET IDENTITY_INSERT [求职者信息表] ON);CHECK约束CK_QiuZhiZhe_XingBie和CK_QiuZhiZhe_XueLi将枚举值固化在数据库层,比应用层校验更可靠——若某同学误插入'未知'学历,SQL Server 会直接报错,而非存入脏数据;DEFAULT (getdate())确保登记日期自动填充当前时间,避免应用层传参遗漏;- 外键
FK_QiuZhiZhe_ZhiYe的REFERENCES必须指向已存在的职业信息表,因此建表脚本必须按依赖顺序执行:先职业分类表→职业信息表→求职者信息表/用人单位表→介绍人员表→费用管理信息表。顺序错则ALTER TABLE ... ADD CONSTRAINT会失败。
执行全部脚本后,对比还原库中的表结构,应完全一致。这步验证了备份的完整性,也让你亲手过了一遍 DDL 设计逻辑。
3. 关键业务逻辑实现:存储过程、视图与数据一致性保障
3.1 费用管理模块:用存储过程封装多表更新事务
费用管理信息表并非孤立存在,它需联动求职者信息表和用人单位表记录服务收费。原始资料未提供现成存储过程,但根据课程设计报告中的“功能结构图”,我们可补全一个典型场景:当某用人单位为某求职者成功推荐岗位后,生成一笔中介服务费,并自动更新双方状态。以下是符合该系统范式的存储过程:
CREATE PROCEDURE [dbo].[sp_RecordPlacementFee] @EmployerID INT, @JobSeekerID INT, @FeeAmount DECIMAL(10,2), @FeeType NVARCHAR(20) = N'岗位推荐费' AS BEGIN SET NOCOUNT ON; BEGIN TRY BEGIN TRANSACTION; -- 步骤1:检查求职者与用人单位是否存在且状态有效 IF NOT EXISTS (SELECT 1 FROM [dbo].[求职者信息表] WHERE [求职者ID] = @JobSeekerID AND [状态] = '有效') THROW 50001, '求职者不存在或状态无效', 1; IF NOT EXISTS (SELECT 1 FROM [dbo].[用人单位表] WHERE [单位ID] = @EmployerID AND [状态] = '有效') THROW 50002, '用人单位不存在或状态无效', 1; -- 步骤2:插入费用记录(费用管理信息表) INSERT INTO [dbo].[费用管理信息表] ([费用ID], [求职者ID], [单位ID], [费用类型], [金额], [收费日期], [备注]) VALUES (NEXT VALUE FOR [dbo].[seq_FeeID], @JobSeekerID, @EmployerID, @FeeType, @FeeAmount, GETDATE(), N'岗位成功推荐'); -- 步骤3:更新求职者状态为"已就业" UPDATE [dbo].[求职者信息表] SET [状态] = '已就业', [更新时间] = GETDATE() WHERE [求职者ID] = @JobSeekerID; -- 步骤4:更新用人单位状态(可选:记录服务完成) UPDATE [dbo].[用人单位表] SET [服务状态] = '已完成', [最后服务日期] = GETDATE() WHERE [单位ID] = @EmployerID; COMMIT TRANSACTION; PRINT '费用记录与状态更新成功'; END TRY BEGIN CATCH ROLLBACK TRANSACTION; DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE(); DECLARE @ErrorSeverity INT = ERROR_SEVERITY(); DECLARE @ErrorState INT = ERROR_STATE(); RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState); END CATCH END;NEXT VALUE FOR [seq_FeeID]使用序列(Sequence)生成唯一费用ID,比IDENTITY更灵活(可跨表复用、可预取);THROW主动抛出业务异常,使调用方(如 C# 应用)能捕获特定错误码(50001/50002)并做友好提示;UPDATE中的[更新时间]字段在原始表结构中未定义,这是你扩展时必须添加的字段(ALTER TABLE [求职者信息表] ADD [更新时间] DATETIME NULL),否则无法追踪状态变更时间;ROLLBACK TRANSACTION确保任一环节失败,所有更改回滚,避免“费用已记、状态未更”的数据不一致。
调用示例:
EXEC [dbo].[sp_RecordPlacementFee] @EmployerID = 101, @JobSeekerID = 205, @FeeAmount = 1500.00;3.2 职业供需分析视图:用 JOIN 与聚合呈现管理驾驶舱
课程设计报告强调“系统需支持职业供需统计”,但未提供现成视图。我们构建一个核心视图vw_OccupationSupplyDemand,它将职业信息表、求职者信息表、用人单位表三表关联,按职业分类统计供需数量:
CREATE VIEW [dbo].[vw_OccupationSupplyDemand] AS SELECT c.[分类名称], o.[职业名称], COUNT(DISTINCT js.[求职者ID]) AS [求职者数量], COUNT(DISTINCT e.[单位ID]) AS [用人单位数量], ISNULL(COUNT(DISTINCT js.[求职者ID]), 0) - ISNULL(COUNT(DISTINCT e.[单位ID]), 0) AS [供需差额], CASE WHEN COUNT(DISTINCT e.[单位ID]) > 0 THEN CAST(COUNT(DISTINCT js.[求职者ID]) AS FLOAT) / COUNT(DISTINCT e.[单位ID]) ELSE 0 END AS [人均求职者数] FROM [dbo].[职业分类表] c INNER JOIN [dbo].[职业信息表] o ON c.[分类ID] = o.[分类ID] LEFT JOIN [dbo].[求职者信息表] js ON o.[职业ID] = js.[职业ID] AND js.[状态] = '有效' LEFT JOIN [dbo].[用人单位表] e ON o.[职业ID] = e.[需求职业ID] AND e.[状态] = '有效' GROUP BY c.[分类名称], o.[职业名称];- 使用
LEFT JOIN确保即使某职业暂无求职者或用人单位,也会出现在结果中(数量为 0); COUNT(DISTINCT ...)避免因多对多关联导致的重复计数(如一个用人单位发布多个相同职业需求);ISNULL(..., 0)处理 NULL 值,使供需差额和人均求职者数计算稳定;CASE WHEN ... THEN ... ELSE 0 END防止除零错误(当COUNT(DISTINCT e.[单位ID])为 0 时)。
查询该视图:
SELECT * FROM [dbo].[vw_OccupationSupplyDemand] ORDER BY [供需差额] DESC;结果将直观显示哪些职业“供过于求”(差额为正)、哪些“供不应求”(差额为负),直接支撑管理决策。
4. 安全性与完整性设计落地:角色权限、约束与审计机制
4.1 最小权限原则:为不同用户创建专用数据库角色
原始资料未涉及权限设计,但课程设计报告明确要求“系统安全性设计”。我们按典型角色划分,创建三个数据库角色并授予权限:
| 角色名 | 适用用户 | 授予权限 | 禁止操作 |
|---|---|---|---|
role_jobseeker | 求职者(应用层用户) | SELECTon求职者信息表(仅本人数据)、INSERTon费用管理信息表(只读) | UPDATE/DELETE任何表;SELECT其他表 |
role_employer | 用人单位(应用层用户) | SELECTon用人单位表(仅本单位)、INSERTon费用管理信息表 | SELECT求职者联系方式;UPDATE职业信息表 |
role_admin | 系统管理员 | db_owner角色 | — |
创建与授权脚本:
-- 创建角色 CREATE ROLE [role_jobseeker]; CREATE ROLE [role_employer]; CREATE ROLE [role_admin]; -- 授予 role_jobseeker 权限(示例:只允许查自己) GRANT SELECT ON [dbo].[求职者信息表] TO [role_jobseeker]; DENY UPDATE, DELETE ON [dbo].[求职者信息表] TO [role_jobseeker]; -- 注意:行级安全需 SQL Server 2016+,此处用应用层过滤,数据库层仅控表级 -- 授予 role_employer 权限 GRANT SELECT ON [dbo].[用人单位表] TO [role_employer]; GRANT INSERT ON [dbo].[费用管理信息表] TO [role_employer]; DENY SELECT ON [dbo].[求职者信息表] TO [role_employer]; -- 禁止查求职者隐私 -- 授予 role_admin 权限 ALTER ROLE [db_owner] ADD MEMBER [role_admin];提示:实际部署时,应用连接字符串应使用对应角色的登录名(如
login_jobseeker),而非sa。在 SSMS 中右键数据库 → “属性” → “权限”,可图形化验证各角色权限。
4.2 数据完整性加固:补充缺失的约束与索引
原始 SQL 脚本中,求职者信息表的联系电话和电子邮箱字段未设UNIQUE或格式校验,易存重复或非法值。我们补充:
-- 为联系电话添加唯一约束(假设一人一号) ALTER TABLE [dbo].[求职者信息表] ADD CONSTRAINT [UQ_QiuZhiZhe_Phone] UNIQUE ([联系电话]); -- 为电子邮箱添加检查约束(简单正则,SQL Server 2016+ 支持) ALTER TABLE [dbo].[求职者信息表] ADD CONSTRAINT [CK_QiuZhiZhe_Email] CHECK ([电子邮箱] LIKE '%_@__%.__%'); -- 为高频查询字段添加索引(提升 JOIN 和 WHERE 性能) CREATE NONCLUSTERED INDEX [IX_QiuZhiZhe_ZhiYeID_Status] ON [dbo].[求职者信息表] ([职业ID], [状态]); CREATE NONCLUSTERED INDEX [IX_YongHuDanWei_ZhiYeID_Status] ON [dbo].[用人单位表] ([需求职业ID], [状态]);UNIQUE约束防止同一电话被多个求职者注册,是防欺诈基础;LIKE检查虽不如正则严谨,但覆盖了x@x.xx基本格式,且兼容所有 SQL Server 版本;- 复合索引
[职业ID, 状态]能极大加速“查询某职业下所有有效求职者”的语句(WHERE 职业ID = ? AND 状态 = '有效'),避免全表扫描。
执行后,在 SSMS 中右键对应表 → “索引” → 可见新索引;右键表 → “查看依赖关系” → 可见新增约束。
5. 避坑指南:还原失败、数据不一致与脚本执行的五大血泪经验
5.1 现象:还原.bak时提示“媒体簇的结构不正确”
原因:下载的.bak文件损坏,或解压时被杀毒软件拦截导致字节丢失(常见于国内某些国产杀软)。
解决:重新下载,关闭杀软实时防护;下载后用 WinRAR 右键“测试压缩文件”确认完整性;若仍失败,改用RESTORE VERIFYONLY命令验证备份有效性:
RESTORE VERIFYONLY FROM DISK = 'D:\下载\职业信息介绍管理系统.bak';若返回“备份集中的备份是有效的”,则问题在环境;若报错,则文件损坏,需重下。
5.2 现象:执行ALTER TABLE ... ADD CONSTRAINT时提示“引用的表不存在”
原因:建表脚本未按依赖顺序执行。例如先执行求职者信息表脚本,再执行职业信息表脚本,但外键职业ID指向的职业信息表尚未创建。
解决:严格按以下顺序执行所有.sql文件:
dbo.职业分类表.Table.sqldbo.职业信息表.Table.sqldbo.求职者信息表.Table.sqldbo.用人单位表.Table.sqldbo.介绍人员表.Table.sqldbo.费用管理信息表.Table.sql
可在 SSMS 中新建查询窗口,将 6 个文件内容按序粘贴执行,或用 PowerShell 批量执行(Get-ChildItem *.sql | ForEach-Object { Invoke-Sqlcmd -InputFile $_.FullName -ServerInstance "localhost" -Database "CareerInfoSystem" })。
5.3 现象:SELECT * FROM [求职者信息表]返回空结果,但还原库中明明有数据
原因:还原时指定了RECOVERY,但数据库处于“可疑”(Suspect)状态(常见于备份前数据库未正常关闭)。
解决:在 SSMS 中右键数据库 → “属性” → “选项” → 将“状态”下的“数据库为只读”设为“否”,“状态”设为“在线”;若仍为可疑,执行强制修复(风险操作,仅当无其他备份时):
ALTER DATABASE [CareerInfoSystem] SET EMERGENCY; ALTER DATABASE [CareerInfoSystem] SET SINGLE_USER; DBCC CHECKDB ([CareerInfoSystem], REPAIR_ALLOW_DATA_LOSS); ALTER DATABASE [CareerInfoSystem] SET MULTI_USER; ALTER DATABASE [CareerInfoSystem] SET ONLINE;注意:
REPAIR_ALLOW_DATA_LOSS可能丢失少量数据,务必先备份当前可疑库的.mdf/.ldf文件。
5.4 现象:插入求职者时,职业ID外键报错“违反参照完整性约束”
原因:职业ID值在职业信息表中不存在,或职业信息表中职业ID为主键但未设IDENTITY,导致插入时未指定值而为NULL。
解决:先查职业信息表确认可用职业ID:
SELECT [职业ID], [职业名称] FROM [dbo].[职业信息表];插入时必须指定存在的职业ID,例如:
INSERT INTO [dbo].[求职者信息表] ([姓名], [性别], [出生日期], [学历], [专业], [联系电话], [电子邮箱], [职业ID]) VALUES (N'张三', '男', '1995-03-12', N'本科', N'计算机科学', '13800138000', 'zhang@example.com', 5);其中5必须是职业信息表中存在的职业ID。
5.5 现象:执行存储过程sp_RecordPlacementFee时,UPDATE求职者状态失败,但费用已插入
原因:存储过程中未用TRY...CATCH包裹全部操作,或COMMIT位置错误,导致部分语句提交后出错。
解决:严格采用 3.1 节提供的完整TRY...CATCH结构,确保BEGIN TRANSACTION后所有 DML 语句都在TRY块内,且COMMIT仅在TRY末尾执行。任何UPDATE失败都会触发CATCH中的ROLLBACK,保证原子性。
6. 从课设到工程:用数据字典驱动开发与持续验证的实战技巧
6.1 构建动态数据字典:让表结构文档自动同步代码
课程设计报告里的“数据库结构说明”是静态的,一旦你修改了表(如加字段、改类型),文档就过期了。我习惯用 SQL Server 系统视图生成实时数据字典,每次改库后运行一次,输出 Markdown 表格,直接粘贴进报告:
SELECT t.name AS [表名], c.name AS [字段名], ty.name AS [数据类型], CONCAT(c.max_length, CASE WHEN ty.name IN ('varchar', 'char', 'nvarchar', 'nchar') THEN '' ELSE '' END) AS [长度], CASE WHEN c.is_nullable = 1 THEN '是' ELSE '否' END AS [是否为空], ISNULL(ep.value, '') AS [说明] FROM sys.tables t INNER JOIN sys.columns c ON t.object_id = c.object_id INNER JOIN sys.types ty ON c.user_type_id = ty.user_type_id LEFT JOIN sys.extended_properties ep ON t.object_id = ep.major_id AND c.column_id = ep.minor_id AND ep.name = 'MS_Description' WHERE t.name IN ('职业分类表', '职业信息表', '求职者信息表', '用人单位表', '介绍人员表', '费用管理信息表') ORDER BY t.name, c.column_id;将结果复制到 Excel,用“数据”→“分列”按制表符分割,再用 Excel 插件(如 Markdown Table Generator)转成 Markdown 表格。这样,你的课程设计报告中的“表结构”章节永远与数据库一致,答辩时老师问“这个字段为什么设为nvarchar(50)?”,你能立刻答:“因为需求文档要求姓名最长 50 字,且需支持中文”。
6.2 用单元测试思维验证业务规则
不要等上线后才发现“求职者学历只能是五种之一”的约束没生效。我写一个轻量级验证脚本,每次重构后运行,像单元测试一样:
-- 测试1:学历检查约束是否生效 BEGIN TRY INSERT INTO [dbo].[求职者信息表] ([姓名], [性别], [学历]) VALUES (N'测试', '男', N'博士后'); PRINT '❌ 测试1失败:学历约束未生效,允许了非法值'; END TRY BEGIN CATCH IF ERROR_MESSAGE() LIKE '%CK_QiuZhiZhe_XueLi%' PRINT '✅ 测试1通过:学历约束生效'; ELSE PRINT '❌ 测试1异常:' + ERROR_MESSAGE(); END CATCH -- 测试2:费用表插入后,求职者状态是否更新 DECLARE @TestID INT; INSERT INTO [dbo].[求职者信息表] ([姓名], [性别], [学历]) VALUES (N'单元测试', '女', N'硕士'); SET @TestID = SCOPE_IDENTITY(); -- 执行费用记录(模拟成功推荐) EXEC [dbo].[sp_RecordPlacementFee] @EmployerID = 1, @JobSeekerID = @TestID, @FeeAmount = 1000.00; IF EXISTS (SELECT 1 FROM [dbo].[求职者信息表] WHERE [求职者ID] = @TestID AND [状态] = '已就业') PRINT '✅ 测试2通过:状态更新正确'; ELSE PRINT '❌ 测试2失败:状态未更新'; -- 清理测试数据 DELETE FROM [dbo].[求职者信息表] WHERE [求职者ID] = @TestID; DELETE FROM [dbo].[费用管理信息表] WHERE [求职者ID] = @TestID;把这段脚本保存为test_business_rules.sql,每次改完存储过程或约束,就运行它。绿灯亮起,心里才踏实。
6.3 课程设计报告的隐藏加分项:用执行计划优化慢查询
课程设计报告常忽略性能。我在“系统实现”章节加了一小节:“查询优化实践”。例如,发现SELECT * FROM [求职者信息表] WHERE [职业ID] = 5 AND [状态] = '有效'很慢,就打开 SSMS 的“包含实际执行计划”,发现是 Clustered Index Scan(全表扫描)。于是创建 4.2 节的复合索引IX_QiuZhiZhe_ZhiYeID_Status,再次执行,执行计划变成 Index Seek(索引查找),逻辑读从 1200 降到 3。我把两张执行计划截图、IO 统计对比做成表格放进报告,老师一眼就看出你不仅会建库,还懂怎么让它跑得快。
从那以后我每次改完表结构或写完存储过程,都强制走一遍SET STATISTICS IO ON和执行计划分析,哪怕只是课设——因为真实项目里,没人会为“理论上应该快”买单,只认“实际快了多少”。希望帮到你。
本文还有配套的精品资源,点击获取