TSQL:如何优化此更新查询

时间:2016-02-18 17:42:06

标签: sql-server tsql sql-update sql-server-2000

我一直在努力优化其他程序员在我的工作中创建的过程,重写整个查询以使用块语句而不是游标。然而,我遇到了一个问题。我让我的程序运行了一个小时,它从未完成(而光标程序在30分钟内完成)。我开始调试,发现它永远不会超过以下查询:

    -- Create our temp table
    create table #tData(
        First varchar(50) null,
        Middle varchar(50) null,
        Last varchar(50) null,
        Address varchar(50) null,
        Address2 varchar(50) null,
        City varchar(30) null,
        State varchar(2) null,
        Zip varchar(20) null,
        Phone varchar(20) null,
        SSN varchar(20) null,
        DOB varchar(15) null,
        Gender varchar(1) null,
        cID int null,
        pNum varchar(50) null,
        POFlag bit null,
        MatchFound bit null,
        Status varchar(10) null
    )

    -- Index the temp table
    create clustered index IX_tData_Clust on #tData(First, Middle, Last, Address, SSN, DOB)
    create index IX_tData on #tData(First, Middle, Last, Address, SSN, DOB)

    -- Look for matches
    update 
        #tData 
    set 
        #tData.MatchFound = 1,
        #tData.cID = ClientDatabase.cID,
        #tData.pNum = ClientDatabase.pNum
    from
        #tData,
        ClientDatabase
    where
        #tData.Status = 'ACTIVE'
        and (
                (
                    #tData.SSN is not null
                    and ClientDatabase.SSN is not null
                    and #tData.SSN = ClientDatabase.SSN
                ) 
                or 
                (
                    #tData.First is not null
                    and ClientDatabase.FirstName is not null
                    and #tData.Last is not null
                    and ClientDatabase.LastName is not null
                    and #tData.Address is not null
                    and ClientDatabase.AddressLine1 is not null
                    and #tData.First = ClientDatabase.FirstName
                    and #tData.Last = ClientDatabase.LastName
                    and #tData.Address = ClientDatabase.AddressLine1
                )
            )

基本上,上述查询具有从文本文件批量插入的临时数据表(#tData)。然后它尝试在ClientDatabase中找到匹配项(其中包含超过500万个条目)。找到匹配后,它会更新表行的MatchFound,cID和pNum单元格。我用小插入文件(5行)测试了它,它似乎完成得很好。当我进入成千上万时,就像我们的大多数文件一样,它只会消失。

我做了一些进一步的研究和调试,发现它当前正在运行的机器正在所有6个核心上进行最大化,并且它似乎只是在该点之后暂停,直到程序被迫退出。

有没有人对如何优化上述查询或者如何制作它以便SQL可以更好地管理查询有任何建议?非常感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

由于WHERE子句的第一部分是:

where
    #tData.Status = 'ACTIVE'
    -- ...

您需要在INDEX字段上添加Status

其次,我会在两个语句中打破UPDATE语句,每个OR - 一个语句。同时删除NULL检查,因为当您最终比较字段时,如果条件为真,则字段不能为空(除非您将ANSI_NULLS设置为OFF,但我对此表示怀疑) :

update 
-- snipped for brevity 
where
    #tData.Status = 'ACTIVE'
    and #tData.SSN = ClientDatabase.SSN

update 
-- snipped for brevity 
where
    #tData.Status = 'ACTIVE'
    and #tData.First = ClientDatabase.FirstName
    and #tData.Last = ClientDatabase.LastName
    and #tData.Address = ClientDatabase.AddressLine1

第三,既然事情已经解决了,你会发现这些UPDATE语句更易于使用新学校的JOIN语句阅读(阅读Bad habits to kick : using old-style JOINs)。

update 
    #tData 
set 
    #tData.MatchFound = 1,
    #tData.cID = ClientDatabase.cID,
    #tData.pNum = ClientDatabase.pNum
from
    #tData
    INNER JOIN ClientDatabase ON
        #tData.SSN = ClientDatabase.SSN
where
    #tData.Status = 'ACTIVE'

update 
    #tData 
set 
    #tData.MatchFound = 1,
    #tData.cID = ClientDatabase.cID,
    #tData.pNum = ClientDatabase.pNum
from
    #tData
    INNER JOIN ClientDatabase ON
        #tData.First = ClientDatabase.FirstName
        and #tData.Last = ClientDatabase.LastName
        and #tData.Address = ClientDatabase.AddressLine1
where
    #tData.Status = 'ACTIVE'

第四:由于匹配的查找位于表ClientDatabase中,我认为您需要ClientDatabase中的索引。一个用于SSN查找,一个用于FirstName + LastName + AddressLine1查找。

检查Actual Execution Plan很可能会揭示出这一点。如果这些索引不存在,可能会导致几次表扫描,这将破坏性能。

create nonclustered index IX_ClientDatabase_SSN on ClientDatabase(SSN);
create nonclustered index IX_ClientDatabase_Name_Address on ClientDatabase(FirstName,LastName,AddressLine1);

答案 1 :(得分:0)

我不知道你为什么要更新临时(#temporary)表,但我会给出一些建议。

在您的情况下更新#temp表可能是一个坏主意,因为您有数百万条记录要匹配,而#temp表没有索引。

更好的方法是创建一个包含索引的表,然后将数据插入其中,然后将其与主表中的索引列匹配,这样您的查询将显着加快。像这样的东西

创建#TABLE(colum1作为主键,columne2,.... columnn) 插入#TABLE()VALUES()

现在你的临时表一样快,你的查询也应该非常快。请注意,上面的代码是伪的。