Reputation: 3213
I have the below query to optimize.
SELECT count(*) AS count FROM area
INNER JOIN entity ON area.id = entity.id
INNER JOIN areacust ON area.id = areacust.id
WHERE entity.deleted=0
AND area.id > 0
There are indexes on deleted, ids on all the tables.
Now when i have suppose 20 Lac (2 million) of records then the query takes lots of time to give me the result. Its between 10 to 20 seconds.
How can i optimize it more. Also is there any other technique to get count.
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE vtiger_crmentity ref PRIMARY,entity_deleted_idx entity_deleted_idx 4 const 729726 Using where; Using index
1 SIMPLE area eq_ref PRIMARY PRIMARY 4 area.id 1 Using index
1 SIMPLE areacust eq_ref PRIMARY PRIMARY 4 area.id 1 Using where; Using index
New explain for composite key
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE entity ref PRIMARY,entity_deleted_idx,comp_index deleted_idx 4 const 928304 Using index
1 SIMPLE area eq_ref PRIMARY PRIMARY 4 entity.id 1 Using index
1 SIMPLE areacust eq_ref PRIMARY PRIMARY 4 entity.idid 1 Using index
Upvotes: 1
Views: 2099
Reputation: 14071
As per comments, if you want to keep the query in question - you have to allocate more resources to your MySQL instance. I am assuming you use InnoDB for storage engine, otherwise this advice is useless:
Increase the value of innodb_buffer_pool
variable. As much as you can. You want to allocate as much RAM as possible.
Also, get rid of index on deleted
column, it's useless. Its cardinality is too low for it to be an index.
The other "technique" that you can (should) use is taking care of this count manually.
Create the table that holds the count number you are interested in. Every time you update / insert / delete the entity or area record - update the count value manually (increase, decrease).
That way all you have to do is look up a single record of a single table. Setting up triggers that will sort this out automatically should be trivial. That way you'll take care of the count at runtime instead waste I/O and CPU to constantly traverse the data set.
Upvotes: 1
Reputation: 13110
You could try:
SELECT count(*) AS count
FROM area
JOIN entity
ON entity.id = area.id
AND entity.deleted = 0
JOIN areacust
ON areacust.id = area.id
I like to include conditions in JOINs where possible and keep the table I'm JOINing on the left of the equals in these conditions.
Also the WHERE area.id > 0
was strange.. most foreign_keys start at 1 due to auto_increment ids in other tables so this will include all rows. I have deleted this condition.
From the look of your explain, you don't really want the top row to be using entity_deleted_idx
. You may get more joy with a composite index on (id, deleted)
for entity
These are the indexes i'd have for this query:
area
- (id) This is probably the PRIMARY alreadyareacust
- (id) This is probably the PRIMARY alreadyentity
- (id, deleted) This should be added and used.UPDATE
Remove all unsused indexes from the table entity
except for the PRIMARY and the composite index.
If that doesn't work run:
SELECT count(*) AS count
FROM area
JOIN entity USE INDEX (**composite_index_name**)
ON entity.id = area.id
AND entity.deleted = 0
JOIN areacust
ON areacust.id = area.id
Upvotes: 0