加入收藏 | 设为首页 | 会员中心 | 我要投稿 站长网 (https://www.024zz.com.cn/)- 区块链、CDN、AI行业应用、人脸识别、应用程序!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

SQL Server数据库设计避坑12实战要点

发布时间:2026-10-22 14:28:24 所属栏目:MsSql教程 来源:DaWei
导读:  去年6月,我蹲在客户机房里改索引,空调坏了,冷凝水一滴一滴砸在机柜顶上,咚、咚、咚——像给DDL倒计时。DBA老张蹲在对面拧散热扇螺丝,拧到第三颗时,他手机响了,接起来就吼:“不是说了别动主库吗!”——结果那边挂得比他拧

  去年6月,我蹲在客户机房里改索引,空调坏了,冷凝水一滴一滴砸在机柜顶上,咚、咚、咚——像给DDL倒计时。DBA老张蹲在对面拧散热扇螺丝,拧到第三颗时,他手机响了,接起来就吼:“不是说了别动主库吗!”——结果那边挂得比他拧螺丝还快。


  我原以为分区表加个DATE列就能扛住三年数据滚动,结果上线第三周,查询计划里全蹦出“分区消除失败”。查了一下午,发现是WHERE里写了GETDATE()-1,SQL Server愣是没推导出分区边界,连hint都救不回来。这个我敢打包票:任何带函数的WHERE,只要碰分区列,你就等于在分区头上贴胶带——看着粘上了,一拉就脱。


  还有那个NVARCHAR(4000)当主键的表。开发说“怕不够用”,我说“你存四十万字小说也用不完”,他笑嘻嘻敲回车确认了。结果半年后唯一约束开始抖,插入时偶尔卡住十八秒。不是死锁,是内部哈希冲突。你信不信?SQL Server对NVARCHAR主键做哈希的时候,真会把前28个字符扔进桶里,后面全当空气。我们最后改成BIGINT + 计算列映射,重写迁移脚本那天,运维小李端着凉透的黄焖鸡进来,筷子尖蘸着酱,在白板上划了个歪歪扭扭的箭头。


  非空约束?呵。我们有个表叫OrderHeader,CreatedTime NOT NULL,但实际业务方传NULL进来,开发图省事加了个DEFAULT GETDATE(),再加个INSTEAD OF INSERT触发器兜底。结果某天凌晨三点,订单流水号断层了——触发器里少判了一种INSERT...SELECT场景,导致两百单直接塞进同毫秒。我删掉触发器那行代码时,窗外正好打雷,闪电照见墙上贴着的旧版《SQL Server 2016兼容性矩阵》,边角卷起来了。


  说到兼容性。上个月帮兄弟团队看慢查,执行计划里全是“隐式转换”。一扒参数类型,C#传的是DateTime,SP里声明的是DATETIME2(3),结果引擎硬生生给每个参数套CAST。这种坑不报错,只吃CPU。我们抓包抓了三小时,最后是测试妹子端着咖啡杯晃进来,说她刚跑完接口压测,JMeter线程数调高了五倍——她说话时耳钉在闪,我盯着那点光,忽然想起十年前在西二旗一个地下室改过同样的事,也是耳钉,也是咖啡渍泼在键盘上。


  外键……哎,外键这东西吧。去年6月那个项目,主子表搞了级联DELETE,逻辑看着漂亮。结果某天财务导数脚本手误多加了个WHERE,删掉三百条主记录,连带删掉六万七千条子表数据。恢复花了四小时。没人骂语法,都骂“怎么没设RESTRICT”。我说RESTRICT也不保险,你查不出级联路径的执行树——SSMS里右键“查看依赖关系”,它压根不显示跨库外键。这点我说不准,但我知道去年有三个项目翻车在外键没建反向索引上,其中俩还是用SSDT自动生成的。


  哦对,临时表命名。他们非要用#TempOrderResult_2023,我拦不住。后来报表服务器半夜崩了两次,查出来是tempdb里堆了八百多个类似名字的缓存计划。不是内存不足,是编译缓存哈希桶撞得太密。DBA老张后来改了命名规范,要求带session_id后缀,但他改完第一周就去休陪产假了,走之前把笔记本留在工位上,封面印着“SQL Server 2019 Query Store实战指南”,第78页折了个角。


  索引碎片。有人还在看sys.dm_db_index_physical_stats的avg_fragmentation_in_percent。真不如盯PAGEIOLATCH_SH等待。上个月我盯着一个视图跑了十七遍,统计信息更新过,索引重建过,执行计划也固化过,就是慢。最后发现是基础表用了ROW_NUMBER() OVER (ORDER BY ID)当伪主键,而ID是GUID,物理存储乱得像泡面。索引重建根本治标不治本——因为每insert一行,页就裂一次。这种设计,你加十个覆盖索引都不如换个顺序键。


  还有人迷信SSIS包里建表。我见过一个ETL流程,每次运行都DROP再CREATE staging表,表名带时间戳。结果tempdb日志文件每天长两百兆。问为啥不用TRUNCATE?开发说“TRUNCATE不记日志,审计过不去”。我说你这INSERT又没开启XACT_ABORT,万一中间失败,半截数据卡在那儿,审计更过不去。他低头扒拉键盘,指甲缝里嵌着蓝墨水,像是上周签纸质变更单留下的。


  关于“优胜劣汰”这个说法……说实话,我有点后怕。不是怕设计差,是怕活下来的全是侥幸——比如那个没加CHECK约束的钱包余额字段,靠应用层try-catch防负数;比如那个把JSON塞NVARCHAR(MAX)却从不validate的配置表,至今没爆,只是因为前端永远传标准格式。它们没死,不是因为设计好,是因为还没碰到那个刚好触发BUG的业务分支。这种幸存者偏差,比任何显式错误都难修。


  我桌上现在还摆着六月的故障复盘纪要打印件,纸边被咖啡洇湿了一块。第一页写着“建议统一使用datetime2(0)”,第二页就粘着张便利贴,字是老张写的:“改完了,但同步脚本里漏了一个convert”。我昨天把它揭下来,没扔,夹进了新买的《T-SQL Window Function Patterns》里——书还没翻,封底还沾着一点黄焖鸡的油印。


文章配图,仅供参考

  下次再遇到要建第一个表的项目,我不急着画ER图。先去机房坐十分钟,听空调声,数冷凝水滴数,等谁接个电话,看谁端外卖进来。有些坑不在DDL里,在人喘气的节奏里。

(编辑:站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!