sqlserver高级教程
很多人用 SQL Server 十年,依然在写 `SELECT *`,依然搞不清 `NOLOCK` 到底锁了什么。问题不在经验,在于没人逼你往下看一层。
先聊执行计划。你写一条查询,SQL Server 拿到后不是直接跑,它先算。算走哪个索引、用哪种连接、要不要并行。你打开 SSMS,按 Ctrl+M,再执行,那个图形化执行计划里藏着真相。我见过一个案例:同一张表,同一组条件,只是把 `WHERE CreateDate > '2023-01-01'` 改成 `WHERE CreateDate >= '2023-01-01'`,执行计划从索引扫描变成索引查找,逻辑读从 12000 降到 37。差一个等号,差三个数量级。执行计划里每个箭头粗细代表数据量,鼠标悬停能看到实际行数和预估行数。预估和实际差得离谱,统计信息多半过期了。`UPDATE STATISTICS` 不是玄学,是刚需。
索引这块,聚集索引不是随便选的。它决定数据物理存储顺序,一张表只能有一个。选错了,所有非聚集索引都跟着遭殃,因为非聚集索引的叶子节点存的是聚集索引键。你把聚集索引建在 `NEWID()` 生成的 GUID 列上,每次插入都随机写,页分裂频繁,碎片率飙升。换成自增 INT 或者有序 GUID,插入变成追加,碎片率能压在 1% 以下。`sys.dm_db_index_physical_stats` 这个 DMV 能看碎片率,超过 30% 考虑重建,5% 到 30% 之间重组就行。重建是离线操作,企业版可以 ONLINE=ON,标准版不行,得挑维护窗口。
锁和隔离级别,别只会 `WITH (NOLOCK)`。那玩意儿读脏数据,还可能读到重复行。真正要减少阻塞,先看 `sys.dm_tran_locks`,看谁锁了谁。读已提交快照(RCSI)是个好东西,开启后读操作不阻塞写,写不阻塞读,代价是 tempdb 压力上升。`ALTER DATABASE YourDB SET READ_COMMITTED_SNAPSHOT ON`,执行时得等所有连接断开,或者用 `WITH ROLLBACK IMMEDIATE` 强制踢人。生产环境慎用后者,但维护窗口里可以。
参数嗅探是个老坑。存储过程第一次执行时,优化器根据传入的参数值生成计划,之后复用。如果第一次传的是“稀有值”,计划针对稀有值优化,后来传“常见值”,计划就废了。解决办法不是重编译所有存储过程,那太粗暴。可以用 `OPTION (RECOMPILE)` 让每次执行都重新编译,代价是 CPU 升高。或者用 `OPTIMIZE FOR UNKNOWN`,让优化器用平均密度而不是具体值。再或者,把参数赋值给局部变量,但这样优化器也看不到值了,可能选更差的计划。没有银弹,看场景选。
内存配置有个常见的误区:把 max server memory 设成物理内存的 80%。这没错,但别忘了 SQL Server 还要给操作系统留空间,给其他进程留空间。一台 64GB 的机器,设 51GB 左右比较稳。设太高,操作系统开始换页,SQL Server 反而变慢。`sys.dm_os_process_memory` 能看到实际用了多少。还有,锁内存页(Lock Pages in Memory)这个策略,在虚拟化环境里不一定管用,得看宿主机怎么配。
备份不是 `BACKUP DATABASE` 就完事了。你得试恢复。我见过备份文件损坏,恢复时才发现,那时候已经晚了。`RESTORE VERIFYONLY` 能验证备份集完整性,不实际恢复,但能查出大部分问题。完整恢复模式下,事务日志备份不能断链,断一次就得做完整备份重新开始。日志文件别设自动收缩,那玩意儿碎片化日志,性能杀手。设个合理初始大小,让它自己长。
最后说个冷门的:`sys.dm_exec_query_stats` 配合 `sys.dm_exec_sql_text`,能找出历史上最耗 CPU、最多逻辑读的查询。按 `total_worker_time` 排序,前十条往往就是系统变慢的元凶。这个查询我每周跑一次,比任何监控工具都直接。
本文地址:http://www.79wt.cn/news/1925e1099797.html
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。