SQL Server数据库设计避坑指南:12个实战关键点
|
跟人吵架那天,机房空调坏了,吹着热风,老张蹲在机柜底下拿万用表量PDU电压,后颈全是汗——他根本没听我说完“聚簇索引列顺序”,就接了个电话,说“喂妈,我马上回”,然后挂了,转身拧紧一颗松动的导轨螺丝。 第1个坑:非空约束不加NOT NULL。不是性能问题,是尊严问题。我原以为DBA和开发吵这个纯属抬杠,结果2026年1月那个OLTP库上线第三天凌晨两点十七分,一个UPDATE语句锁了三十七张表,只因WHERE里拼了个NULL = NULL——SQL Server自己都懒得优化这玩意,直接走嵌套循环。同事小王当时啃着冷掉的肉夹馍,馍渣掉进键盘缝里,他边抠边说“反正有索引”,我说“你查执行计划了吗”,他敲F5重编译,屏幕蓝了一下,不是Windows,是SSMS崩了。 第2个坑:把GUID当主键还默认NEWID()。这个我敢打包票,它比磁盘碎片还害人。你建个五千万行的订单表,再做一次ALTER INDEX REBUILD,别管填充分数设多少,重建完物理读暴增,不是因为IO慢,是因为页裂得太碎——每插一条,就得撕开一整页塞进去,像往装满弹珠的玻璃罐里硬塞一颗新弹珠。那天下午暴雨,窗框漏雨,水滴在测试服务器机箱顶盖上“嗒、嗒、嗒”,我们盯着I/O延迟图里的锯齿线,没人说话。老张后来改用NEWSEQUENTIALID(),可迁移脚本写错了一位,导致某批历史数据的GUID开头全是0x00……算了,不提了。 第3个坑:text/ntext/image还活着?去年十月我见个客户库里真有三个ntext字段,存的是JSON片段,全表扫描时CPU干到98%,SQL Server 2019执行计划里居然还给你标个“LOB logical reads: 287K”。我说换varchar(max),对方DBA搓着手指头笑:“怕迁移丢数据。”我说:“那你先试试SELECT TOP 1 SUBSTRING([notes], 1, 10) FROM logs”——他试了,返回空字符串。不是NULL,是空。他愣住,我去倒了杯凉透的咖啡,咖啡渣沉在杯底,像淤泥。 第4个坑:把计算列当普通列加索引,却不persist。这事儿我服气——SQL Server真能算,但算得越准,越拖死你。有个报表库,计算列是CONVERT(date, [created_time]),建了非聚集索引,查询跑得飞起;上线三天后,用户说“昨天还能查12小时的数据,今天卡死”。我查发现统计信息陈旧,手动UPDATE STATISTICS,没用;最后发现是自动更新阈值被调成0.1%——那表四亿行,0.1%就是四十万行变更才触发更新。小王这时候突然喊:“等等!这列没PERSISTED!”我盯着他手边的AirPods左耳掉了,他正单手捏着往耳朵里塞。 第5个坑:外键没加索引。不说了,上周五刚出的事。关联订单和客户,外键在customer_id上,没索引,DELETE客户时级联删三万订单,耗时三百七十二秒。运维老李坐在工位上,用指甲刮键盘缝隙里的糖霜——前两天团建发的甜甜圈,他吃完没擦手。他看我截图EXEC sp_whoisactive,突然说:“我上个东家也这么干,删个客户,连带把CRM的短信队列都压爆了。”我没接话,窗外雷声闷响,像远处有台柴油发电机启动失败。
文章配图,仅供参考 第6个坑:用datetime而非datetime2(3)。不是精度不够,是存储浪费和隐式转换陷阱。有个金融对账模块,JOIN条件里一边datetime,一边datetime2,执行计划显示“隐式转换:datetime → datetime2”,扫完两千万行,缓存全被这种小转换占满。我改完,清缓存,重跑,时间从十九秒降到一点二秒。但当天下午就收到邮件,说下游ETL作业挂了——它们依赖sys.columns里的user_type_id=40,而datetime2是42。我盯着邮件发了会儿呆,桌上的泡面盒歪了,汤全洒在鼠标垫上,黏糊糊的。第7个坑:过度归档,分区分表却忘建分区函数范围边界。这个我说不准。有次迁移老库,他们按月建了六十四张分区表,但没用PARTITION SCHEME,纯靠视图UNION ALL,然后告诉我“查询快”。我写了等价的SELECT FROM [orders_202501] WHERE…,和SELECT FROM orders_all WHERE order_date >= '2025-01-01',前者0.3秒,后者8.7秒。为什么?因为SQL Server根本没跳过其他五十九个表。可到底该不该强制分区裁剪?我现在看到CREATE PARTITION FUNCTION就犯怵。 第8个坑:用sp_rename改列名——这事儿本身不致命,但会毁掉所有引用它的视图、函数、SSIS包的元数据依赖链。我们曾在一个生产库上rename了一个price_old为unit_price,第二天BI组发来截图:Power BI报表里字段全变#ERROR。老张当时正在调试SSD寿命监控脚本,嘴里念叨着“SMART状态是0xC3,C3你知道是什么意思吗”,我摆摆手让他闭嘴,低头重写了一个带sys.dm_exec_describe_first_result_set的校验SQL。 第9个坑:没配max server memory,让SQL Server吃光系统内存,OS开始杀进程。这事不新鲜,但上次发生时,它顺手干掉了监控agent,而告警邮件依赖那个agent发……最后是我们用手机查了Windows事件日志,ID 17890。小王说“应该加个外部心跳检测”,我说“你先把你那Excel里的连接字符串密码改成变量再说”。他愣了一下,摸出手机给媳妇发微信:“今晚不回去了”,然后关了屏幕。 第10个坑:全文索引不维护。客户抱怨搜索变慢,我查sys.fulltext_indexes,看到population_status是0(idle),last_population_date是三个月前。问他“谁负责刷新”,他指指墙上排班表——那页纸被风吹起一角,粘在打印机出纸口。我叹了口气,没再问。 第11个坑:误信“大表必分片”,在单实例上搞跨数据库JOIN,又不建同义词或链接服务器。有个库存系统,把商品主数据放master库,交易放sales库,SELECT FROM master.dbo.products p JOIN sales.dbo.orders o ON p.id = o.product_id……执行计划里赫然出现“Remote Query”。不是分布式查询,是本地发起、远程执行、再本地聚合。那个查询跑了十八秒,而我把两个表COPY到同一库,0.4秒。可没人愿意挪数据——“流程不允许”。 第12个坑:相信文档。SQL Server在线丛书写着“ALTER TABLE … SWITCH分区转移毫秒级”,我信了。实测时,目标分区未清理、源表CHECK约束冲突、权限不对、甚至目标表上有个没注意的启用CDC……SWITCH直接报错回滚,日志暴涨。我在错误日志里翻了四十三分钟,找到那行“The target table must be empty”,然后想起上周五下班前,小王顺手往target表INSERT了一条测试数据,没删。他此刻正蹲在茶水间修饮水机,说“水管老化,接头漏了”,水滴在拖鞋上,哒、哒、哒。 这些坑现在看都是优胜劣汰筛出来的——活下来的DBA,要么早年踩过,要么抄过别人的血泪清单。但我最近开始怀疑:是不是该留一个“故意不优化”的坑?比如,某个字段明知要高频筛选,偏不加索引,只为逼开发写好参数化查询……算了,这事得下周晨会再说。明天我要去机房换风扇滤网,听说新来的实习生已经把三台服务器的网线标签全撕了。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


创业科技合规避坑指南:政策红线、数据安全与技术底线
深度学习服务器选型避坑指南:GPU显存到NVLink调优实战
Linux新手避坑指南:12年工程师实战安装配置
网站搭建总卡壳?运维实习生避坑指南
嵌入式Linux开发者Unix环境搭建避坑指南
Windows数据科学环境搭建:17年UI运维师避坑指南
