更新查询中的SQL IN运算符会导致大量时间

时间:2014-01-05 05:09:28

标签: sql sql-server sql-server-2012

下面是一个更新查询,用于更新包含大约40000条记录的表:

UPDATE tableName
SET colA = val, colB = val
WHERE ID IN (select RecordIDs from tableB where needUpdate = 'Y')

执行上述查询时,我发现以下查询花了~15秒

SELECT RecordIDs
FROM tableB
WHERE needUpdate = 'Y'

但是当我拿走where子句(即update tableName set colA = val, colB = val)时,查询运行顺利。

为什么会这样?有没有办法缩短执行时间?


编辑:

以下是两个表格的结构:

tableName:
    ID int,
    VehicleBrandID int,
    VehicleLicenseExpiryDate nvarchar(25),
    LicensePlateNo nvarchar(MAX),
    ContactPerson nvarchar(MAX),
    ContactPersonID nvarchar(MAX),
    ContactPersonPhoneNumber nvarchar(MAX), 
    ContactPersonAddress nvarchar(MAX),
    CreatedDate nvarchar(MAX),
    CreatedBy nvarchar(MAX)
    PRIMARY KEY (ID)



  tableB:
    RowNumber int
    RecordIDs int
    NeedUpdate char(1)
    PRIMARY KEY (RowNumber)

被修改

屏幕截图是更新查询的执行计划

enter image description here

4 个答案:

答案 0 :(得分:2)

我想你是以下两种情况之一:

1 / STATISTICS are not updated由于您最近在表中进行了一些修改。在这种情况下,您应该执行此操作:

UPDATE STATISTICS tableB

2 /我想a wrong query plan is used,我建议执行此操作以强制重新编译查询:

SELECT RecordIDs
FROM tableB
WHERE needUpdate = 'Y'
OPTION (RECOMPILE)

告诉我们结果,我们会详细介绍。

答案 1 :(得分:2)

执行计划显示您正在使用表变量并且缺少有用的索引。

将现有PK保留在@output

DECLARE @output TABLE (
  ID                       INT PRIMARY KEY,
  VehicleBrandID           INT,
  VehicleLicenseExpiryDate NVARCHAR(25),
  LicensePlateNo           NVARCHAR(MAX),
  ContactPerson            NVARCHAR(MAX),
  ContactPersonID          NVARCHAR(MAX),
  ContactPersonPhoneNumber NVARCHAR(MAX),
  ContactPersonAddress     NVARCHAR(MAX),
  CreatedDate              NVARCHAR(MAX), /*<-- Don't store dates as strings*/
  CreatedBy                NVARCHAR(MAX)) 

并将 new 索引添加到@tenancyEditable

DECLARE @tenancyEditable TABLE (
  RowNumber  INT PRIMARY KEY,
  RecordIDs  INT,
  NeedUpdate CHAR(1),
  UNIQUE (NeedUpdate, RecordIDs, RowNumber)) 

使用这些索引进行以下查询

UPDATE @output
SET    LicensePlateNo = ''
WHERE  ID IN (SELECT RecordIDs
              FROM   @tenancyEditable
              WHERE  NeedUpdate = 'Y')
OPTION (RECOMPILE) 

可以生成更高效的外观

enter image description here

此外,您应该使用适当的数据类型,而不是将所有内容存储为NVARCHAR(MAX)。个人姓名最多不需要nvarchar(100)CreatedDate应该存储为date[time2]

答案 2 :(得分:0)

您可以使用内部联接而不是IN子句。

 update  t
 set
t.colA = val, t.colB = val
From tablename 
inner join tableb x on
t.id = x.recordid 
where x.needUpdate = 'Y'

虽然UPDATE...FROM 语法在某些方面至关重要 情况下,我更喜欢使用 子查询(通过使用IN子句) 可能的。

答案 3 :(得分:0)

这是另一种选择。在您的环境中尝试是值得的,因为已经证明其他人可以更快。

   MERGE INTO tableName tn
       USING (
              SELECT recordIDs
                FROM tableB
               WHERE needUpdate = 'Y'
             ) tb
          ON tn.ID = tb.recordID
    WHEN MATCHED THEN
       UPDATE 
          SET colA = tb.val, 
              colB = tb.val;

编辑: 我并不认为这在每种情况下或在每个设置/环境中都更快 - 只是值得一试,因为它对我和我曾经合作或阅读的其他人有用。