You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server查询性能优化:如何提升物品巡检查询速度?

优化巡检物品查询性能的方案

表结构说明

Collections  
-Id

CollectionItems(一组物品中的单个物品)  
-Id  
-Name  
-CollectionId  
-NotAvailable  
-LastInspectionDate

ItemReports(物品巡检报告)  
-Id  
-CollectionItemId  
-ReportDate

需求概述

展示指定集合内的所有物品列表,其中需包含最新实际巡检日期:

  • 巡检找到物品时,NotAvailable为0且生成ItemReports记录,取最新的ReportDate
  • 巡检未找到物品时,NotAvailable填入原因ID且无报告,取CollectionItems的LastInspectionDate
    原查询功能正常,但300+物品的集合查询耗时超30秒,需优化性能,优先采用单查询实现。

原查询代码

SELECT 
    CollectionItems.*,
    ISNULL(MAX(CASE WHEN ItemReports.NotAvailable = 0 THEN ReportDate END), 
    CollectionItems.LastInspectionDate) AS LastActualDate
FROM 
    CollectionItems
LEFT JOIN 
    ItemReports ON ItemReports.CollectionItemID = CollectionItems.Id

优化方案

1. 添加针对性索引

索引是性能提升的核心,需创建以下索引减少扫描范围:

  • 针对CollectionItems的CollectionId创建索引,同时包含查询所需字段,加快集合过滤和数据读取:
    CREATE NONCLUSTERED INDEX IX_CollectionItems_CollectionId ON CollectionItems (CollectionId)
    INCLUDE (Id, Name, NotAvailable, LastInspectionDate);
    
  • 针对ItemReports创建复合索引,按CollectionItemId分组、ReportDate降序排列,覆盖NotAvailable字段,让MAX()操作直接获取最新记录:
    CREATE NONCLUSTERED INDEX IX_ItemReports_CollectionItemId_ReportDate ON ItemReports (CollectionItemId, ReportDate DESC)
    INCLUDE (NotAvailable);
    

2. 重构查询避免全表连接

原查询先全量左连接再聚合,会生成大量中间数据。推荐先预取每个物品的最新有效报告日期,再关联主表:

方式一:使用CTE预取最新报告

WITH LatestValidReports AS (
    SELECT 
        CollectionItemId,
        MAX(ReportDate) AS LatestReportDate
    FROM ItemReports
    WHERE NotAvailable = 0
    GROUP BY CollectionItemId
)
SELECT 
    ci.*, -- 建议替换为具体需要的字段,减少IO开销
    ISNULL(lvr.LatestReportDate, ci.LastInspectionDate) AS LastActualDate
FROM CollectionItems ci
LEFT JOIN LatestValidReports lvr ON ci.Id = lvr.CollectionItemId
WHERE ci.CollectionId = @TargetCollectionId; -- 必须指定目标集合ID,避免全表扫描

方式二:使用关联子查询

SELECT 
    ci.*, -- 建议替换为具体需要的字段
    ISNULL(
        (SELECT MAX(ReportDate) FROM ItemReports ir WHERE ir.CollectionItemId = ci.Id AND ir.NotAvailable = 0),
        ci.LastInspectionDate
    ) AS LastActualDate
FROM CollectionItems ci
WHERE ci.CollectionId = @TargetCollectionId;

3. 关键优化细节

  • 提前过滤集合:必须加上WHERE ci.CollectionId = 目标集合ID,只处理指定集合的物品,避免扫描全表。
  • **避免SELECT ***:如果CollectionItems包含大字段(如文本、二进制数据),只选择需要展示的字段,减少磁盘IO和内存占用。

内容的提问来源于stack exchange,提问作者Sparrowhawk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 09:07:43