【问题标题】:Why a SQL Server join is taking too long to execute?为什么 SQL Server 连接执行时间过长?
【发布时间】:2020-01-02 10:40:36
【问题描述】:

我正在用数据填充一个临时表,下面是我的临时表的定义。

DECLARE @PurgeFilesList TABLE
(
    JobFileID BIGINT,
    ClientID INT,
    StatusID INT,
    IsPurgeSuccessfully BIT,
    ReceivedDate DATETIME,
    FilePath VARCHAR(2000),
    StatementPath VARCHAR(2000)
)

插入逻辑以填充临时表,之后我将与名为 Account 的表进行额外连接:

SELECT 
    JobFileID,
    PFL.ClientID,
    StatusID,
    IsPurgeSuccessfully,
    ReceivedDate,
    CASE 
       WHEN FilePath IS NULL THEN StatementPath 
       ELSE FilePath 
    END 'FilePath'
FROM 
    @PurgeFilesList PFL
INNER JOIN 
    Account(NOLOCK) A ON ISNULL(PFL.ClientID, 0) = ISNULL(A.ClientID, 0) 
                      AND A.HoldStatementPurge = 0

但是,这个连接花费了太多时间。虽然 Account 表中的总行数少于 5000。

Account 表架构:

Column_name         Type    Computed    Length
-----------------------------------------------
AccountID           bigint      no        8
AccountNumber       varchar     no        32
PrimaryCustomerName varchar     no        100
LastName            varchar     no        100
ClientName          varchar     no        32
BankID              varchar     no        32
UpdatedDate         datetime    no        8
IsPurged            bit         no        1
PurgeDate           datetime    no        8
ClientID            int         no        4
HoldStatementPurge  bit         no        1

如果需要任何其他信息,请告诉我。

执行计划:

【问题讨论】:

  • 你试过删除 NOLOCK 吗?
  • @PurgeFilesList 中有多少行?表变量在性能方面总是有点危险,因为查询优化器总是假设只有一行(如果表变量中有更多行,这会对执行计划产生严重的负面影响)
  • @HoneyBadger 更新了我的问题。请查看执行计划。
  • @FranCerezo 是的,没有运气。
  • @marc_s 表变量的记录数少于 2000。

标签: sql sql-server join query-performance


【解决方案1】:

由于您没有使用来自Account 的任何列,所以我会使用EXISTS

select fl.JobFileID, fl.ClientID, fl.StatusID, 
       fl.IsPurgeSuccessfully, fl.ReceivedDate, 
       isnull(FilePath, StatementPath) as FilePath
from @PurgeFilesList fl
where fl.ClientID is null or
      exists (select 1 
              from Account a 
              where a.clientid = fl.clientid and a.HoldStatementPurge = 0
             );

对于性能,索引将有助于Account(clientid,HoldStatementPurge) & 与表变量相同。如果不是这种情况,只需确保您的表变量具有少量数据,那么您将需要使用临时表并在该表上提供适当的索引。

【讨论】:

    【解决方案2】:

    您的帐户架构缺少可为空的是/否信息。话虽如此,我假设 Account.ClientID 不可为空,因此 ISNULL(PFL.ClientID, 0) = A.ClientID 也可以。无论如何。

    我的猜测是您在这里缺少几个放置良好的索引,例如:

    CREATE INDEX IX_Account_ClientID_HoldStatementPurge ON Account(ClientID, HoldStatementPurge)
    

    或者只是

    CREATE INDEX IX_Account_ClientID ON Account(ClientID)
    

    我会说在先检查查询计划的同时尝试创建两者。

    此外,您可能希望在这种情况下使用临时表 (CREATE TABLE #TempTable ...) 而不是表变量 (DECLARE @TempTable TABLE ...),这样您就可以应用额外的索引来加快速度:

    CREATE TABLE #PurgeFilesList 
    (
        JobFileID BIGINT PRIMARY KEY,
        ClientID INT,
        StatusID INT,
        IsPurgeSuccessfully BIT,
        ReceivedDate DATETIME,
        FilePath VARCHAR(2000),
        StatementPath VARCHAR(2000)
    )
    
    CREATE INDEX #IX_PurgeFilesList_ClientID ON #PurgeFilesList(ClientID)
    

    原因是无法在表变量上创建非聚集索引(只允许使用主键)。

    【讨论】:

      【解决方案3】:

      请检查表@PurgeFilesList中的记录大小。 尝试使用临时表而不是表变量。

      【讨论】:

        猜你喜欢
        • 2019-02-07
        • 1970-01-01
        • 1970-01-01
        • 2010-10-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-19
        • 1970-01-01
        相关资源
        最近更新 更多