Sometimes when I am comparing queries I get query plan costs that are very different, but the cpu and io numbers run just the opposite (in this case quite dissimilar).  Consider the two stored procedures below:

CREATE PROCEDURE [dbo].[Get_Communications_ByCompany]
@p_nCompanyID  int
AS
DECLARE @Error as int;
DECLARE @CompanyEntityID INT = (SELECT TOP 1 CompanyEntityID FROM dbo.UserCompanyGroup WHERE CompanyID = @p_nCompanyID);
SET NOCOUNT ON;
select         distinct c.CommunicationID, c.CommunicationTypeID, ct.TypeName,
               isnull(c.Name, '') as Name, c.CommunicationValue, c.DateAdded,
               c.AddedBy, c.DateUpdated, c.UpdatedBy
        FROM dbo.EntityAssociation ea (NOLOCK)
        JOIN dbo.Entity e2 (NOLOCK)
          ON e2.EntityID = ea.EntityID2
        JOIN dbo.Communication c (NOLOCK)
          on c.CommunicationID = e2.EntityIdentity
        JOIN dbo.CommunicationType ct (NOLOCK)
          ON ct.CommunicationTypeID = c.CommunicationTypeID
where   ea.EntityID1           = @CompanyEntityID AND
               ea.DelFlag                    = 'N' AND
               c.DelFlag                     = 'N' and
               e2.EntityTypeID               = 5 and
               e2.DelFlag             = 'N'
order by               c.CommunicationID     
SET @Error = @@Error;
RETURN @Error;
 

and

 

CREATE PROCEDURE [dbo].[Get_Communications_ByCompany2]
@p_nCompanyID  int
AS
DECLARE @Error as int;
DECLARE @CompanyEntityID INT = (SELECT TOP 1 CompanyEntityID FROM dbo.UserCompanyGroup WHERE CompanyID = @p_nCompanyID);
SET NOCOUNT ON;
select         distinct c.CommunicationID, c.CommunicationTypeID, ct.TypeName,
               isnull(c.Name, '') as Name, c.CommunicationValue, c.DateAdded,
               c.AddedBy, c.DateUpdated, c.UpdatedBy
        FROM dbo.EntityAssociation ea (NOLOCK)
        INNER HASH JOIN dbo.Entity e2 (NOLOCK)
          ON e2.EntityID = ea.EntityID2
        JOIN dbo.Communication c (NOLOCK)
          on c.CommunicationID = e2.EntityIdentity
        JOIN dbo.CommunicationType ct (NOLOCK)
          ON ct.CommunicationTypeID = c.CommunicationTypeID
where   ea.EntityID1           = @CompanyEntityID AND
               ea.DelFlag                    = 'N' AND
               c.DelFlag                     = 'N' and
               e2.EntityTypeID               = 5 and
               e2.DelFlag             = 'N'
order by               c.CommunicationID
SET @Error = @@Error;
RETURN @Error;
 
With the major different between the two queries being the INNER HASH JOIN on dbo.Entity.  I’ve rebuilt all the affected indexes and updated statistics (FULL) on dbo.EntityAssociation and dbo.Entity, but get same results. 

With statistics IO,Time on and running following code:


exec Get_Communications_ByCompany 1434
PRINT '******'
exec Get_Communications_ByCompany2 1434

 

 I get (partial results shown)

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, …
Table 'CommunicationType'. Scan count 0, logical reads 8, physical reads 0, …
Table 'Communication'. Scan count 0, logical reads 16, physical reads 0, …
Table 'Entity'. Scan count 0, logical reads 3520398, physical reads 0, …
Table 'EntityAssociation'. Scan count 1, logical reads 2558, physical reads 0, …

 SQL Server Execution Times:
   CPU time = 2672 ms,  elapsed time = 2784 ms.
******

...
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, …
Table 'CommunicationType'. Scan count 0, logical reads 8, physical reads 0, …
Table 'Communication'. Scan count 0, logical reads 16, physical reads 0, …
Table 'Workfile'. Scan count 16, logical reads 2752, physical reads 312, …
Table 'Entity'. Scan count 1, logical reads 789, physical reads 0, …
Table 'EntityAssociation'. Scan count 1, logical reads 2558, physical reads 0, r…

SQL Server Execution Times:
   CPU time = 531 ms,  elapsed time = 1223 ms.

With the following query plans respectively:



and

​Query 4:  Entity.IDX.Entity_EntityTypeDelFlag
   Actual rows returned:    169023
   Estimated rows returned: 132673
   
    EntityAssociation.IX_EntityAssociation_EntityID2
   Actual rows returned:    3383
   Estimated rows returned: 388

Where the major difference is the upper left join type and the noticeably larger number of rows from the right most lower query from the Entity table (Query 4).  However, this completely disagrees with the logical reads from the set statistics results.  Can someone point out why the large disagreement in query cost and cpu/io results.  I am puzzled with this result considering the index rebuilds.  .

Query 2:  Entity.IDX.Entity_EntityTypeDelFlag
   Actual rows returned:    169023
   Estimated rows returned: 132673

    EntityAssociation.IX_EntityAssociation_EntityID2
   Actual rows returned:    3371
   Estimated rows returned: 388

SQLMentoring