1

Can somebody help me to understand why the query below is taking more than a minute to run?

When I comment the below line:

AND sys.fn_hadr_backup_is_preferred_replica(d.name) = 1

the query runs in less than a second.

I'm looking for some alternatives to rewrite the query.

SELECT
DISTINCT @@SERVERNAME AS ServerName ,
d.name AS DatabaseName ,
'Diff Backups Not Performed Recently' AS Finding ,
'Last differential backup: ' + COALESCE(CAST(MAX(b.backup_finish_date) AS VARCHAR(25)),'never') AS Details
FROM master.sys.databases d
    LEFT OUTER JOIN msdb.dbo.backupset b ON d.name COLLATE SQL_Latin1_General_CP1_CI_AS = b.database_name COLLATE SQL_Latin1_General_CP1_CI_AS
    AND b.type = 'I'
    AND b.server_name = SERVERPROPERTY('ServerName') /*Backupset ran on current server */
WHERE d.database_id <> 2 
    AND d.state NOT IN(1, 6, 10) /* Not currently offline or restoring, like log shipping databases */
    AND d.is_in_standby = 0 /* Not a log shipping target database */
    AND d.source_database_id IS NULL /* Excludes database snapshots */
    AND b.user_name = 'tsmadmin'
    AND sys.fn_hadr_backup_is_preferred_replica(d.name) = 1
GROUP BY d.name
HAVING MAX(b.backup_finish_date) <= DATEADD(dd, -2, GETDATE())
    OR MAX(b.backup_finish_date) IS NULL;
5
  • use cross apply? Commented Mar 11, 2017 at 2:24
  • 1
    UDFs are famous both for being slow to run and for interfering with the optimizer's ability to run the query. Commented Mar 11, 2017 at 2:26
  • One way is to try not apply a function to your column. What does your sys.fn_hadr_backup_is_preferred_replica do? Is it deterministic so it can be indexed? Could you show it in your question? Commented Mar 11, 2017 at 2:29
  • what version of sql server? : connect.microsoft.com/SQLServer/feedback/details/783011/… Commented Mar 11, 2017 at 2:44
  • sql server 2012 SP3 Commented Mar 11, 2017 at 2:46

2 Answers 2

1

This might be a case where running the function after the group by is a good idea. Try removing the function call from the where and adding it to the having clause:

HAVING (MAX(b.backup_finish_date) <= DATEADD(day, -2, GETDATE()) OR
        MAX(b.backup_finish_date) IS NULL
       ) AND
       sys.fn_hadr_backup_is_preferred_replica(d.name) = 1

I'm only suggesting this because you are aggregating by d.name. Normally, filtering before the aggregation would be better. But, if the operation is really expensive, it might be better to filter after the aggregation.

Sign up to request clarification or add additional context in comments.

Comments

0

This turns it into a an innner join AND b.user_name = 'tsmadmin' so might as well use a join

HAVING OR may be the problem

DISTINCT may be a problem

SELECT @@SERVERNAME AS ServerName;
SELECT d.name AS DatabaseName  
     , COALESCE(CAST(MAX(b.backup_finish_date) AS VARCHAR(25)), 'never') AS Details
FROM master.sys.databases d
JOIN msdb.dbo.backupset b 
  ON d.name COLLATE SQL_Latin1_General_CP1_CI_AS = b.database_name COLLATE SQL_Latin1_General_CP1_CI_AS
 AND b.type = 'I'
 AND b.server_name = SERVERPROPERTY('ServerName') /*Backupset ran on current server */
 AND b.user_name = 'tsmadmin'
 AND d.database_id <> 2 
 AND d.state NOT IN(1, 6, 10)     /* Not currently offline or restoring, like log shipping databases */
 AND d.is_in_standby = 0          /* Not a log shipping target database */
 AND d.source_database_id IS NULL /* Excludes database snapshots */
 AND sys.fn_hadr_backup_is_preferred_replica(d.name) = 1
GROUP BY d.name
HAVING isnull(MAX(b.backup_finish_date), DATEADD(dd, -2, GETDATE())) 
       <= DATEADD(dd, -2, GETDATE());

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.