如何优化太慢的存储过程?

时间:2017-09-25 21:28:26

标签: sql-server sql-server-2008 stored-procedures query-performance

我的存储过程大约需要1分45秒,我该如何优化它?我在插入之前尝试了几个创建临时表的事情。

我有预计执行计划,但我不知道如何上传。

这是我的存储过程的一部分,这需要更长的时间,查询成本为53%。

SELECT Distinct
    BackupCTE.[InstanceName]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.EnvironmentType = 0 THEN '-1' Else CONVERT(VARCHAR,BackupCTE.EnvironmentType) END  AS EnvironmentType
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.InstanceStatus = 0 THEN '-1' Else CONVERT(VARCHAR,BackupCTE.InstanceStatus) END AS [InstanceStatus] 
   ,BackupCTE.[BackupShare]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.DatabaseOwner = 0 THEN '-1'
          WHEN ISNULL(BackupCTE.IsMirroringEnabled,0) = 0 AND BackupCTE.DatabaseOwner NOT IN ('SA') AND BackupCTE.DatabaseStatus = 'Normal' AND BackupCTE.DatabaseReadOnly = 0
              AND ISNULL(BackupCTE.IsDatabaseSnapshot,0) = 0 THEN '0'
         ELSE '1' END AS DatabaseOwner
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.DBRecoveryModel = 0 THEN '-1' 
          WHEN BackupCTE.DatabaseStatus = 'Normal' AND BackupCTE.DatabaseName NOT IN ('master', 'msdb', 'IHC_DBA','distribution','ReportServerTempDB','NavicareReporting','ReportServer') AND
               BackupCTE.RecoveryModel NOT IN ('Full','BulkLogged') THEN '0'
          ELSE '1'
    END AS [DBRecoveryModel]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.AutoShrink = 0 THEN '-1'              
         ELSE CONVERT(VARCHAR, BackupCTE.[AutoShrink]) END AS [AutoShrink]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.AutoClose = 0 THEN '-1' Else CONVERT(VARCHAR,BackupCTE.[AutoClose]) END AS [AutoClose]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.BackupCompression = 0 THEN '-1' 
          WHEN BackupCTE.[BackupCompression] = 0 THEN '0'
          Else '1' END AS [BackupCompression]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.XPCmdShell = 0 THEN '-1' 
         WHEN CONVERT(VARCHAR,BackupCTE.[XPCmdShell]) = 0 THEN '1'
         Else '0' END AS [XPCmdShell]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.EncryptionEnabled = 0 THEN '-1' Else CONVERT(VARCHAR,BackupCTE.[EncryptionEnabled]) END AS [EncryptionEnabled]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.IsIdera = 0 THEN '-1' Else CONVERT(VARCHAR,BackupCTE.[IsIdera]) END AS [IsIdera]
   ,[HoursRetentionShare]
   ,[HoursSinceLastFullBackup]
   ,[HoursSinceLastDiffBackup]
   ,[HoursSinceLastLogBackup]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.ExceededBkpTimeFrame = 0 THEN '-1' Else BackupCTE.ExceededBkpTimeFrame 
    END AS ExceededBkpTimeFrame
   ,BackupType
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.[Primary] = 0 THEN '-1' Else BackupCTE.[Primary] END AS [Primary]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.[Secondary] = 0 THEN '-1' Else BackupCTE.[Secondary] END AS [Secondary]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.[LockPages] = 0 THEN '-1' 
        Else CONVERT(varchar,BackupCTE.[LockPages]) END  AS [LockPages]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.[SADisabled] = 0 THEN '-1'  
         WHEN CONVERT(varchar,BackupCTE.[SADisabled]) = 0 AND BackupCTE.VersionName like 'Microsoft SQL Server  2000 %' THEN '1' 
         ELSE CONVERT(varchar,BackupCTE.[SADisabled])
         END AS [SADisabled]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.ServiceAccount = 0 THEN '-1'
         WHEN StdServiceAccount.IsValid = 1
                    OR BackupCTE.ServiceAccount IN ('CO\lpsqldbadmin','lpsqldbadmin@CO.IHC.COM')                
            THEN  '1'
            ELSE '0' END AS ServiceAccount
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.[ServicePackFlag] = 0 THEN '-1' Else BackupCTE.[ServicePack] END AS [ServicePack]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.[MaxMemory] = 0 THEN '-1' Else BackupCTE.[MaxMemory] END AS [MaxMemory]
   ,[JobName]
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.[JobOwner] = 0 THEN '-1'
         WHEN BackupCTE.JobOwner NOT IN ('SA') AND JobEnabled = 1 AND DELETED IS NULL THEN '0' 
         ELSE '1' END AS JobOwner 
   ,[JobEnabled]
   ,CASE WHEN BackupCTE.EnvironmentType = 'PROD' AND BackupCTE.[Primary] NOT IN ('Tamie Jensen', 'Chase Mahony','Megna Musapeta','Aaron Uppencamp') THEN '0' 
         WHEN BackupCTE.EnvironmentType = 'STBY' AND BackupCTE.[Primary] NOT IN ('Tamie Jensen', 'Chase Mahony','Megna Musapeta','Aaron Uppencamp') THEN '0'
         ELSE '1' END AS IsNonPrimary
   ,CASE WHEN BackupCTE.EnvironmentType = 'PROD' AND BackupCTE.[Secondary] IN ('NONE') THEN '0' 
         WHEN BackupCTE.EnvironmentType = 'STBY' AND BackupCTE.[Secondary] IN ('NONE') THEN '0'
         ELSE '1' END AS IsNonSecondary
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.[MaxMemory] = 0 THEN '-1' 
         WHEN BackupCTE.[MaxMemory]%8 = 0 THEN '1' 
         ELSE '0' END AS FlagMemory
   ,CASE WHEN BackupCTE.JobName NOT LIKE '%Insure%'
   THEN
       CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.MaintenanceJob = 0 THEN '-1'
              WHEN JobSchMultiplier < 0 THEN '1' --One Time Job. No Need To Flag
              WHEN DATEDIFF(HH, BackupCTE.JobRunDate, GETDATE()) > 24*JobSchMultiplier THEN '0'
              ELSE '1'            
        END
    ELSE '1' END  AS MaintenanceJob
    ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.ServicePackFlag = 0 THEN '-1'
          WHEN LTRIM(RTRIM(SUBSTRING(PatchingStds.ServicePack,3, LEN(PatchingStds.ServicePack)-2))) > ISNULL(LTRIM(RTRIM(SUBSTRING(InstanceSQLDTl.ServicePack,3, 
              LEN(InstanceSQLDTl.ServicePack)-2))),0) THEN '0'
         WHEN LTRIM(RTRIM(SUBSTRING(VersionName,CHARINDEX('-',VersionName )+1,abs(CASE WHEN CHARINDEX('(',VersionName ) > 0 THEN CHARINDEX('(',VersionName )-CHARINDEX('-',VersionName) ELSE len(VersionName)-CHARINDEX('-',VersionName)  end)))) <> LTRIM(RTRIM(PatchingStds.SQLBuild)) THEN '2'
         ELSE '1' END AS ServicePackFlag
   ,VersionName 
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.SAViolations = 0 THEN '-1'
         WHEN LoginName Not IN ('CO\DBA Group','CO\DBAdmin') AND SYSAdmin = 1 OR SecurityAdmin = 1 OR ServerAdmin = 1 OR SetupAdmin = 1 OR ProcessAdmin = 1 OR DiskAdmin = 1
                                                             OR DBCreator = 1 OR BulkAdmin = 1 THEN '0'
         ELSE '1' END AS SAViolations 
   ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.IsBackupShare = 0 THEN '-1'
         WHEN NOT (BackupCTE.[BackupShare] LIKE '\\CO.IHC.COM%' OR BackupCTE.[BackupShare] LIKE '\\CO-LP-SQL1%' OR BackupCTE.[BackupShare] LIKE '\\CO-LP-SQL2%' 
               OR BackupCTE.[BackupShare] LIKE '\\CO-TX-VAULT2%' OR BackupCTE.[BackupShare] LIKE '\\co-tx-vpdsfile2\txPDSsqlBackups%' AND BackupCTE.[BackupShare] NOT LIKE '%Test') OR BackupCTE.[BackupShare] = 'NONE LISTED' THEN '0'
         ELSE '1' END AS IsBackupShare
    ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.Tempdb_DataFileCount = 0 THEN '-1'
          WHEN TEMPDBFileCount.Tempdb_DataFileCount >= 8 OR TEMPDBFileCount.Tempdb_DataFileCount > TEMPDBFileCount.OptimalTempdbFilecount THEN '1'
          WHEN TEMPDBFileCount.OptimalTempdbFilecount > TEMPDBFileCount.Tempdb_DataFileCount THEN '0'
          ELSE '1'END AS Tempdb_DataFileCount
    ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.DataAutoGrow = 0 THEN '-1' ELSE BackupCTE.DataAutoGrow END AS DataAutoGrow
    ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.LogAutoGrow = 0 THEN '-1' ELSE BackupCTE.LogAutoGrow END AS LogAutoGrow
    ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.MaintVersion = 0 THEN '-1' ELSE BackupCTE.MaintVersion END AS MaintVersion
    ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.MaintVersion = 0 THEN '-1' 
         WHEN BackupCTE.MaintVersion = 2.02 OR BackupCTE.MaintVersion = 2.03 THEN '1'
         ELSE '0' END AS FlagMaintVersion
    ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.DBCompatibilityLevel = 0 THEN '-1' 
          WHEN BackupCTE.DBCompatibilityLevel < 90 THEN '0'
          ELSE '1' END AS DBCompatibilityLevel
    ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.FlagVersionName = 0 THEN '-1' 
          WHEN NOT (BackupCTE.VersionName LIKE 'Microsoft SQL Server 2005%' OR BackupCTE.VersionName LIKE 'Microsoft SQL Server  2000%') THEN '1'
          ELSE '0' END AS FlagVersionName
    ,CASE WHEN DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL AND ComplianceReportExceptions.VLFCount = 0 THEN '-1' 
          ELSE BackupCTE.VLFCount END AS VLFCount
Into #FinalData
FROM [DBAPP].InstanceSQLDtl 
LEFT JOIN #BackupCTE BackupCTE ON  InstanceSQLDtl.InstanceID = BackupCTE.InstanceID
LEFT JOIN  [DBAPP].[SQLPatchingStandards] PatchingStds ON LTRIM(RTRIM(LEFT(VersionName, CHARINDEX('-', VersionName)-1))) = LTRIM(RTRIM(LEFT
           (PatchingStds.SQLVersion,CHARINDEX('-',PatchingStds.SQLVersion)-1))) 
LEFT JOIN [DBAPP].[ComplianceReportExceptions] ON ComplianceReportExceptions.InstanceName =  BackupCTE.InstanceName
LEFT JOIN [DBAPP].[TEMPDBFileCount] ON InstanceSQLDtl.InstanceID = [TEMPDBFileCount].InstanceID AND Type_DESC = 'ROWS'
LEFT JOIN DBO.fnGetServiceNames() StdServiceAccount ON BackupCTE.InstanceID = StdServiceAccount.InstanceID
Where BackupCTE.[InstanceName] IS NOT NULL
ORDER BY [InstanceName]

2 个答案:

答案 0 :(得分:2)

那么多的字符串操作和CASE语句总是会很慢。也许你可以将它作为夜间批处理程序运行到数据集市中?否则,这里有一些提示:

  1. 由于您的许多CASE语句都在测试... InstanceName IS NULL,您可以将查询拆分为一半并使用UNION ALL将记录连接在一起并且不为空(参见示例)。这将删除一堆CASE支票。
  2. 如果只有一个项目,请不要使用WHERE IN('SA'),而是使用not-equal(&lt;&gt;)。
  3. 如果可能的话,避免在JOIN条件下进行字符串操作(...PatchingStds ON LTRIM(RTRIM(LEFT(VersionName...)。尝试将这些字段存储在某个位置,可以是专用列,也可以是持久计算列。这样你就可以在该字段上添加索引以使连接更快。
  4. 在可能的情况下,在连接字段上有索引,但受多种因素影响,但大多数情况下,单个表上没有太多索引,因为这会降低INSERT语句的速度。
  5. SELECT DISTINCT 
        BackupCTE.[InstanceName]
       , EnvironmentType = CASE WHEN ComplianceReportExceptions.EnvironmentType = 0 THEN '-1' ELSE CONVERT(VARCHAR, BackupCTE.EnvironmentType) END
       , [InstanceStatus] = CASE WHEN ComplianceReportExceptions.InstanceStatus = 0 THEN '-1' ELSE CONVERT(VARCHAR,BackupCTE.InstanceStatus) END 
       , BackupCTE.[BackupShare]
       , DatabaseOwner = 
            CASE WHEN ComplianceReportExceptions.DatabaseOwner = 0 THEN '-1'
                 WHEN ISNULL(BackupCTE.IsMirroringEnabled,0) = 0 
                    AND BackupCTE.DatabaseOwner <> 'SA'
                    AND BackupCTE.DatabaseStatus = 'Normal' 
                    AND BackupCTE.DatabaseReadOnly = 0
                    AND ISNULL(BackupCTE.IsDatabaseSnapshot,0) = 0 
                THEN '0'
                ELSE '1' 
             END
        -- Etc...
    INTO #FinalData
    FROM [DBAPP].InstanceSQLDtl 
        LEFT JOIN #BackupCTE BackupCTE ON  InstanceSQLDtl.InstanceID = BackupCTE.InstanceID
        LEFT JOIN  [DBAPP].[SQLPatchingStandards] PatchingStds ON LTRIM(RTRIM(LEFT(VersionName, CHARINDEX('-', VersionName)-1))) = LTRIM(RTRIM(LEFT
                   (PatchingStds.SQLVersion,CHARINDEX('-',PatchingStds.SQLVersion)-1))) 
        LEFT JOIN [DBAPP].[ComplianceReportExceptions] ON ComplianceReportExceptions.InstanceName =  BackupCTE.InstanceName
        LEFT JOIN [DBAPP].[TEMPDBFileCount] ON InstanceSQLDtl.InstanceID = [TEMPDBFileCount].InstanceID AND Type_DESC = 'ROWS'
        LEFT JOIN DBO.fnGetServiceNames() StdServiceAccount ON BackupCTE.InstanceID = StdServiceAccount.InstanceID
    WHERE BackupCTE.[InstanceName] IS NOT NULL
        AND DBAPP.ComplianceReportExceptions.InstanceName IS NOT NULL
    --****************
    UNION ALL 
    --****************
    SELECT DISTINCT 
        BackupCTE.[InstanceName]
       , EnvironmentType = CONVERT(VARCHAR,BackupCTE.EnvironmentType)
       , [InstanceStatus] = CONVERT(VARCHAR,BackupCTE.InstanceStatus)
       , BackupCTE.[BackupShare]
       , DatabaseOwner = 
           CASE 
                WHEN ISNULL(BackupCTE.IsMirroringEnabled,0) = 0 
                    AND BackupCTE.DatabaseOwner <> 'SA'
                    AND BackupCTE.DatabaseStatus = 'Normal' 
                    AND BackupCTE.DatabaseReadOnly = 0
                    AND ISNULL(BackupCTE.IsDatabaseSnapshot,0) = 0 
                THEN '0'
                ELSE '1' 
            END
    -- Etc...
    INTO #FinalData
    FROM [DBAPP].InstanceSQLDtl 
        LEFT JOIN #BackupCTE BackupCTE ON  InstanceSQLDtl.InstanceID = BackupCTE.InstanceID
        LEFT JOIN  [DBAPP].[SQLPatchingStandards] PatchingStds ON LTRIM(RTRIM(LEFT(VersionName, CHARINDEX('-', VersionName)-1))) = LTRIM(RTRIM(LEFT
                   (PatchingStds.SQLVersion,CHARINDEX('-',PatchingStds.SQLVersion)-1))) 
        LEFT JOIN [DBAPP].[ComplianceReportExceptions] ON ComplianceReportExceptions.InstanceName =  BackupCTE.InstanceName
        LEFT JOIN [DBAPP].[TEMPDBFileCount] ON InstanceSQLDtl.InstanceID = [TEMPDBFileCount].InstanceID AND Type_DESC = 'ROWS'
        LEFT JOIN DBO.fnGetServiceNames() StdServiceAccount ON BackupCTE.InstanceID = StdServiceAccount.InstanceID
    WHERE BackupCTE.[InstanceName] IS NOT NULL
        AND DBAPP.ComplianceReportExceptions.InstanceName IS NULL
    --****************
    ORDER BY [InstanceName]
    

答案 1 :(得分:-1)

以下是导致降低查询性能的可能性,

  
      
  1. 如果您使用转换,请不要在on子句中转换colum值而不是此创建单独的colum并预先填充转换   它禁止使用索引来搜索表中的记录。

  2.   
  3. 与(nolock)一起使用

  4.   
  5. 区别&amp;如果您不需要将其从查询中删除,那么order by是对查询的高成本操作。

  6.