使用基于RBAR查询的基于设置的查询的好处

时间:2018-04-12 05:22:42

标签: c# sql .net sql-server database

起初,我为我糟糕的英语道歉。

问题是 -

在我的数据库中,我有一个包含307763行的表。我每天都需要处理每一行。为了处理行,我在数据库中写了一个SQL查询到SELECT,INSERT和UPDATE。查询的执行时间是 30分 1小时

然后我创建了一个Visual Studio控制台应用程序来运行该过程。

出现问题。在App.Config中,数据库连接超时有30秒的时间限制。我还尝试将值设为0。

是否有任何安全方法可以保持连接打开1小时或以其他任何方式解决问题?

以下是查询:

DECLARE @totalEmployee AS INT;
DECLARE @i AS INT=1;
DECLARE @employee TABLE
(
    Id INT PRIMARY KEY IDENTITY(1,1),
    SystemId VARCHAR(30),
    PreRecruitmentEmployeeId VARCHAR(30),
    DOJ DATETIME,
    DOS DATETIME,
    ProbationConfirmEntryDate DATETIME
)

INSERT INTO @employee
SELECT EI.SystemId, EI.PreRecruitmentEmployeeId, EI.DOJ, EI.DOS, EI.ProbationConfirmEntryDate FROM EmployeeInformation EI WHERE EI.EmployeeStatus='Active';
SELECT @totalEmployee=COUNT(*) FROM @employee;
WHILE @i<= @totalEmployee
  BEGIN
    UPDATE EmployeeDocument SET 
           DueProcessDateTime=CASE WHEN ED.DueProcessDateTime IS NULL THEN GETDATE() ELSE ED.DueProcessDateTime END, 
           IsMailSend=CASE WHEN ED.DueProcessDateTime IS NULL THEN 1 ELSE ED.IsMailSend END,
           DueDate=
            CASE 
                WHEN CD.DependateDate='AsAndWhen' THEN NULL
                WHEN CD.DependateDate='AppointmentDate' THEN 
                    CASE WHEN E.PreRecruitmentEmployeeId IS NULL AND E.DOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOJ) ELSE
                        CASE WHEN PRE.ApprovedDateTime IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, PRE.ApprovedDateTime) 
                        END
                    END
                WHEN CD.DependateDate='AgreedJoinDate' THEN
                    CASE WHEN E.PreRecruitmentEmployeeId IS NULL AND E.DOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOJ) ELSE
                        CASE WHEN PRE.AgreedDOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, PRE.AgreedDOJ) 
                        END
                    END
                WHEN CD.DependateDate='ResignationApplyDate' THEN (SELECT TOP(1) CASE WHEN ResignationDate<>'' THEN DATEADD(DAY, CD.LeadOrLagDays,ResignationDate)
                                                                    ELSE NULL END FROM TRN.Resignation WHERE EmployeeId=E.SystemId  ORDER BY ResignationDate DESC)
                WHEN CD.DependateDate='ApprovedResignationEffectiveDate' THEN (SELECT TOP(1) CASE WHEN ApprovedEffectiveDate<>'' THEN DATEADD(DAY, CD.LeadOrLagDays,ApprovedEffectiveDate)
                                                                    ELSE NULL END FROM TRN.Resignation WHERE EmployeeId=E.SystemId  ORDER BY ApprovedEffectiveDate DESC)
                WHEN CD.DependateDate='JoiningDate' AND E.DOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOJ)
                WHEN CD.DependateDate='LetterOfIndentDate' THEN 
                    CASE WHEN E.PreRecruitmentEmployeeId IS NULL AND E.DOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOJ) ELSE
                        CASE WHEN PRE.SelectionDateTime IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, PRE.SelectionDateTime) 
                        END
                    END
                WHEN CD.DependateDate='ProfileSubmit' THEN 
                    CASE WHEN E.PreRecruitmentEmployeeId IS NULL AND E.DOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOJ) ELSE
                        CASE WHEN PRE.SelectionDateTime IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, PRE.SelectionDateTime) 
                        END
                    END
                WHEN CD.DependateDate='ProbitionPeriodConfirmationDate' AND E.ProbationConfirmEntryDate IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.ProbationConfirmEntryDate)
                WHEN CD.DependateDate='PromotionDate' THEN NULL
                WHEN CD.DependateDate='SeparationDate' AND E.DOS IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOS)
                WHEN CD.DependateDate='SelectionDate' THEN
                CASE WHEN E.PreRecruitmentEmployeeId IS NULL AND E.DOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOJ) ELSE
                        CASE WHEN PRE.SelectionDateTime IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, PRE.SelectionDateTime) 
                        END
                    END
            END
        FROM EmployeeDocument ED
        JOIN HKP.ComplianceDocument CD ON CD.Id=ED.ComplianceDocumentId
        LEFT JOIN @employee E ON E.SystemId=ED.EmpSystemID
        LEFT JOIN PreRecruitmentEmployee PRE ON PRE.Id=E.PreRecruitmentEmployeeId
        WHERE E.Id=@i AND ED.FileId IS NULL                     
    SET @i = @i + 1;
  END

1 个答案:

答案 0 :(得分:2)

既然我们可以看到你的sql语句,我们可以建议一个更好的方法。

您当前的SQL语句正在使用循环,这意味着@Employee表变量中的每个记录运行一次。这种程序方法被称为RBAR - (RBAR发音为“ree-bar”,并且是“按行划分行”的“Modenism” - 由Jeff Moden创建 - 一位SQL大师) - 因为它是,嗯,痛苦地慢。 (这里有one of many articles关于这个主题的更多信息)

SQL不适用于这种方法。相反,它适用于基于集合的方法 - 这意味着您可以让它在一组记录上工作,而不是逐个进行。

所以这里是我认为你的sql语句应该是什么样的(注意我用一个简单的派生表交换了@Employees表变量,所以没有必要担心这个)。

请注意我无法对此进行测试,因为您没有提供样本数据或所需的结果,因此您需要自己进行测试 - 但原则是 - 当您离开时不要去RBAR可以避免它。

UPDATE EmployeeDocument 
SET DueProcessDateTime = CASE WHEN ED.DueProcessDateTime IS NULL THEN GETDATE() ELSE ED.DueProcessDateTime END, 
    IsMailSend = CASE WHEN ED.DueProcessDateTime IS NULL THEN 1 ELSE ED.IsMailSend END,
    DueDate = 
        CASE 
        WHEN CD.DependateDate='AsAndWhen' THEN NULL
        WHEN CD.DependateDate='AppointmentDate' THEN 
            CASE WHEN E.PreRecruitmentEmployeeId IS NULL AND E.DOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOJ) ELSE
                CASE WHEN PRE.ApprovedDateTime IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, PRE.ApprovedDateTime) 
                END
            END
        WHEN CD.DependateDate='AgreedJoinDate' THEN
            CASE WHEN E.PreRecruitmentEmployeeId IS NULL AND E.DOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOJ) ELSE
                CASE WHEN PRE.AgreedDOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, PRE.AgreedDOJ) 
                END
            END
        WHEN CD.DependateDate='ResignationApplyDate' THEN (SELECT TOP(1) CASE WHEN ResignationDate<>'' THEN DATEADD(DAY, CD.LeadOrLagDays,ResignationDate)
                                                            ELSE NULL END FROM TRN.Resignation WHERE EmployeeId=E.SystemId  ORDER BY ResignationDate DESC)
        WHEN CD.DependateDate='ApprovedResignationEffectiveDate' THEN (SELECT TOP(1) CASE WHEN ApprovedEffectiveDate<>'' THEN DATEADD(DAY, CD.LeadOrLagDays,ApprovedEffectiveDate)
                                                            ELSE NULL END FROM TRN.Resignation WHERE EmployeeId=E.SystemId  ORDER BY ApprovedEffectiveDate DESC)
        WHEN CD.DependateDate='JoiningDate' AND E.DOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOJ)
        WHEN CD.DependateDate='LetterOfIndentDate' THEN 
            CASE WHEN E.PreRecruitmentEmployeeId IS NULL AND E.DOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOJ) ELSE
                CASE WHEN PRE.SelectionDateTime IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, PRE.SelectionDateTime) 
                END
            END
        WHEN CD.DependateDate='ProfileSubmit' THEN 
            CASE WHEN E.PreRecruitmentEmployeeId IS NULL AND E.DOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOJ) ELSE
                CASE WHEN PRE.SelectionDateTime IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, PRE.SelectionDateTime) 
                END
            END
        WHEN CD.DependateDate='ProbitionPeriodConfirmationDate' AND E.ProbationConfirmEntryDate IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.ProbationConfirmEntryDate)
        WHEN CD.DependateDate='PromotionDate' THEN NULL
        WHEN CD.DependateDate='SeparationDate' AND E.DOS IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOS)
        WHEN CD.DependateDate='SelectionDate' THEN
            CASE WHEN E.PreRecruitmentEmployeeId IS NULL AND E.DOJ IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, E.DOJ) ELSE
                CASE WHEN PRE.SelectionDateTime IS NOT NULL THEN DATEADD(DAY, CD.LeadOrLagDays, PRE.SelectionDateTime) 
                END
            END
        END
FROM EmployeeDocument ED
JOIN HKP.ComplianceDocument CD ON CD.Id=ED.ComplianceDocumentId
LEFT JOIN 
(
    SELECT EI.SystemId, EI.PreRecruitmentEmployeeId, EI.DOJ, EI.DOS, EI.ProbationConfirmEntryDate 
    FROM EmployeeInformation EI 
    WHERE EI.EmployeeStatus='Active'
) E ON E.SystemId=ED.EmpSystemID
LEFT JOIN PreRecruitmentEmployee PRE ON PRE.Id=E.PreRecruitmentEmployeeId
WHERE ED.FileId IS NULL