Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > SQL查询优化

SQL Server中千万级大表查询性能调优实战路径

作者:大勇前进

当 SQL Server 单表数据量突破千万级别,查询越来越慢几乎是必然会出现的问题,本文将结合生产实践为大家提供一套完整的调优流程,有需要的小伙伴可以了解下

当 SQL Server 单表数据量突破千万级别,“查询越来越慢”几乎是必然会出现的问题。很多同学一上来就加索引、改代码,结果收效甚微,甚至越调越慢。

真正有效的性能调优,不是靠“感觉”,而是靠一套可复现、可验证的步骤。本文结合生产实践,给你一套从“看现状 → 找瓶颈 → 精准优化 → 验证效果”的完整流程。

一、先别急着改:建立性能基线

调优的第一步,是搞清楚:现在到底有多慢?为什么慢?

1. 明确业务指标

不要只说“很慢”,要量化:

2. 抓取“坏 SQL”

使用 SQL Server 自带的工具定位问题 SQL:

-- 查看当前正在执行的请求
SELECT
    r.session_id,
    r.status,
    r.command,
    r.cpu_time,
    r.total_elapsed_time,
    t.text AS sql_text,
    p.query_plan
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) p
WHERE r.session_id <> @@SPID;

也可以用:

重点关注:

这些指标能告诉你:是 CPU 算得慢,还是 IO 读得多,还是等锁等得久

二、看执行计划:找到真正的“罪魁祸首”

千万级数据下,80% 的性能问题都写在执行计划里

1. 获取实际执行计划

在 SSMS 中按 Ctrl + M 打开“包含实际执行计划”,再执行你的 SQL。

重点看:

2. 常见“危险信号”

现象可能原因
Table Scan无合适索引
Key Lookup 多索引覆盖不足
Sort 溢出内存不足 / ORDER BY 不合理
预估行数偏差大统计信息过期

经验法则:千万级表,几乎不能容忍 Table Scan

三、索引优化:最值得投入的 20%

索引通常是性价比最高的优化手段。

1. 检查现有索引的使用情况

SELECT
    i.name AS index_name,
    i.type_desc,
    s.user_seeks,
    s.user_scans,
    s.user_lookups,
    s.user_updates
FROM sys.indexes i
JOIN sys.dm_db_index_usage_stats s
    ON i.object_id = s.object_id
   AND i.index_id = s.index_id
WHERE OBJECT_NAME(i.object_id) = 'YourBigTable';

关注:

2. 设计“对的”索引

千万级表建索引,有几个铁律:

WHERE + JOIN + ORDER BY 是核心

-- 示例
SELECT *
FROM Orders
WHERE CustomerID = @cid
  AND OrderDate >= @start
ORDER BY OrderDate;

推荐复合索引:

CREATE INDEX IX_Orders_CustomerID_OrderDate
ON Orders(CustomerID, OrderDate);

顺序原则

避免“索引失效”的写法

这些写法容易导致索引失效,触发全表扫描:

改写示例:

-- 不推荐
WHERE DATEDIFF(DAY, CreateTime, GETDATE()) > 7

-- 推荐
WHERE CreateTime < DATEADD(DAY, -7, GETDATE())

3. 覆盖索引(Covering Index)

如果查询只用到少数几列,尽量让索引“包圆”:

CREATE INDEX IX_Orders_Cover
ON Orders(CustomerID, OrderDate)
INCLUDE (TotalAmount, Status);

这样可以避免 Key Lookup,性能提升往往是数量级的。

四、统计信息:让优化器“看清”数据

SQL Server 优化器依赖统计信息来做决策。统计信息不准,索引再好也没用。

1. 检查统计信息状态

DBCC SHOW_STATISTICS ('Orders', IX_Orders_CustomerID_OrderDate);

关注:

2. 手动更新统计信息

UPDATE STATISTICS Orders WITH FULLSCAN;

或在维护窗口内定期执行:

EXEC sp_updatestats;

千万级表建议:关键索引使用 FULLSCAN,普通索引可用默认采样,并在业务低峰期执行。

五、SQL 语句本身:少干活,早过滤

很多时候,不是数据库不行,而是 SQL 写得“太勤奋”。

1. 减少返回的数据量

-- OFFSET / FETCH(SQL Server 2012+)
SELECT Id, Name, CreateTime
FROM Orders
ORDER BY CreateTime
OFFSET 100000 ROWS FETCH NEXT 50 ROWS ONLY;

前提是 CreateTime 上有索引。

2. 避免不必要的计算与排序

-- 不推荐
SELECT CustomerID, COUNT(*)
FROM Orders
GROUP BY CustomerID
HAVING COUNT(*) > 10;

-- 推荐
SELECT CustomerID, COUNT(*)
FROM Orders
WHERE Status = 'Active'
GROUP BY CustomerID;

六、表结构与存储:从“根”上减负

当索引和 SQL 都优化到位后,就该看“数据本身”了。

1. 分区表(Partition Table)

千万级甚至亿级数据,强烈建议考虑分区表:

-- 按日期分区示例
CREATE PARTITION FUNCTION pf_OrderDate (DATETIME)
AS RANGE RIGHT FOR VALUES
('2024-01-01', '2024-07-01', '2025-01-01');

CREATE PARTITION SCHEME ps_OrderDate
AS PARTITION pf_OrderDate ALL TO ([PRIMARY]);

优势:

2. 数据类型精简

每少 1 字节,千万行就是 10MB 的差距:

3. 归档历史数据

不是所有数据都要放在“热表”里:

七、服务器与配置:别让硬件拖后腿

1. 内存:最重要的资源

千万级表,数据页能否留在内存,直接决定性能。

SELECT *
FROM sys.dm_os_performance_counters
WHERE counter_name = 'Page life expectancy';

2. TempDB:隐藏的性能杀手

排序、哈希连接、临时表都用到 TempDB。

优化建议:

3. 参数嗅探(Parameter Sniffing)

同一个存储过程,有时快有时慢,很可能是参数嗅探问题。

应对方式:

八、一个简化的调优流程清单

实际工作中,可以按这个顺序来:

  1. 确认问题 SQL(Profiler / DMV)
  2. 查看执行计划(找 Scan / Lookup / Sort)
  3. 检查索引(缺失 / 冗余 / 覆盖)
  4. 更新统计信息
  5. 改写 SQL(减少数据量、避免函数)
  6. 评估分区 / 归档
  7. 检查服务器配置(内存 / TempDB)
  8. 验证效果并固化(索引 + 定时维护)

九、总结

千万级大表的性能调优,不是“一招鲜”,而是一个系统工程

记住一句话:先测量,再优化;先整体,再局部;先低成本,再高风险

到此这篇关于SQL Server中千万级大表查询性能调优实战路径的文章就介绍到这了,更多相关SQL查询优化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文