I have 2 tables as below:
CREATE TABLE `ox_campaigns` (
`campaignid` mediumint(9) NOT NULL auto_increment,
`campaignname` varchar(255) NOT NULL default '',
`clientid` mediumint(9) NOT NULL default '0',
`is_deleted` tinyint(1) NOT NULL default '0',
PRIMARY KEY (`campaignid`),
KEY `ox_campaigns_clientid` (`clientid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
CREATE TABLE `ox_clients` (
`clientid` mediumint(9) NOT NULL auto_increment,
`agencyid` mediumint(9) NOT NULL default '0',
`clientname` varchar(255) NOT NULL default '',
`is_deleted` tinyint(4) NOT NULL,
PRIMARY KEY (`clientid`),
UNIQUE KEY `ox_clients_account_id` (`account_id`),
KEY `ox_clients_agencyid` (`agencyid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
One client can have many campaigns linked to it.
I have a list of campaignids with me , what I want is a list of distinct clientids for those campaigns.
The query that I am using is:
SELECT clients.*
FROM clients
JOIN campaigns ON clients.clientid = campaigns.clientid
WHERE campaigns.is_deleted=0
AND campaignid in (2325,2395)
AND clients.is_deleted=0
GROUP BY clients.clientid
The EXPLAIN output that it gives is :
+----+-------------+-----------+-------+-------------------------------+---------+--------+-------------------------------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len| ref | rows| Extra |
+----+-------------+-----------+-------+-------------------------------+---------+--------+-------------------------------------------------------------------------------+
| 1 | SIMPLE | campaigns | range | PRIMARY,ox_campaigns_clientid | PRIMARY | 3 | NULL | 2 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | clients | eq_ref| PRIMARY | PRIMARY | 3 | openx.campaigns.clientid | 1 | Using where
Why it is using temporary and filesorting for this query ?
It is using filesort because of the group by
. You can prevent this by using an exists
clause for what you are doing:
SELECT c.*
FROM clients c
WHERE EXISTS (SELECT 1
FROM campaigns ca
WHERE ca.clientid = c.clientid AND
ca.is_deleted = 0 AND
ca.campaignid IN (2325,2395)
)
AND c.is_deleted = 0;
You have an index on campaigns_clientid(clientid)
, so this should use the index. A better index would be campaigns_clientid(clientid, is_deleted, campaign_id)
. This index "covers" the subquery. In other words, the engine will only use the index and not have to read in the data pages for that table.