decoder
decoder

Reputation: 926

Query execution takes too much time

I have the following query

SELECT dbo.tblRegion.RegionName,
       dbo.tblDistributionLocation.DistributionLocationName,
       dbo.tblTSA.TSAName,
       TEmailInfo.EmailCM,
       COUNT(*) AS EmailCount
FROM   dbo.tblArea
       INNER JOIN dbo.tblTerritory
         ON dbo.tblArea.AreaID = dbo.tblTerritory.AreaID
       INNER JOIN dbo.tblDistribution
         ON dbo.tblTerritory.TerritoryID = dbo.tblDistribution.TerritoryID
       INNER JOIN dbo.tblDistributionLocation
         ON dbo.tblDistribution.DistributionID = dbo.tblDistributionLocation.DistributionID
       INNER JOIN dbo.tblRegion
         ON dbo.tblArea.RegionID = dbo.tblRegion.RegionID
       INNER JOIN dbo.tblTSA
         ON dbo.tblDistributionLocation.DistributionLocationID = 
                                                       dbo.tblTSA.DistributionLocationID
       INNER JOIN dbo.tblTSAEmail
         ON dbo.tblTSA.TSAID = dbo.tblTSAEmail.TSAID
       INNER JOIN (SELECT *
                   FROM   dbo.tblCMEvalEmail
                   WHERE  ( dbo.tblCMEvalEmail.EmailSentDate 
                    BETWEEN '2013-05-19 00:00:00' AND '2013-06-16 23:59:59' )) AS TCMEvalEmail
         ON dbo.tblTSAEmail.TSAEmail = TCMEvalEmail.EmailSenderEmail
       INNER JOIN (SELECT *
                   FROM   dbo.tblCMEvalEmailInfo
                   WHERE  dbo.tblCMEvalEmailInfo.EmailCMFacingDate 
                    BETWEEN '2013-05-19 00:00:00' AND '2013-06-16 23:59:59') AS TEmailInfo
         ON TCMEvalEmail.EmailID = TEmailInfo.EmailID
WHERE  ( dbo.tblTSA.TSAActive = 1 )
       AND TCMEvalEmail.EmailStatus = 'Success'
GROUP  BY dbo.tblRegion.RegionName,
          dbo.tblDistributionLocation.DistributionLocationName,
          dbo.tblTSA.TSAName,
          TEmailInfo.EmailCM 

What's wrong with this query that it takes so much time?

But if I shorten time '2013-05-20 00:00:00' and '2013-06-16 23:59:59' then it replies so quick. What's problem with my query that it takes so much time?

Upvotes: 0

Views: 3629

Answers (3)

johnd
johnd

Reputation: 526

As marc_s points out, optimization is not a quick thing to do, nor is it a one-trick-fixes-all solution. Your best bet is to read up on the topic (see http://beginner-sql-tutorial.com/sql-query-tuning.htm for some starter tips).

You should also read up on the EXPLAIN PLAN tool (or equivalent variation for your DB) which is a vital optimisation tool; it will highlight things that can be slowing down your query on your particular database, like full table scans - eliminating these typically gives you quick wins and often a noticable improvement.

Just off the bat though, the two things that jumps out at me are:

  1. Do you have indices set up on all the IDs you're using to join? If not, this will have a negative hit on performance
  2. TCMEvalEmail.EmailStatus='Success' is a string match which is typically a slow comparison to do; without seeing the results of your Explain Plan it's hard to say, but you might want to consider replacing this with a numeric status code (e.g. a Foreign Key to a STATUS table) - but since this could be a big task you should only do it if Explain Plan highlights it as an issue.

Upvotes: 0

Robert McKee
Robert McKee

Reputation: 21487

Probably don't have the proper indexes to do the joins. You could optimize out the two subselects, but I suspect the query optimizer is doing that already.

SELECT dbo.tblRegion.RegionName, 
        dbo.tblDistributionLocation.DistributionLocationName, 
        dbo.tblTSA.TSAName,
        TEmailInfo.EmailCM,
        COUNT(*) as EmailCount
FROM dbo.tblArea 
INNER JOIN dbo.tblTerritory
 ON dbo.tblArea.AreaID = dbo.tblTerritory.AreaID
INNER JOIN dbo.tblDistribution
 ON dbo.tblTerritory.TerritoryID = dbo.tblDistribution.TerritoryID
INNER JOIN dbo.tblDistributionLocation
 ON dbo.tblDistribution.DistributionID = dbo.tblDistributionLocation.DistributionID 
INNER JOIN dbo.tblRegion
 ON dbo.tblArea.RegionID = dbo.tblRegion.RegionID 
INNER JOIN dbo.tblTSA
 ON dbo.tblDistributionLocation.DistributionLocationID = dbo.tblTSA.DistributionLocationID 
INNER JOIN dbo.tblTSAEmail
 ON dbo.tblTSA.TSAID = dbo.tblTSAEmail.TSAID 
INNER JOIN dbo.tblCMEvalEmail
 ON dbo.tblTSAEmail.TSAEmail = tblCMEvalEmail.EmailSenderEmail
   AND dbo.tblCMEvalEmail.EmailSentDate BETWEEN '2013-05-19 00:00:00' 
                                               AND '2013-06-16 23:59:59'
   AND tblCMEvalEmail.EmailStatus='Success'
INNER JOIN dbo.tblCMEvalEmailInfo
 ON tblCMEvalEmail.EmailID = tblCMEvalEmailInfo.EmailID
   AND dbo.tblCMEvalEmailInfo.EmailCMFacingDate BETWEEN '2013-05-19 00:00:00' 
                                                       and '2013-06-16 23:59:59'
WHERE (dbo.tblTSA.TSAActive = 1) 
GROUP BY dbo.tblRegion.RegionName, 
          dbo.tblDistributionLocation.DistributionLocationName, 
          dbo.tblTSA.TSAName, TEmailInfo.EmailCM

Upvotes: 0

marc_s
marc_s

Reputation: 754230

Performance tuning is not just flipping a magic switch - it's hard work.

So start with the most obvious : try to reduce your query to the absolute minimum.

E.g.

  • why are you selecting SELECT * in your inner queries, when you're only ever using a single (or two) columns from that data? Only select what you really need!

In the first case, if I'm not mistaken, you only ever need the EmailSenderEMail column - so select only that!

INNER JOIN 
(
   select EmailSenderEmail 
   from dbo.tblCMEvalEmail 
   where (dbo.tblCMEvalEmail.EmailSentDate BETWEEN '2013-05-19 00:00:00' 
                                               AND '2013-06-16 23:59:59') 
) as TCMEvalEmail  ON dbo.tblTSAEmail.TSAEmail = TCMEvalEmail.EmailSenderEmail 

In the second case, you need the EmailID for the JOIN, and the EmailCM in the output of the SELECT - so select only those two columns!

INNER JOIN 
(
    select EMailID, EMailCM
    from dbo.tblCMEvalEmailInfo 
    where dbo.tblCMEvalEmailInfo.EmailCMFacingDate BETWEEN '2013-05-19 00:00:00' 
                                                       and '2013-06-16 23:59:59'
 ) as TEmailInfo ON TCMEvalEmail.EmailID = TEmailInfo.EmailID 
  • next step: make sure you have the appropriate indexes in place. If you have subselects like these, it's extremely valuable to have an index that will cover your query, e.g. that will return exactly those columns you need. So do you have an index on dbo.tblCMEvalEmail with the EmailSenderEMail column? Do you have an index on dbo.tblCMEvalEmailInfo that contains the two columns EMailID, EMailCM ?

  • another thing: all foreign key columns should be indexed, to improve the speed of JOIN operations, and to help speed up foreign key constraint checks. Are you foreign keys used here all indexed?

Upvotes: 2

Related Questions