Details
- 
    Type:
Bug
 - 
    Status: Done/Fixed
 - 
    Priority:
Major
 - 
    Resolution: Fixed/Completed
 - 
    Affects Version/s: 4.3.4
 - 
    Fix Version/s: 4.4.0
 - 
    Component/s: CiviContribute
 - 
    Labels:None
 
Description
Whilst looking at performance problems at LLR, came across the contributionCount method in the CRM_Contribute_BAO_Contribution class.
Its query is something like this
SELECT  count( contribution.id ) count
FROM  civicrm_contribution contribution LEFT JOIN civicrm_contribution_soft softContribution 
ON ( contribution.id = softContribution.contribution_id )
WHERE   contribution.is_test = 0 AND ( contribution.contact_id = 742 OR  softContribution.contact_id = 742 OR  contribution.honor_contact_id = 742 ) and 2 = 2;
-------
| count | 
-------
| 7 | 
-------
1 rows in set (3.17 sec)
This was based on a around 1.7 million contribution records.
Due to the 'OR' statements the wasn't using any indexes on the contribution table.
In our install we use this query instead
SELECT  count( x.id ) count FROM (
SELECT  contribution.id AS id
     FROM  civicrm_contribution contribution 
    WHERE   contribution.is_test = 0 AND contribution.contact_id = 742
UNION
SELECT  contribution.id
     FROM  civicrm_contribution contribution 
    WHERE   contribution.is_test = 0 AND contribution.honor_contact_id = 742
UNION
SELECT  contribution.id
     FROM  civicrm_contribution contribution INNER JOIN civicrm_contribution_soft softContribution 
                                             ON ( contribution.id = softContribution.contribution_id )
    WHERE   contribution.is_test = 0 AND softContribution.contact_id = 742) x
-------
| count | 
-------
| 7 | 
-------
1 rows in set (0.07 sec)
So my feeling is this is a much more efficient query.
Code for method is below.
    function contributionCount( $contactId, $includeSoftCredit = true, $includeHonoree = true ) 
    {
        if ( !$contactId ) return 0;
				$contactContributionsSQL = "SELECT  contribution.id AS id
     FROM  civicrm_contribution contribution 
    WHERE   contribution.is_test = 0 AND contribution.contact_id = {$contactId} ";
				$contactHonoreeContributionsSQL = "SELECT  contribution.id
     FROM  civicrm_contribution contribution 
    WHERE   contribution.is_test = 0 AND contribution.honor_contact_id = {$contactId} ";
				$contactSoftCreditContributionsSQL = "SELECT  contribution.id
     FROM  civicrm_contribution contribution INNER JOIN civicrm_contribution_soft softContribution 
                                             ON ( contribution.id = softContribution.contribution_id )
    WHERE   contribution.is_test = 0 AND softContribution.contact_id = {$contactId} ";
				$query = "SELECT  count( x.id ) count FROM ( ";
				$query .= $contactContributionsSQL;
        if ( $includeSoftCredit ) 
				
        if ( $includeHonoree ) 
				
				$query .= ") x";
        return CRM_Core_DAO::singleValueQuery( $query );
    }