优化SQL查询

时间:2009-07-13 15:48:04

标签: sql sql-server tsql

我正在使用以下执行1'500'000行

我的SP如下:

CREATE Procedure USP_12(@AuditMasterID as varchar(10),@TABLE as Varchar(50))
as
BEGIN
Declare @SQLStatement varchar(2000)
Declare @PrefixNo varchar(20)
Declare @PrefixLen varchar(20)
Declare @AfterPrefixLen varchar(20)

DECLARE Cur_Prefix CURSOR
FOR
SELECT PrefixNo,PrefixLen,AfterPrefixLen FROM NoSeriesMaster_Prefix WHERE PrefixType='SMS' order by ID

OPEN Cur_Prefix
FETCH NEXT FROM Cur_Prefix INTO @PrefixNo,@PrefixLen,@AfterPrefixLen
WHILE @@FETCH_STATUS = 0
BEGIN 
SET @SQLStatement = 'update '+@TABLE+' set AuditData.TATCallType=''12'', AuditData.TATCallUnit=''1'' ' +
'from '+@TABLE+' AuditData '+
'inner join AuditMaster am on am.ID=AuditData.AuditMaster_ID '+
'inner join HomeCircleMaster hcm on hcm.Ori_CircleMaster_ID=am.CircleMaster_ID and hcm.Ori_ServiceTypeMaster_ID=1 and hcm.Dest_ServiceTypeMaster_ID=1 '+
'inner join AuditTaggingMaster atm on atm.AuditMaster_ID=am.ID '+
'inner join NoSeriesMaster ns on (ns.CircleMaster_ID=am.CircleMaster_ID or ns.CircleMaster_ID=hcm.Dest_CircleMaster_ID) '+
' and ns.ProviderMaster_ID=am.ProviderMaster_ID '+
' and ns.ServiceTypeMaster_ID=1 '+
'inner join ProviderMaster_CallTypeMaster pm_ctm on pm_ctm.ProviderMaster_ID=am.ProviderMaster_ID and pm_ctm.CallTypeMaster_ID=101 and pm_ctm.CallTypeTagValue=AuditData.CallTypeTag '+
'where AuditData.TATCallType is null and substring(AuditData.CallTo,1,convert(int,'+@PrefixLen+'))='''+ @PrefixNo + ''' and len(AuditData.CallTo)='+convert(varchar(10),convert(int,@PrefixLen)+convert(int,@AfterPrefixLen))+' and '''+@PrefixNo+'''+ns.NoSeries=Left(AuditData.CallTo,len(ns.NoSeries)+convert(int,'+@PrefixLen+')) and AuditData.AuditMaster_ID='+@AuditMasterID+' '
print(@SQLStatement)
exec(@SQLStatement)
FETCH NEXT FROM Cur_Prefix INTO @PrefixNo,@PrefixLen,@AfterPrefixLen
END
CLOSE Cur_Prefix
DEALLOCATE Cur_Prefix
end

以上查询需要60分钟才能对1'500'000行

运行

该查询是否可以进行任何优化?

3 个答案:

答案 0 :(得分:3)

没有。 1优化 - 摆脱CURSOR! :-)你对许多不同的表执行此操作吗?你能以某种方式摆脱@table变量吗?

将动态SQL与游标结合起来是一种可靠的方法来消除SQL Server可能使用的任何优化.......

尝试针对该1.5mio表运行存储过程的核心,表名为hardcoded:

update (your table name)
set AuditData.TATCallType='12', AuditData.TATCallUnit='1'
from (your table name) AuditData 
inner join AuditMaster am on am.ID=AuditData.AuditMaster_ID 
 ...... (and so forth)

这需要多长时间?

你可以发布更多信息吗?表格结构,可用的指数是什么?

马克

PS:我尝试分解庞大的SQL语句,并尝试通过公用表表达式来避免使用CURSOR。然而,这需要您将@Table名称硬编码到您的语句中 - 这对您有用吗?

试试吧 - 你现在几点钟了?

UPDATE 
    (your table name)
SET 
    AuditData.TATCallType='12', AuditData.TATCallUnit='1'
FROM
    (your table name) AuditData 
INNER JOIN
    AuditMaster am ON am.ID = AuditData.AuditMaster_ID 
INNER JOIN
    HomeCircleMaster hcm ON hcm.Ori_CircleMaster_ID = am.CircleMaster_ID 
          AND hcm.Ori_ServiceTypeMaster_ID = 1 
          AND hcm.Dest_ServiceTypeMaster_ID = 1 
INNER JOIN
    AuditTaggingMaster atm ON atm.AuditMaster_ID = am.ID 
INNER JOIN
    NoSeriesMaster ns on (ns.CircleMaster_ID = am.CircleMaster_ID or ns.CircleMaster_ID = hcm.Dest_CircleMaster_ID) 
      AND ns.ProviderMaster_ID = am.ProviderMaster_ID 
      AND ns.ServiceTypeMaster_ID = 1 
INNER JOIN 
    ProviderMaster_CallTypeMaster pm_ctm ON pm_ctm.ProviderMaster_ID = am.ProviderMaster_ID 
      AND pm_ctm.CallTypeMaster_ID = 101 
      AND pm_ctm.CallTypeTagValue = AuditData.CallTypeTag 
INNER JOIN
    NoSeriesMaster_Prefix PD ON SUBSTRING(AuditData.CallTo, 1, CONVERT(INT, PD.PrefixLen)) = PD.PrefixNo 
      AND LEN(AuditData.CallTo) = CONVERT(VARCHAR(10), CONVERT(INT, PD.PrefixLen) + CONVERT(INT, PD.AfterPrefixLen))
      AND PD.PrefixNo + ns.NoSeries = LEFT(AuditData.CallTo, len(ns.NoSeries) + CONVERT(INT, PD.PrefixLen)) 
WHERE
    AuditData.TATCallType is NULL
    AND AuditData.AuditMaster_ID = @AuditMasterID
    AND PD.PrefixType = 'SMS'

IF 这是有效的,接下来的步骤是检查您是否有

的索引
  • 所有的JOIN条件,例如

    INNER JOIN AuditTaggingMaster atm ON atm.AuditMaster_ID = am.ID

    你有关于“atm.AuditMaster_ID”和“am.ID”的索引吗?

  • 你的WHERE子句(例如你有PD.PrefixType的索引吗?)

此外,对于每种情况,您都需要考虑索引的选择性。例如,在PD.PrefixType ='SMS'的WHERE子句中 - 这是选择“PD”表中所有条目的一半,还是仅1-2%?如果索引是选择性的,那么它很可能会被使用 - 如果它在一个“BIT”列上,它只能有两个值,每个值将选择大约一半的表,不要在那里放一个索引,它赢了没帮忙。

答案 1 :(得分:2)

由于你正在传递@table,你似乎最好为你需要运行它的每个表都有一个sProc。至少服务器与缓存计划有争斗的机会。

答案 2 :(得分:1)

我要检查的第一件事是我已经在所有外键上定义了索引。

在点击审核表时,阻止也可能是一个严重的问题。阅读表格提示,看看他们是否可以帮助解决因阻塞造成的任何延迟。