SQL SERVER SQL 优化指南 四句真言 (SQL 优化系列 2)
❝开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, OceanBase, Sql Server等有问题,有需求都可以加群群内有各大数据库行业大咖,可以解决你的问题。加群请联系 liuaustin3 ,(共3300人左右 1 + 2 + 3 + 4 +5 + 6 + 7 + 8 +9)(1 2 3 4 5 6 7群均已爆满,开8群近400 9群 200+,开10群PolarDB专业学习群100+)
SQL 优化四字真言系列
PostgreSQL SQL 优化指南 四句真言(SQL 优化系列 1)
上期说完PostgreSQL 数据库,这期咱们说说MSSQL,也就是SQL SERVER的SQL优化指南。SQL SERVER 作为中小企业,现在应该是外企最喜欢的数据库产品,是有道理的,他比ORACLE更便宜,但不比ORACLE在SQL计算上差,同时基于WINDOWS的系统之上,他的操作更多的是鼠标化的方式,当然命令的方式也很丰富。这里最值得称赞的事,MSSQL本身的自动化能力很强,尤其在最新版本的2025,SQL的优化已经可以基本AI话,自动化,历史数据分析化了。
但SQL SERVER的SQL优化也有自己的特色,这里也有四句真言:
索引为王,聚集最快,要想更快就上包含,
统计信息,一定要准,真要不行,马上RCL,
并行厉害,但要有度,单条语句也能控制,
日志重要,性能关键,实在不行给点好盘。
作为SQL SERVER的老手,我自己还藏了一招,四句真言里面的第五句是,真要不行,CI 独上。
下面我们逐步分解者几句,并找案例
1 SQL SERVER 中索引是提高查询速度的关键,而SQL SERVER里面的索引有一个特别有意思的地方,这点是搞ORACLE, PG DBA所不理解,不明白,想不通的地方。 聚集索引,也就是SQL SERVER 可以和MySQL一样在建表时将主键和行的物理位置进行绑定,也就是说,在MYSQL中的一些优化原理,在MSSQL的聚集索引上也是有效的,比如UPDATE + 聚集索引条件,他一定比你UPDATE + 二级索引要快,这也是MSSQL的DBA 上手MySQL容易得一个原因(仅限SQL执行层面)。
同时MSSQL 还有一个原来的查询的杀手锏,include索引,这个功能PG到PG11才引入进来。MSSQL 的一些 SELECT 一堆字段的优化就可以通过include索引来解决回表的问题,通过索引就完全返回数据,对于一些大表和字段多的查询是有利的。
CREATE TABLE Orders (
OrderID INT PRIMARY KEY,
CustomerID INT NOT NULL,
OrderDate DATETIME NOT NULL,
Amount DECIMAL(10,2) NOT NULL
);
比如上面的建表,在MSSQL ,同样是查询
SELECT *
FROM Orders
WHERE CustomerID = 1001;
对比
SELECT *
FROM Orders
WHERE OrderID = 1001;
那个更快,在有主键 orderID 和 CustomerID 二级索引的情况下,那一定是主键的查询更快,这是ORADLE 和 PG DBA所一时间不能理解的,MySQL DBA会明白这个道理。
而如果非要比较,如果在不显示主键的情况下,建立include索引必然是要比单独建立CustomerID索引要快。
CREATE NONCLUSTERED INDEX IX_Orders_CustomerID_Include
ON Orders(CustomerID)
INCLUDE (OrderDate, Amount);
统计信息对于任何数据库都很重要,一般来说不是突然的插入,更改,删除大量的数据是不会导致MSSQL的统计信息不对导致SQL操作的执行计划失误的。但我们还是要留一手,
MSSQL的统计信息分为直方图,密度向量,和更新行数等信息,这里我们可以手动去触发一个表的统计信息更新如,
UPDATE STATISTICS dbo.Orders;
如果你不手动,那么自动更新的方式会以默认约 20% + 500行 变化时更新统计信息的信息。但还是会在一些较大场景下,不及时的情况,所以手动更新统计信息的方式还是要会的。
-- 开启自动创建统计信息
ALTER DATABASE MyDB SET AUTO_CREATE_STATISTICS ON;
-- 开启自动更新统计信息
ALTER DATABASE MyDB SET AUTO_UPDATE_STATISTICS ON;
-- 开启异步更新统计信息(不阻塞查询)
ALTER DATABASE MyDB SET AUTO_UPDATE_STATISTICS_ASYNC ON;
建议:
OLTP系统 → AUTO_UPDATE_STATISTICS ON 即可
大规模OLAP / 数据仓库 → 建议定期手动更新(FULLSCAN),并可考虑 ASYNC 避免阻塞
同时是MSSQL 对于数据倾斜的情况有一些解决方案,这里就不在初级的指南里面讨论了。
关于四句真言中的第二句的RCL,意思是抛弃执行计划的缓存,每次执行语句都需要进行重新编译。
SELECT *
FROM Orders
WHERE CustomerID = @cid
OPTION (RECOMPILE);
第三句中的并行很厉害,SQL SERVER中的并行的确在这么多数据库中,我个人认为是将并行用到极致的,甚至到了一种病态的状态,到了并行滥用的境地。对于MSSQL的并行在之前的使用经验里面基本上复杂的SQL,所有的CPU单元都给你用上,到时IOPS出现问题的情况比比皆是,IOPS超高又会导致累积现象,让SQL运行越来越慢,越慢越DOP。所以一些复杂的SQL,建议控制一下DOP的使用。
我们可以在一些OLAP的语句中直接加入MAXDOP的参数如下
SELECT ...
FROM table
OPTION (MAXDOP 8); -- 指定并行度
数字式这个SQL可以最大使用多少CPU线程来并行执行这条SQL。一句话合理控制并行度MAXDOP的参数,关注一些SQL的数据倾斜,减少Gather Streams的时间,可以从全局上先控制 max degree of parallelism (MAXDOP) 的大小,然后在从一些语句上进行细调找到合适DOP。
最后一句与一些语句的UPDATE的效率,INSERT,和DELETE的效率有关,再多的操作都是要串行写入LDF文件的,LDF文件的写入速度的快慢,就决定了你的事务中的UPDATE INSERT DELETE语句的执行效率,这里可以把日志文件放到单独的 NVME ,SSD磁盘上降低大事务,频繁小事务对于COMMIT的压力。
最后我们以一个案例结束,假设我们有以上的一些表,
customers(cust_id, name, country) → 用户
orders(order_id, cust_id, order_date, status, total_amount) → 订单
order_items(order_id, product_id, quantity, price) → 订单明细
products(product_id, category_id, name, price) → 商品
categories(category_id, name) → 商品分类
找出 最近一年内下过订单的客户,并且这些客户购买过 至少一个“电子产品”类的商品,再统计这些客户的订单总额。
SELECT c.cust_id,
c.name,
SUM(o.total_amount) AS total_spent
FROM customers c
JOIN orders o
ON c.cust_id = o.cust_id
WHERE o.order_date >= DATEADD(year, -1, GETDATE())
AND c.cust_id IN (
SELECT o2.cust_id
FROM orders o2
JOIN order_items oi ON o2.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
JOIN categories cat ON p.category_id = cat.category_id
WHERE cat.name = 'Electronics'
)
AND EXISTS (
SELECT 1
FROM orders o3
WHERE o3.cust_id = c.cust_id
AND o3.status = 'Completed'
)
GROUP BY c.cust_id, c.name
HAVING SUM(o.total_amount) > 1000
ORDER BY total_spent DESC;
这样的语句在之前MSSQL的经验中经常遇到,主要有两个问题
1 IN 中的数据集太大执行效率慢的问题 2 Exists 子查询会多次扫描order表的问题
WITH cust_with_electronics AS (
SELECT DISTINCT o2.cust_id
FROM orders o2
JOIN order_items oi ON o2.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
JOIN categories cat ON p.category_id = cat.category_id
WHERE cat.name = 'Electronics'
)
SELECT c.cust_id,
c.name,
SUM(o.total_amount) AS total_spent
FROM customers c
JOIN orders o
ON c.cust_id = o.cust_id
JOIN cust_with_electronics ce
ON c.cust_id = ce.cust_id
WHERE o.order_date >= DATEADD(year, -1, GETDATE())
AND EXISTS (
SELECT 1
FROM orders o3
WHERE o3.cust_id = c.cust_id
AND o3.status = 'Completed'
)
GROUP BY c.cust_id, c.name
HAVING SUM(o.total_amount) > 1000
ORDER BY total_spent DESC;
这样修改的好处主要在 1 使用CTE方式可以先对买过电子产品的用户进行筛选,并且语句观感也更加的清晰。 2 将之前的IN改成JOIN,IN 与 JOIN 之间的效率关系,在这里就不多讲了,已经讲烂了。 3 EXISTS 属于办理案件,可以避免不必要的聚合。
但是 ,但是,但是,如果你使用是SQL SERVER 2022以上版本包含2022 那么我的语句根本不用改,新版本的SQL SERVER 支持了 QOE功能,可以自动把这些写的不怎么样的语句进行重写,同时通过AJ功能,自动适应Nested loop or Hash Join的方式,最后还可以使用2019版本提供的批模式执行,当然这里还么有用到物化索引,那个部分我就不想讲了,自己的留一个高技能留着。
同时还有一堆的新功能如 QS,psp,CI功能,这个就不讲了。
基于SQL SERVER在SQL执行中的智能化,AI化,之前文章也写过2025版本的厉害,相信更先进的SQL SERVER必定能让烂SQL优化更加不需要人工的介入。
微软动手了,联合OpenAI + Azure 云争夺AI服务市场
“当复杂的SQL不再需要特别的优化”,邪修研究PolarDB for PG 列式索引加速复杂SQL运行
“合体吧兄弟们!”——从浪浪山小妖怪看OceanBase国产芯片优化《OceanBase “重如尘埃”之歌》
未知黑客通过SQL SERVER 窃取企业SAP核心数据,影响企业运营
那个MySQL大事务比你稳定,主从延迟低,为什么? Look my eyes! 因为宋利兵宋老师
非“厂商广告”的PolarDB课程:用户共创的新式学习范本--7位同学获奖PolarDB学习之星
说我PG Freezing Boom 讲的一般的那个同学,专帖给你,看看这次可满意
这个 PostgreSQL 让我有资本找老板要 鸡腿 鸭腿 !!
OceanBase Hybrid search 能力测试,平换MySQL的好选择
HyBrid Search 实现价值落地,从真实企业的需求角度分析 !不只谈技术!
OceanBase 光速快递 OB Cloud “MySQL” 给我,Thanks a lot
从“小偷”开始,不会从“强盗”结束 -- IvorySQL 2025 PostgreSQL 生态大会
被骂后的文字--技术人不脱离思维困局,终局是个 “死” ? ! ......
个群2025上半年总结,OB、PolarDB, DBdoctor、爱可生、pigsty、osyun、工作岗位等
从MySQL不行了,到乙方DBA 给狗,狗都不干? 我干呀!
SQL SERVER 2025发布了, China幸亏有信创!
MongoDB 麻烦专业点,不懂可以问,别这么用行吗 ! --TTL
PostgreSQL 新版本就一定好--由培训现象让我做的实验
删除数据“八扇屏” 之 锦门英豪 --我去-BigData!
写了3750万字的我,在2000字的OB白皮书上了一课--记 《OceanBase 社区版在泛互场景的应用案例研究》
跟我学OceanBase4.0 --阅读白皮书 (OB分布式优化哪里了提高了速度)
跟我学OceanBase4.0 --阅读白皮书 (4.0优化的核心点是什么)
跟我学OceanBase4.0 --阅读白皮书 (0.5-4.0的架构与之前架构特点)
跟我学OceanBase4.0 --阅读白皮书 (旧的概念害死人呀,更新知识和理念)
MongoDB 相关文章
MongoDB “升级项目” 大型连续剧(4)-- 与开发和架构沟通与扫尾
MongoDB “升级项目” 大型连续剧(3)-- 自动校对代码与注意事项
MongoDB “升级项目” 大型连续剧(2)-- 到底谁是"der"
MongoDB “升级项目” 大型连续剧(1)-- 可“生”可不升
MongoDB 大俗大雅,上来问分片真三俗 -- 4 分什么分
MongoDB 大俗大雅,高端知识讲“庸俗” --3 奇葩数据更新方法
MongoDB 大俗大雅,高端的知识讲“通俗” -- 2 嵌套和引用
MongoDB 大俗大雅,高端的知识讲“低俗” -- 1 什么叫多模
MongoDB 合作考试报销活动 贴附属,MongoDB基础知识速通
MongoDB 使用网上妙招,直接DOWN机---清理表碎片导致的灾祸 (送书活动结束)
MongoDB 2023年度纽约 MongoDB 年度大会话题 -- MongoDB 数据模式与建模
免费PolarDB云原生课程,听课“争”礼品,重塑云上知识,提高专业能力
“PostgreSQL” 高性能主从强一致读写分离,我行,你没戏!
POLARDB 添加字段 “卡” 住---这锅Polar不背
PolarDB 版本差异分析--外人不知道的秘密(谁是绵羊,谁是怪兽)
PolarDB 答题拿-- 飞刀总的书、同款卫衣、T恤,来自杭州的Package(活动结束了)
PolarDB for MySQL 三大核心之一POLARFS 今天扒开它--- 嘛是火
PostgreSQL 无服务 Neon and Aurora 新技术下的新经济模式 (翻译)
“PostgreSQL” 高性能主从强一致读写分离,我行,你没戏!
全世界都在“搞” PostgreSQL ,从Oracle 得到一个“馊主意”开始
PostgreSQL 加索引系统OOM 怨我了--- 不怨你怨谁
PostgreSQL “我怎么就连个数据库都不会建?” --- 你还真不会!
PostgreSQL 稳定性平台 PG中文社区大会--杭州来去匆匆
PostgreSQL 分组查询可以不进行全表扫描吗?速度提高上千倍?
POSTGRESQL --Austindatabaes 历年文章整理
PostgreSQL 查询语句开发写不好是必然,不是PG的锅
MySQL相关文章