DBA 夜读·第一季第1期|重新出发:T-SQL开发中最常见的5个错误(以及如何避免)

0 阅读5分钟

📘 第一季·《100 SQL Server Mistakes and How to Avoid Them》

本季围绕 Peter A. Carter 的经典著作,系统梳理 SQL Server 开发与管理的常见错误。本书共408页,涵盖T-SQL开发、安装配置、性能优化、高可用性、安全等全领域,每章都是作者近20年实战中遇到的真实问题。


今日早报回顾: 今天早上「技术三件事·第1期」我们讨论了SQL Server视图性能陷阱——这恰恰印证了今晚要讲的核心观点:很多性能问题的根源,其实在开发阶段就埋下了。今晚我们开启新系列《DBA 成长计划》,用这本《100 SQL Server Mistakes and How to Avoid Them》作为起点,从Peter A. Carter近20年的实战经验中,学习如何避开那些最常见的坑。


第一部分:核心总结与实践

一、本期概览

本书第一章聚焦T-SQL开发中的常见错误。作者Peter A. Carter开篇就点明:很多性能问题不是调优能解决的,而是写代码时就已经错了。

本期我们提炼出5个最基础、最容易犯、影响面最广的开发错误,并给出"正确姿势"。


二、核心错误与解决方案

错误1:SELECT * 的滥用

问题表现:

  • • 返回不需要的列,增加网络传输和内存消耗

  • • 覆盖索引失效,查询被迫访问数据页

  • • 表结构变更时(如增加列),应用程序可能收到意外数据而崩溃

正确做法:

-- 错误写法
SELECT * FROM Sales.Orders WHERE orderdate = '2024-01-01';

-- 正确写法:只取需要的列
SELECT orderid, custid, orderdate 
FROM Sales.Orders 
WHERE orderdate = '2024-01-01';

💡 延伸思考: 即使你"现在需要所有列",也建议显式列出。未来表加字段时,你的查询不会自动多返回数据,避免了潜在的性能倒退和兼容性问题。


错误2:省略架构名称

问题表现:

-- 错误写法(没有架构名)
SELECT * FROM Orders;

当用户默认架构或数据库上下文不明确时,SQL Server需要额外解析对象所在架构,增加开销。更严重的是,如果存在同名表,可能访问到错误的对象。

正确做法:

-- 正确写法:显式指定架构
SELECT * FROM Sales.Orders;

💡 作者强调:"通过显式指定架构名称,可以保证得到的对象的确是你原来想要的,而且不必付出任何额外的代价。"


错误3:NULL值的错误处理

问题表现:

-- 想找region不是WA的客户
SELECT * FROM Sales.Customers WHERE region <> &#x27;WA&#x27;;

这条查询不会返回region为NULL的行!因为 NULL <> 'WA' 的结果是 UNKNOWN,WHERE子句只保留 TRUE

正确做法:

SELECT * FROM Sales.Customers 
WHERE region <> &#x27;WA&#x27; OR region IS NULL;

💡 核心原则: SQL使用三值逻辑(TRUE/FALSE/UNKNOWN)。处理NULL时,必须显式考虑 IS NULL 或 IS NOT NULL。建议在表设计层面,对可能产生NULL的列设置默认值,减少NULL带来的逻辑复杂度。


错误4:TOP使用不当导致数据遗漏

问题表现: 取销量前5的产品,但当第5名有并列时,只返回了部分数据。

正确做法: 使用 WITH TIES

SELECT TOP (5) WITH TIES productid, sales
FROM Sales.OrderValues
ORDER BY sales DESC;

💡 WITH TIES 会返回所有与第5名销量相同的行,避免遗漏并列数据。


错误5:忽略隐式类型转换的性能代价

问题表现:

-- 假设orderid是INT类型
SELECT * FROM Orders WHERE orderid = &#x27;123&#x27;;

当字符串与整数列比较时,SQL Server会将列隐式转换为字符串——这会导致索引失效,触发全表扫描

正确做法:

-- 参数类型与列类型保持一致
SELECT * FROM Orders WHERE orderid = 123;

💡 延伸思考: 同样的原则适用于所有数据类型。用函数包裹列(如 WHERE YEAR(orderdate)=2024)也会导致索引失效,应改为范围查询 WHERE orderdate >= '2024-01-01' AND orderdate < '2025-01-01'


三、本期小结

| 错误类型 | 后果 | 正确姿势 | | --- | --- | --- | | SELECT * | 性能差、脆弱、网络浪费 | 显式列出列名 | | 省略架构名 | 解析开销、可能访问错误对象 | 始终写 Schema.Table | | NULL比较错误 | 结果集不完整 | 加上 IS NULL 条件 | | TOP无WITH TIES | 遗漏并列数据 | 使用 TOP WITH TIES | | 隐式类型转换 | 索引失效、全表扫描 | 参数类型与列类型一致 |


关于本书

《100 SQL Server Mistakes and How to Avoid Them》由Manning Publications出版,作者Peter A. Carter是拥有近20年SQL Server经验的资深专家,涵盖SQL Server开发、管理、高可用性和安全等全领域。

全书分为14章,共408页,采用问题/解决方案的实用格式,不写"Happy Path",而是直面真实世界中的错误和问题,非常适合初中级DBA和"意外成为DBA"的开发人员阅读。

本书第一章"Introducing SQL Server"从基础概念入手,后续章节将深入T-SQL开发、数据类型、索引设计、性能优化、高可用性等核心主题。


下期预告

📖 下期主题:《DBA 成长计划·第一季第2期》 我们将进入开发标准——为什么SQL01、DB01这样的命名会让故障排查多花几小时?如何建立一套让团队受益的数据库命名标准?以及跨表Join时数据类型不一致的隐形性能杀手。

💬 读者讨论: 你在工作中遇到过哪些因NULL处理不当导致的Bug?欢迎留言分享,我会在下期精选回复。


本文为学习笔记,内容基于《100 SQL Server Mistakes and How to Avoid Them》第一章提炼总结,作者Peter A. Carter,Manning Publications出版。