【问题标题】:Slow SQL Update using sub query使用子查询进行慢速 SQL 更新
【发布时间】:2018-08-24 19:58:27
【问题描述】:

大家好……不知道有没有人可以帮我解决这个问题。

我正在运行查询以根据销售线更新产品类别,并且需要备份几百万条记录,因此我编写了下面的查询以针对特定订单 ID 运行

DECLARE @ID INT

SET @ID = 659483

UPDATE [TradeSpace].[TradeSpace].[dbo].[SalesLine] 
   SET [ProductCategory] = [curSync].[pc_Cat] 
  FROM (SELECT [SC_ID], 
               [pc_cat] 
          FROM [MW_MereSys].[dbo].[MWSLines] 
         INNER 
          JOIN [MW_MereSys].[dbo].[MWProductCats] 
            ON [MWSLines].[pc_catref] = [MWProductCats].[pc_catref]
         WHERE [sh_id] = @ID
       ) AS [curSync]
 WHERE [SalesLine].[slID] =  [curSync].[sc_id] 
   AND [salesline].[soid] = @ID 

sub SELECT 在不到一秒的时间内运行,但更新尚未完成(最多停留一个小时)。 [slID] 和 [soid] 存在索引 .. 手动更新一行需要不到一秒的时间,但像这样运行(10 行)非常慢。

请问大家有什么线索吗?我已经写了很多这样的查询并且从来没有遇到过问题......难倒:(

【问题讨论】:

  • 嗨@David - 这类问题通常需要一些额外的线索。请发布表定义,包括 PK、索引和约束。还请包括查询计划输出。
  • 您好.. 由于我为客户签订的合同,我恐怕不能。无法获得查询计划,因为它从未完成运行。仅使用硬编码值运行更新是即时的,查询也是如此,不知道为什么这样运行会出现问题。很奇怪。
  • 理想情况下,两个 pc_catref 列都应该是各自索引中的第一列。
  • 这部分查询单独运行良好,确实有相关索引。 (从 [MW_MereSys].[dbo].[MWSLines] 内部连接 ​​[MW_MereSys].[dbo].[MWProductCats] 中选择 [SC_ID],[pc_cat] [MWSLines].[pc_catref] = [MWProductCats].[pc_catref] WHERE [sh_id] = @ID) AS [curSync] ..... 我相信是 UPDATE 导致了问题?
  • 您是否可能遇到过某种类型的锁定问题?根据您的设置,更新可能需要在更新期间锁定整个 SalesLine 表。

标签: sql sql-server


【解决方案1】:

您的查询被重写,没有任何变化:

UPDATE s SET 
    ProductCategory = curSync.pc_Cat
FROM TradeSpace.TradeSpace.dbo.SalesLine s
INNER JOIN
  (
    SELECT [SC_ID], [pc_cat] 
    FROM [MW_MereSys].[dbo].[MWSLines]  l
    INNER JOIN [MW_MereSys].[dbo].[MWProductCats] c ON l.[pc_catref] = c.[pc_catref]
    WHERE [sh_id] = @ID
  ) AS [curSync]
  on s.[slID] =  [curSync].[sc_id]
WHERE s.[soid] = @ID

您确定这里的一切都正确吗? SalesLine 中的那一行总是只匹配子查询中的一行?

那就试试这个吧。如果这不是真的,将会失败。原始查询会在相同情况下以不同值静默更新同一行。

UPDATE s SET 
    ProductCategory = (
            SELECT [pc_cat] 
            FROM [MW_MereSys].[dbo].[MWSLines]  l
            INNER JOIN [MW_MereSys].[dbo].[MWProductCats] c ON l.[pc_catref] = c.[pc_catref]
            WHERE [sh_id] = @ID
              AND [sc_id] = s.[slID]
          )
FROM TradeSpace.TradeSpace.dbo.SalesLine s
WHERE s.[soid] = @ID

请检查估计的执行计划。是否命中索引?

【讨论】:

    【解决方案2】:

    我们需要我在 cmets 中提到的其他细节。

    当更新表与子查询结果连接时,由于基数估计非常高,您的更新很慢。

    这可能是因为错误的join和where谓词。

    您可以将子查询结果放在#Temp表中尝试。也可以在#temp表中创建相同的索引。

    DECLARE @ID INT
    
    SET @ID = 659483
    
    create #temp table([SC_ID] int,[pc_cat] int)
    
    insert into #temp 
    SELECT [SC_ID], 
                   [pc_cat] 
              FROM [MW_MereSys].[dbo].[MWSLines] 
             INNER JOIN [MW_MereSys].[dbo].[MWProductCats] 
                ON [MWSLines].[pc_catref] = [MWProductCats].[pc_catref]
             WHERE [sh_id] = @ID
    
    
    
    
    UPDATE SalesLine 
       SET [ProductCategory] = [curSync].[pc_Cat] 
      FROM [TradeSpace].[TradeSpace].[dbo].[SalesLine] as SalesLine
    inner join #temp  AS [curSync]
     WHERE [SalesLine].[slID] =  [curSync].[sc_id] 
       AND [salesline].[soid] = @ID 
    
    drop table #temp
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 2011-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多