如果你目前的工作是 T-SQL 开发,或者正从运维、应用开发转向数据库侧,Microsoft 认证路径里的 Developing SQL Databases 是一个很适合用来建立体系的方向。和我一开始想的不太一样,这门认证并不是让你背 SQL 语法,而是要求你像开发人员一样去设计表、索引、存储过程、函数、触发器,同时还要处理事务、并发、死锁和性能优化。这篇文章我会按自己的备考和实际开发顺序,把重点模块、容易踩的坑、以及值得照着做的练习路径完整讲一遍。
先给一个判断:如果你只是想提升日常查询能力,那更需要学的是 Querying Data with T-SQL 这类方向;如果你要负责设计数据库对象、写存储过程、优化慢查询,Developing SQL Databases 这条线会更对口。它在常见认证序列里通常排在 T-SQL 查询之后,属数据库开发方向的核心考试。下面内容不仅针对考试,也适合刚接手数据库开发工作的人。
1. 先判断你适不适合考这门认证,以及它到底考什么
1.1 它的能力目标不是“会写 SQL”,而是“会开发数据库”
很多人把“数据库开发”理解成“写复杂的 select 查询”,这是最大的误区。Developing SQL Databases 考的是一整套对象设计能力,包括:
- 设计并实现表结构、数据类型、约束。
- 设计索引,并理解索引对查询和写入的影响。
- 编写存储过程、视图、函数、触发器,并知道每种对象的适用边界。
- 处理事务、隔离级别、死锁和阻塞。
- 对查询进行性能分析,能看懂执行计划,能做基础优化。
- 部署数据库对象时考虑权限、版本和可回滚性。
也就是说,它要求你从“能用 SQL 查出结果”升级到“能设计一个稳定、高效、可维护的数据库应用”。
1.2 三类人群最适合,一种人要慎重
我接触过的学员和同事里,适合走这条路径的主要有三类:
第一类是专职 T-SQL 开发。这类人每天都在写存储过程、视图、报表查询,但缺少系统化的对象设计训练。通过认证学习,能把零散经验整理成方法,尤其是索引和事务部分。
第二类是运维转开发,或者运维转 DBA。这类人有服务器和实例管理经验,但对业务对象设计不熟悉。他们最需要补的是“为什么表要这么建”“为什么索引会影响写入性能”这类开发侧问题。
第三类是刚毕业或转行的新人。认证可以帮助建立知识框架,但不能替代练习量。如果只刷题不实操,面试时很容易被问倒。
有一种人建议缓一缓:如果你的工作内容只是写简单查询、做报表导出,不涉及表结构调整和存储过程开发,那更合适的路径是先学 T-SQL 查询基础和 SQL Server 管理基础,不要直接冲 Developing SQL Databases。
1.3 考试涉及的模块和常见比例
这门认证在不同版本下的大纲会稍有调整,但核心模块基本稳定。按我的观察,常见考核重点可以分成几块:
- 表设计:数据类型选择、约束创建、临时表和表变量差异,占比不低。
- 索引:聚集索引、非聚集索引、覆盖索引、索引维护,这部分很难跳过。
- 可编程对象:存储过程、视图、函数、触发器,内容最多,也最耗时间。
- 事务与并发:事务隔离级别、锁、死锁处理,属于拉开差距的部分。
- 性能优化:执行计划、统计信息、动态管理视图,是考试后期和应用实战都需要的部分。
复习顺序建议也按这个节奏走:先建表,再索引,再可编程对象,再事务,最后性能优化。过早进入性能优化,会因为缺少对象设计经验而看不懂很多结论,学习效率并不高。
2. 表结构设计:认证里的“建表”和项目里的“建表”不一样
2.1 设计顺序:先逻辑模型,再物理表结构
这不是流程要求,而是为了减少返工。直接打开 SSMS 建表当然可以,但一旦牵涉到十几个表的关联关系,没有逻辑设计会非常痛苦。
实际开发里我一般这么拆:
- 先理清业务实体有哪些。比如订单、订单明细、客户、商品。
- 再确定实体之间的关系。一对多、多对多,是否允许为空。
- 然后才落到物理表设计:表名、列名、数据类型、主键、外键、约束。
- 最后才写建表脚本。
在服务器上建表时,脚本建议带上 Schema 前缀,避免默认 dbo 混乱,也方便权限管理。示例:
CREATE SCHEMA sales; GO CREATE TABLE sales.Orders ( OrderId INT IDENTITY(1,1) NOT NULL, CustomerId INT NOT NULL, OrderDate DATETIME2(0) NOT NULL, TotalAmount DECIMAL(12,2) NOT NULL, CONSTRAINT PK_Orders PRIMARY KEY (OrderId) );这里有一点要注意:主键不一定只能用自增列。如果业务上有自然唯一列,例如订单号业务编号,也可以作为主键。但主键列同时会默认成为聚集索引,所以列宽度不能太大。用多个 varchar(50) 拼出来的复合主键要非常谨慎,因为它会让索引变大,也会让所有非聚集索引的回表列变宽。
2.2 约束的细节:主键、外键、唯一约束、检查约束
约束是数据库层面的完整性保护,不是可有可无的装饰。实际开发中,我见过太多表没有外键,业务层删了关联数据,导致后续报表出现孤单单据。该加的外键一定要加。
外键的代价是写入时需要检查引用关系,这在大量并发插入时会影响性能。但大多数业务系统里,这个代价远小于数据损坏后的修复成本。性能问题应该通过索引和写入模式来优化,而不是通过删约束来解决。
唯一约束和检查约束比触发器轻量,能用约束的地方不要用触发器。比如状态字段只允许有效值,优先写:
CONSTRAINT CK_Orders_Status CHECK (Status IN ('Pending', 'Paid', 'Cancelled'))日常开发还有一个容易被忽略的点:约束和索引命名。生产环境用系统自动生成的约束名,报错信息会非常难读。建议统一用表名列名来命名,例如 PK_Orders、FK_Orders_Customers、UQ_Customers_Email。
排查表结构时,可以用系统视图快速确认:
SELECT t.name AS TableName, c.name AS ColumnName, c.max_length, c.is_nullable FROM sys.tables t JOIN sys.columns c ON t.object_id = c.object_id WHERE t.name = 'Orders';2.3 数据类型选错的典型后遗症
类型选错不会导致立即报错,但会慢慢拖垮性能和存储。
先说最常见的 varchar 与 nvarchar。nvarchar 每个字符占两字节,varchar 通常占一字节。如果业务没有多语言需求,不需要把所有列都定义成 nvarchar。很多历史系统全表 nvarchar,表体积偏大,索引也变得更大,查询自然会慢一点。
日期时间类型也一样。datetime 精度到 3 毫秒左右,datetime2 精度更高,存储也可能不同。建议新系统用 datetime2,并根据业务精度设 scale。不要在日期列上存字符串,排序和范围查询都会吃亏。
金额字段建议用 decimal,不要用 float。float 是浮点数,做累计求和时可能出现精度误差。示例:decimal(18,2)或decimal(12,2)都可以,关键要定好精度。
所有文本列都设置成 varchar(max) 也是常见问题。max 类型不能被索引,且在内存排序和比较时开销更大。业务上明显超过普通长度才用 max,一般用 varchar(256) 或 varchar(1000) 配合合适索引即可。
3. 索引设计是数据库开发的胜负手
3.1 聚集索引、非聚集索引、堆:怎么理解
如果只记住一句话,那就是“索引不是越多越好,而是越精准越好”。
没有聚集索引的表叫做堆,插入时通常很快,但查询经常需要扫描,更新也可能产生表级锁。大多数业务表建议有聚集索引。聚集索引决定了数据的物理顺序,也承担所有非聚集索引的“指针”作用。所以聚集索引键要符合几个条件:唯一、稳定、宽度小。最常见的做法是用自增主键。
非聚集索引是独立结构,查询时通过索引找到键值,再根据聚集索引键回表取整行数据。这里有个很容易踩的坑:如果一个表经常按“用户 ID + 状态”查询,但非聚集索引只包含用户 ID,SQL Server 可能需要回表多次。到底要不要加覆盖索引,不是拍脑袋,而是要看实际执行计划。
判断索引是否被使用时,不要只看“建了索引就有效”。可以先查看索引使用情况:
SELECT object_name(s.object_id) AS TableName, i.name AS IndexName, s.user_seeks, s.user_scans, s.user_lookups, s.user_updates FROM sys.dm_db_index_usage_stats s JOIN sys.indexes i ON s.object_id = i.object_id AND s.index_id = i.index_id WHERE s.database_id = DB_ID();如果某个索引 user_seeks 很低,但 user_updates 很高,这个索引可能反而拖累写入。
3.2 覆盖索引和过滤索引:什么时候值得用
覆盖索引指索引包含查询需要的全部列,查询可以完全从索引页取数据,不需要再回表。这种索引对固定查询模式非常有效,尤其适合报表场景。
但覆盖索引不是“多塞几列进去就行”。列的宽度越大,索引页能容纳的行数越少,I/O 和内存占用越高。建覆盖索引前要先观察查询语句,明确哪些列是过滤列,哪些列是返回列,尽量只覆盖高频查询的必要列。
过滤索引适合只查询数据子集的场景。比如一张订单表有订单状态,业务上只关心未处理记录:
CREATE INDEX IX_Orders_Status_CreatedDate ON sales.Orders(Status, CreatedDate) WHERE Status IN ('Pending', 'Failed');这种索引比全表索引小很多,查询和维护成本都更低。要注意的是,过滤索引的使用条件在查询中要能匹配过滤谓词,否则优化器可能不选择它。
3.3 重复索引和缺索引的判断方法
实际项目里最常见的索引问题不是没有索引,而是索引冗余。
举例:一张表已经有了索引IX_Email,后来又建一个IX_Email_Status,这两个索引在查询单列时可能都能用,但后者在前者之上增加了列。如果两个索引列顺序相似,靠着前面的列就能覆盖查询,那么索引就存在冗余。建议定期对比 sys.indexes 和 sys.index_columns,清理明显重复的索引。
缺索引的判断主要靠执行计划。在 SSMS 里查看时,如果看到大量 Table Scan 或 Key Lookup,就说明索引可能不够。系统也提供了缺失索引提示,例如 sys.dm_db_missing_index_details。但这个提示只能作为参考,直接照搬创建所有缺失索引,很可能又制造一批冗余索引。
更稳妥的做法是:
- 先记录慢查询的 SQL 文本和参数。
- 查看当前执行计划和实际行数。
- 再考虑加索引。
- 加完索引后重新执行同一查询,对比逻辑读和耗时。
- 观察一段时间写入性能是否受影响。
索引维护也要有规律。用下面的语句可以看碎片率:
SELECT object_name(object_id) AS TableName, index_id, index_type_desc, avg_fragmentation_in_percent, page_count FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED');碎片率通常可以作为参考,但不能只看数值就决定重建。重建索引会锁定对象,大表重建耗时很长。生产环境要考虑维护窗口和磁盘空间。
4. 存储过程、视图、函数、触发器:把业务逻辑写进数据库的边界在哪里
4.1 存储过程:参数、SET NOCOUNT、错误处理
存储过程是数据库开发里最常用的对象。它的价值不只是“把一堆 SQL 存起来”,而是减少客户端和数据库反复传输 SQL 文本,也能通过权限控制让应用账号只能执行过程,不能直接改表。
写存储过程时,有几件事几乎每次都要做。
第一,开头加SET NOCOUNT ON;。如果不加,每个 DML 语句都会返回行数信息,增加网络开销,也可能影响 ORM 处理结果。
第二,所有输入用参数,不要拼接字符串。动态拼接 SQL 不仅可能引发注入风险,还会让执行计划很难复用。必须动态拼接时,用sp_executesql并按参数化方式传值。
第三,要有错误处理。一个带事务的过程,不能只是 BEGIN TRANSACTION 后盲目 COMMIT。至少要有 try-catch 逻辑:
CREATE PROCEDURE sales.InsertOrder @CustomerId INT, @TotalAmount DECIMAL(12,2) AS BEGIN SET NOCOUNT ON; DECLARE @OrderId INT; BEGIN TRY BEGIN TRAN; INSERT INTO sales.Orders(CustomerId, TotalAmount, OrderDate) VALUES (@CustomerId, @TotalAmount, SYSDATETIME()); SET @OrderId = SCOPE_IDENTITY(); COMMIT; SELECT @OrderId AS OrderId; END TRY BEGIN CATCH IF XACT_STATE() <> 0 ROLLBACK; THROW; END CATCH END;注意XACT_STATE()检查很有必要,不能只凭 catch 就认为事务一定处于可回滚状态。如果调用方已经存在一个失败事务,直接回滚可能影响外部状态。
4.2 视图:适合封装查询,别把它当万能工具
视图的优点是隐藏表结构、封装复杂关联、控制权限。但很多人把视图当成大量表的替身,三层视图套四层视图,最后执行计划复杂得没法看。
默认视图是不带排序的。需要排序时,查询里必须显式写 ORDER BY,而且要配合 TOP 或 OFFSET,才可能在视图中保留稳定结果。
索引视图在某些圈子里被吹得很高,但它的创建条件很严格,包括 WITH SCHEMABINDING、SET ANSI_NULLS ON、SET QUOTED_IDENTIFIER ON 等一系列要求。建立索引后,基础表更新时视图索引也要同步更新,写入成本不低。实际项目里,我更推荐先用普通视图加合理索引解决报表查询,而不是盲目上索引视图。
4.3 函数与触发器:方便,但是有成本
函数最大的问题是性能陷阱。尤其是标量函数,如果放在 WHERE 条件里,经常导致每一行都执行一次函数计算。比如WHERE YEAR(CreateDate) = 2025,即使 CreateDate 上有索引,也基本用不上。正确写法通常是WHERE CreateDate >= '2025-01-01' AND CreateDate < '2026-01-01'。
表值函数相对好用一些。内联表值函数(Inline Table-Valued Function)在优化器里可以展开,能力接近视图。多语句表值函数因为要物化到临时表,开销更大,能不用尽量不用。
触发器是另一个“方便但危险”的对象。业务上常见的需求是“某数据变更后记录日志”,听起来触发器很合适,但一旦触发器里逻辑变复杂,就会带来几个问题:
- 触发器内的错误会让主操作失败,排查链路变长。
- 多个触发器之间的执行顺序不可控。
- 大表上的触发器会对写放大产生明显影响。
如果确实需要用 DML 触发器,我的建议是逻辑尽量短,只做记录或简单同步,不要在里面做复杂运算,也不要调用远程服务器。更复杂的变更跟踪需求,可以考虑 SQL Server 自带的数据变更捕获或更改跟踪,这些机制比手写触发器更可控,系统性也更强。
5. 事务与并发控制:开发数据库和查询数据库最大的区别
5.1 显式事务的写法与提交时机
事务存在的意义是保证一组操作要么全部成功,要么全部失败。实际开发中,事务不是越宽越好,而是要尽量短。
看一个典型场景:一个事务里插入主表、插入明细表,还要调用外部 API 或发送邮件。把外部调用放进数据库事务里,意味着外部操作可能会长时间占用连接和锁,数据库压力会明显上升。正确做法是先用数据库事务确保核心写库操作完成,再在业务层做外部调用,不要把所有事情塞进一个事务。
事务写法上要注意两点:
第一,事务开始后,重新执行前面示例中的 try-catch 模式,确保出错能回滚。
第二,事务里不要随意使用WAITFOR、长时间循环这类阻塞操作。事务时间越长,锁持有时间越长,出现阻塞和死锁的概率就越高。
如果只需要回滚一部分操作,可以使用SAVE TRANSACTION保存点。但保存点容易让事务逻辑复杂化,调试也更麻烦,默认情况下不如拆成多个事务。
5.2 隔离级别怎么选,默认级别够不够用
SQL Server 默认隔离级别是 READ COMMITTED,它避免脏读,但不能保证同一事务内两次读到的数据一致,也就是可能出现不可重复读。
如果你的业务能接受这种差异,尽量不要动隔离级别。调高级别一定让并发能力下降。READ UNCOMMITTED 虽然读取快,但可能读到未提交的数据,这类“快”对业务结果有风险,尤其在做金额统计时非常危险。
SNAPSHOT 隔离级别在部分读多写少的系统里是一个调整方向。它利用行版本,让读操作不阻塞写操作。但它依赖 tempdb,并且数据库必须开启ALLOW_SNAPSHOT_ISOLATION。开启前要做资源评估,否则在大量并发读写下 tempdb 增长会很快,反而造成新的性能问题。
这里给一个通用选择思路:
- 财务、库存等强一致场景,沿用默认 READ COMMITTED 或更高,重点靠索引和事务设计减少锁冲突。
- 报表、统计、页面列表等弱一致且读多场景,可以评估 READ COMMITTED SNAPSHOT 或 SNAPSHOT。
- 不要为了“避免堵塞”把所有查询改成 NOLOCK。这个习惯很容易留下脏读隐患。
5.3 死锁和阻塞的定位思路
死锁报错 1205 表明当前会话被选为死锁牺牲品。遇到死锁,第一反应不是“调事务隔离级别”,而是先看锁冲突在哪里。
排查阻塞时,我通常会按这个顺序做:
- 查看当前请求里有没有被阻塞的会话和阻塞源头。
SELECT session_id, blocking_session_id, wait_type, wait_time, status, command FROM sys.dm_exec_requests WHERE blocking_session_id > 0;- 根据阻塞会话 id 找到正在执行的 SQL。
SELECT r.session_id, t.text FROM sys.dm_exec_requests r CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t WHERE r.session_id IN (需要查的 session_id);查看当前数据库中的锁信息,聚焦 LCK_M_X、LCK_M_S 这类等待。
根据等待类型判断是普通阻塞还是死锁。
解决死锁通常从几个方向入手:保持对象访问顺序一致、事务尽量短、索引设计合理、减少扫描范围、必要时用重试机制。先做前几项,不要一上来就开改成 READ UNCOMMITTED。
6. 性能优化和部署:认证之外真正要具备的生产能力
6.1 执行计划先看哪几项
会写索引和存储过程只算开发入门,真正拉开差距的是性能优化。执行计划是绕不开的第一站。
使用 SSMS 时,按 Ctrl+M 可以打开“包含实际执行计划”,运行查询后重点看几个地方:
- 是否出现大表上的 Table Scan 或 Index Scan。注意“Scan”不一定是坏事,如果表本身很小,全表扫描可能比走索引更快。
- 是否出现大量 Key Lookup。如果回表次数非常多,可以考虑覆盖索引。
- 连接运算符是 Nested Loop 还是 Hash Match 还是 Merge Join。数据量小的时候 Loop 正常,但大表关联如果出现 Loop,可能意味着需要使用索引或重写语句。
- “估计行数”和“实际行数”严重偏差,大概率是统计信息过期或参数嗅探。
还有一个实操习惯:执行前先按 Ctrl+L 看估计执行计划,再按 Ctrl+M 运行拿实际执行计划。两者对照能看出优化器的判断和实际数据的差异。
统计信息过期导致的性能问题非常常见。比如一张表几千万行,每天的增量让分布变化很大,如果统计信息不更新,优化器可能以为“返回值很少”,实际返回大量行,因此选择了错误计划。这不是索引问题,甚至不是 SQL 写法问题,而是统计信息维护问题。
6.2 动态管理视图怎么用
动态管理视图是排查性能问题最重要的工具,比很多可视化工具都直接。
我平时最常用的是:
sys.dm_exec_requests:看当前正在执行什么,有没有阻塞。sys.dm_exec_query_stats:看历史查询的 CPU、逻辑读、执行次数,找消耗最高的会话。sys.dm_db_index_usage_stats:看索引到底被使用了多少。sys.dm_os_wait_stats:看实例级别的等待类型,例如 PAGEIOLATCH_SH 表示 I/O 压力,LCK_M_X 表示锁等待。sys.dm_tran_locks:看锁粒度,排查是行锁还是表锁。
使用查询统计时,可以直接按累计逻辑读或 CPU 排序,定位高频慢查询。这是一个非常实用的做法:先找出最消耗资源的 Top 查询,再打开执行计划分析,不要拿着监控工具从头看到尾。
6.3 部署、权限与版本兼容
很多人在本地把脚本写好了,却不重视部署过程,这是开发转生产最容易翻车的环节。
第一个建议是把所有数据库对象变更都脚本化,用版本控制工具管理。表结构变更、索引新增、存储过程更新,都应该有脚本记录。不要直接在开发库改完,再通过“生成脚本”或“同步”功能凭空发布。脚本化之后,才能做代码审查、回滚和追溯。
第二个建议是权限按最小化原则给。应用账号只需要对业务对象执行存储过程的权限,就不要给 ALTER、DELETE、DROP 这类权限,更不该给 sysadmin。数据库部署账号和日常应用账号要分开。
第三个建议是注意版本差异。SQL Server 2016、2019、2022 之间,部分语法和默认行为有差异。例如某些排序、字符串截断行为、兼容性级别变化,会导致同一套 SQL 在不同版本上表现不同。如果团队混用多个版本,写 SQL 时要尽量使用通用写法,并在目标版本上验证。
一个常见问题:线上环境没有高级功能或权限,比如分布式查询组件被禁用,出现类似“阻止了对组件 ad hoc distributed queries 的 statement”的报错。这种情况通常不是 SQL 本身错了,而是实例配置或权限问题。开发环境能跑,生产环境不一定能跑,必须先确认服务器配置和应用账号权限。
7. 备考和练习路径:从环境搭建到考前自测
7.1 本地环境怎么搭
学习 Developing SQL Databases 必须动手,光看视频很难形成记忆。本地环境建议这样准备:
- 安装 SQL Server Developer Edition。Developer Edition 功能和企业版基本一致,适合学习和开发,授权成本相对友好。没有完整授权条件时,也可以先用 Express 版本,但要注意 Express 在内存、数据库大小和部分功能上有限制。
- 安装 SQL Server Management Studio,也就是 SSMS。这是最常用的图形化工具,看执行计划、写查询、管理对象都很方便。
- 如果喜欢轻量编辑器,可以并行使用 Azure Data Studio。
- 准备一个样例数据库。常见的做法是安装微软公开的 AdventureWorks 样例库,具体版本选择要和你的 SQL Server 版本匹配。
- 电脑配置不需要太高。普通 8GB 内存、SSD 磁盘就能日常练习。如果要测试高并发、快照隔离、大量数据写入,建议内存加到 16GB,并给 SQL Server 预留足够磁盘空间。
安装的时候注意实例名。默认实例直接写主机名,命名实例要写“主机名\实例名”这种格式。连接不上时,优先检查 SQL Server 服务是否启动、TCP/IP 是否启用、SQL Server Browser 服务是否运行,这三个原因占了多数。
7.2 推荐练习顺序
不要按教材目录从头翻到尾,我建议按能“跑起来”的顺序来学:
- 先建库建表,把主键、外键、默认值、检查约束都建一遍。
- 插入几组正常数据和异常数据,观察约束是否生效。
- 然后学索引。先建立普通索引,再看执行计划的 Scan 和 Seek。
- 再写存储过程,练习 try-catch、事务、OUTPUT 参数。
- 接着写视图和函数,重点做查询封装,不要一开始就写复杂触发器。
- 最后学事务隔离级别和性能优化,做几个“慢查询变快”的对比实验。
每学完一个模块,不要急着进入下一个,而是尝试把当前模块应用到样例数据库的某个真实场景里。比如设计一张订单表,然后为它写分页查询、写状态更新存储过程、分析执行计划、补索引。这样学下来,知识点是连成片的。
7.3 常见报错和排查顺序
练习过程中一定会出问题。遇到问题不要直接问“这个报错怎么办”,按顺序排查:
- 看现象:是连接失败、SQL 语法报错、权限拒绝,还是查询卡住,还是结果不对。
- 看输入:SQL 里的表名、列名、数据库名、Schema 是否写对,字符串编码是否正确,NULL 是否参与比较。
- 看环境:服务是否启动,登录名和默认数据库是否设置正确,账号是否被授予对应对象权限。
- 看日志:查看 SQL Server 错误日志,以及 SSMS 消息面板里的详细信息。
- 看参数与配置:索引、统计信息、兼容性级别、数据库选项是否影响当前语句。
举一个高频问题:用户能用 SSMS 看数据,但应用端报“对象名无效”。这类问题很多不是权限,而是应用连接字符串里的初始目录和数据库账号的默认 Schema 不同。表建在 dbo 下,账号默认 Schema 却是 guest,查询时又不带 Schema 前缀,就容易出现对象找不到。这时只要显式写 dbo.TableName,或者调整账号默认 Schema 即可。
还有一种很常见的情况:开发环境跑得好好的 SQL,复制到生产环境就变慢。这大概率不是服务器内存问题,而是统计信息、索引和参数不一样。对比时不要只看执行时间,要同时看执行计划、估计行数、实际行数和逻辑读。
收尾
如果要给一个学习结论,我会说:Developing SQL Databases 的核心价值,是逼着你从“会查询”走到“会设计、会优化、会排错”。这门认证相关的课程很多,但课程只是引子,真正起作用的是你按照考试要求一个个动手建表、建索引、写存储过程、模拟阻塞和死锁的过程。
备考时别急着刷大量题,先花时间把样例数据库里的核心对象重建一遍,比看三遍视频都有效。把单个模块跑稳之后,再组合成完整业务场景,比如订单状态流转、库存扣减、报表查询缓存。能稳定处理这些场景,考试和实际工作都会轻松不少。
如果只是学过一次、跑过几个简单例子,那还不够。数据库开发的很多问题,平时不出现,一旦出现就是线上问题。提前把排查顺序和对象设计底子打扎实,后续再遇到慢查询、死锁、权限报错,你至少知道从哪里开始查,而不是直接重建数据库。