Nested set index issue - mysql

I have a query which is running a bit slow. It takes a table containing the items that result from a search and then gets the categories that contain 1 or more of these items. The categories (~300) are stored in a nested set model with around 4 levels. I need to know the counts at each level (so an item might be in the grand child category, but also needs to be counted in the child and parent categories).
The query to do this is as follows:-
SELECT category_parent.id,
category_parent.depth,
category_parent.name AS item_sub_category,
category_parent.left_index,
category_parent.right_index,
COUNT(DISTINCT item.id) as total
FROM search_enquiries_found
INNER JOIN item ON search_enquiries_found.item_id = item.id
INNER JOIN category ON item.mmg_code = category.mmg_code
INNER JOIN category category_parent ON category.left_index BETWEEN category_parent.left_index AND category_parent.right_index
WHERE search_enquiries_found.search_enquiry_id = 35
AND item.cost_price > 0
GROUP BY category_parent.id,
category_parent.depth,
item_sub_category,
category_parent.left_index,
category_parent.right_index
ORDER BY category_parent.left_index
With around 12k records found this is taking ~1.5 seconds. The explain follows:-
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE category NULL ALL left_index NULL NULL NULL 337 Using temporary; Using filesort
1 SIMPLE item NULL ref PRIMARY,id,mmg_code mmg_code 27 em_entaonline.category.mmg_code 43 Using where
1 SIMPLE search_enquiries_found NULL eq_ref search_enquiry_id,item_id,search_enquiry_id_2,search_enquiry_id_relevance search_enquiry_id 8 const,em_entaonline.item.id 1 Using index
1 SIMPLE category_parent NULL ALL left_index NULL NULL NULL 337 Range checked for each record (index map: 0x2)
The important table is the hierachical category table:-
CREATE TABLE `category` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL,
`depth` int(11) NOT NULL,
`is_active` tinyint(1) NOT NULL DEFAULT '1',
`left_index` int(4) NOT NULL,
`right_index` int(4) NOT NULL,
`mmg_code` varchar(25) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `left_index` (`left_index`,`right_index`),
UNIQUE KEY `depth` (`depth`,`left_index`,`right_index`),
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
This is not usefully using any index on the join to get parent categories.
Changing this query to remove most of the group by fields and just using the unique id (in effect the other fields in the group by are not required, but I tend to include them to keep to strict standards) reduces the time taken down to ~0.5 seconds:-
SELECT category_parent.id,
category_parent.depth,
category_parent.name AS item_sub_category,
category_parent.left_index,
category_parent.right_index,
COUNT(DISTINCT item.id) as total
FROM search_enquiries_found
INNER JOIN item ON search_enquiries_found.item_id = item.id
INNER JOIN category ON item.mmg_code = category.mmg_code
INNER JOIN category category_parent ON category.left_index BETWEEN category_parent.left_index AND category_parent.right_index
WHERE search_enquiries_found.search_enquiry_id = 35
AND item.cost_price > 0
GROUP BY category_parent.id
ORDER BY category_parent.left_index
The explain for this is very slightly different:-
id select_type table partitions type possible_keys key key_len ref rows Extra?
1 SIMPLE category NULL ALL left_index NULL NULL NULL 337 Using temporary; Using filesort
1 SIMPLE item NULL ref PRIMARY,id,mmg_code mmg_code 27 em_entaonline.category.mmg_code 43 Using where
1 SIMPLE search_enquiries_found NULL eq_ref search_enquiry_id,item_id,search_enquiry_id_2,search_enquiry_id_relevance search_enquiry_id 8 const,em_entaonline.item.id 1 Using index
1 SIMPLE category_parent NULL ALL PRIMARY,left_index,depth,name NULL NULL NULL 337 Using where; Using join buffer (Block Nested Loop)
Now I have 2 questions.
1 - Why does removing the fields from the GROUP BY (which are completely dependent on the primary key left in the group by) change the EXPLAIN this way, with such a large change in performance.
2 - In either case the performance is poor, with no key used for the join to the parent category table. Any suggestions on improving this?
As a further point, I have tried reversing the order of the joins and forcing it using STRAIGHT_JOIN. In this case this further improves the performance (~0.2 seconds), but this is an unusual situation (as it is returning all the records from the parent category table - most times the search will return far less records hence far less categories), so I think this will slow things down in more normal situations, and it still isn't using indexes on some of the joins. It would be good if MySQL could decide which way to join the tables depending on the result sets.
SELECT category_parent.id,
category_parent.depth,
category_parent.name AS item_sub_category,
category_parent.left_index,
category_parent.right_index,
COUNT(DISTINCT item.id) as total
FROM category category_parent
STRAIGHT_JOIN category ON category.left_index BETWEEN category_parent.left_index AND category_parent.right_index
STRAIGHT_JOIN item ON item.mmg_code = category.mmg_code
STRAIGHT_JOIN search_enquiries_found ON search_enquiries_found.item_id = item.id
WHERE search_enquiries_found.search_enquiry_id = 35
GROUP BY category_parent.id,
category_parent.depth,
item_sub_category,
category_parent.left_index,
category_parent.right_index
ORDER BY category_parent.left_index
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE category_parent NULL ALL left_index NULL NULL NULL 337 Using temporary; Using filesort
1 SIMPLE category NULL ALL left_index NULL NULL NULL 337 Range checked for each record (index map: 0x2)
1 SIMPLE item NULL ref PRIMARY,id,mmg_code mmg_code 27 em_entaonline.category.mmg_code 43 Using index
1 SIMPLE search_enquiries_found NULL eq_ref search_enquiry_id,item_id,search_enquiry_id_2,search_enquiry_id_relevance search_enquiry_id 8 const,em_entaonline.item.id 1 Using index

Related

Why is MySQL not using the indexes I have created?

Any ideas why index is not using on table SD and how to fix it?
I tried to remove the group and sort clauses but still same issue and cant find that is the problem
P.S. dont read this system wont let me post because code is more than description
Query
SELECT sd.filter_group_id, fgd.name AS group_name, sdc.filter_id AS filter_id, fd.name,
COUNT(DISTINCT p2c.product_id) AS total, f.sort_order, sd.sort_order AS sort,
(CASE
WHEN fgd.custom_order = 1
THEN COUNT(p2c.product_id)
END) AS custom_order
FROM oc_sd_filter sd
JOIN oc_product_to_category p2c ON p2c.category_id = sd.category_id
JOIN oc_product_filter sdc18 ON sdc18.product_id = p2c.product_id
JOIN oc_product_filter sdc21 ON sdc21.product_id = p2c.product_id
JOIN oc_product p ON p.product_id = p2c.product_id
JOIN oc_product_filter sdc ON sdc.product_id = p2c.product_id
JOIN oc_filter f ON sdc.filter_id = f.filter_id
JOIN oc_filter_description fd ON sdc.filter_id = fd.filter_id
JOIN oc_filter_group_description fgd ON fd.filter_group_id = fgd.filter_group_id
WHERE sd.category_id = '93'
AND p.status = '1'
AND sd.filter_group_id = fd.filter_group_id
AND sd.status = 1
AND sdc18.filter_id IN (199,200,120,321,611,451,380,542)
AND sdc21.filter_id IN (241,242)
GROUP BY fd.filter_id, fd.filter_group_id
ORDER BY sd.sort_order ASC,
(CASE
WHEN fgd.custom_order = 0
THEN f.sort_order
END) ASC,
(CASE
WHEN fgd.custom_order = 1
THEN COUNT(p2c.product_id)
END) DESC
EXPLAIN
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE sd ALL filter,cat,status NULL NULL NULL 11 Using where; Using temporary; Using filesort
1 SIMPLE fgd ref PRIMARY,filter_group_id PRIMARY 4 example_db.sd.filter_group_id 1
1 SIMPLE p2c ref PRIMARY,category_id, category_id 4 example_db.sd.category_id 59 Using index
1 SIMPLE p eq_ref PRIMARY,status,product_id PRIMARY 4 example_db.p2c.product_id 1 Using where
1 SIMPLE sdc ref PRIMARY PRIMARY 4 example_db.p2c.product_id 9 Using index
1 SIMPLE fd ref PRIMARY,filter PRIMARY 4 example_db.sdc.filter_id 1 Using where
1 SIMPLE f eq_ref PRIMARY PRIMARY 4 example_db.sdc.filter_id 1
1 SIMPLE sdc21 ref PRIMARY PRIMARY 4 example_db.p2c.product_id 9 Using where; Using index
1 SIMPLE sdc18 ref PRIMARY PRIMARY 4 example_db.p2c.product_id 9 Using where; Using index
Table
CREATE TABLE `oc_sd_filter` (
`id` int(11) NOT NULL,
`category_id` int(11) NOT NULL,
`filter_group_id` int(11) NOT NULL,
`status` int(11) NOT NULL,
`sort_order` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Indexes for table `oc_sd_filter`
--
ALTER TABLE `oc_sd_filter`
ADD PRIMARY KEY (`id`),
ADD KEY `filter` (`filter_group_id`),
ADD KEY `cat` (`category_id`),
ADD KEY `status` (`status`),
ADD KEY `sort_order` (`sort_order`);
Suggested composite indexes:
sd: INDEX(category_id, status, filter_group_id, sort_order)
fgd: INDEX(filter_group_id, name, custom_order)
sdc: INDEX(product_id, filter_id)
fd: INDEX(filter_group_id, filter_id, name)
p2c: INDEX(category_id, product_id)
f: INDEX(filter_id, sort_order)
oc_product_filter: INDEX(product_id, filter_id)
p: INDEX(status, product_id)
When adding a composite index, DROP index(es) with the same leading columns.
That is, when you have both INDEX(a) and INDEX(a,b), toss the former.
If that does not help enough, come back and we can talk about turning the query inside out -- so that the GROUP BY is done before most of the JOINs. But first, how many rows in the resultset? How many rows if you take out the GROUP BY clause?
Example (from Comment):
SELECT filter_group_id
FROM sd
WHERE status = 1
ORDER BY sort_order
The Optimal index is both composite and "covering"; the order is important:
INDEX(status, sort_order, filter_group_id)
Any longer index starting with those is essentially "as good". Any shorter index (eg, INDEX(status, sort_order) or starting with that) will be "good", but "not as good".
In particular, the 4-column index I provided above is not useful. It is OK to add both indexes; the Optimizer will decide which index to use for each SELECT.

MySQL query performance improvement

I have a problem with performance with MySQL. How can i improve it?
The situation is following:
Table “backlogsap„ have about 4 mio entries.
Indexes are created
This table have FK and other tables have FK to this table => can’t
create partitions.
This query need about 140 seconds to complete:
select
idmaterial,
materialgroup,
materialgroupcategory,
name,
dispatchgroup,
idsupplier,
group_concat(distinct sellingorganizationname) as sellingorganizationnames,
group_concat(distinct idordertype) as idordertypes,
group_concat(distinct idpositiontype) as idpositiontypes,
sum(newOrUpdated and isCritical) as classA,
sum(newOrUpdated and not isCritical) as classB,
sum(processingstate <3) as classC,
(select count(innerBacklogsAp.idmaterial)
from backlogsap as innerBacklogsAp
where innerBacklogsAp.idmaterial = src.idmaterial and IsDeleted = 0) as countReplacementVehiclerRequests
from
(select
backlogsap.idmaterial as idmaterial,
backlog.processingstate as processingstate,
material.idsupplier as idsupplier,
backlogsap.sellingorganizationname as sellingorganizationname,
backlogsap.idpositiontype as idpositiontype,
backlogsap.idordertype as idordertype,
materialindistributioncenter.dispatchgroup as dispatchgroup,
material.name as name,
material.idmaterialgroup as materialgroup,
materialgroup.idmaterialgroupcategory as materialgroupcategory,
(processingstate = 0 or processingstate = 1) as newOrUpdated,
((cancellation.state is not null and cancellation.state = 0 ) or
(reminderrequest.state is not null and (reminderrequest.state = 2 or reminderrequest.state = 0))
) as isCritical
from backlogsap
join backlog using (idbacklogsap)
left join cancellation using (idcancellation)
left join reminderrequest on backlog.IdReminderRequest = reminderrequest.idreminder
left join material using (idmaterial)
left join materialindistributioncenter using (idmaterial, iddistributioncenter)
left join materialgroup using (idmaterialgroup)
where (idcancellation is null or cancellation.State not in (1)) and
backlogsap.isdeleted = 0 and
backlogsap.idordertype not in ('ZAP', 'ZAK', 'ZAKO', 'ZAKZ', 'ZAPM') and
iddistributioncenter = 1469990
) as src
group by idmaterial
order by classA desc, classB desc, classC, idmaterial desc
Explain
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived3> ALL 26960 Using temporary; Using filesort
3 DERIVED backlogsap index_merge PRIMARY,fk_BacklogSap_OrderType1_idx,
fk_BacklogSap_MaterialInDistributionCenter1_idx,
perform_backlogsap_isdeleted,
fk_BacklogSap_DistributionCenter_idx perform_backlogsap_isdeleted,fk_BacklogSap_DistributionCenter_idx 1,4 35946 Using intersect(perform_backlogsap_isdeleted,fk_BacklogSap_DistributionCenter_idx); Using where
3 DERIVED backlog eq_ref idBacklogSAP_UNIQUE,
fk_Backlog_BacklogSap1_idx,
fk_Backlog_Cancellation1_idx idBacklogSAP_UNIQUE 4 ...backlogsap.IdBacklogSap 1
3 DERIVED cancellation eq_ref PRIMARY PRIMARY 4 ...backlog.IdCancellation 1 Using where
3 DERIVED reminderrequest eq_ref PRIMARY PRIMARY 4 ...backlog.IdReminderRequest 1
3 DERIVED material eq_ref PRIMARY PRIMARY 45 ...backlogsap.IdMaterial 1
3 DERIVED materialindistributioncenter eq_ref PRIMARY,
unqiue_IdDistributionCenter_IdMaterial,
fk_MaterialDistributionCenter_DistributionCenter1_idx,
fk_MaterialDistributionCenter_Material1_idx PRIMARY 49 const,...backlogsap.IdMaterial 1
3 DERIVED materialgroup eq_ref PRIMARY PRIMARY 137 ....material.IdMaterialGroup 1
2 DEPENDENT SUBQUERY innerBacklogsAp ref perform_backlogsap_isdeleted,
idx_backlogsap_IdMaterial idx_backlogsap_IdMaterial 45 func 8 Using where
Solved: created combined Index (idmaterial, IsDeleted)

mysql Query slow on view for search

Our search is very slow on view. we can't define index on view.. Please help how we can improve this .. Below Query took 33.3993 sec.
SELECT
`v_cat_pro`.`product_id`, `v_cat_pro`.`msrp`,
FROM
`v_prod_cat` AS `v_cat_pro`
WHERE
(product_status="1" and msrp >0 AND (search_text = 'de') )
ORDER BY
`msrp` ASC LIMIT 50
Explain query result
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE cat_product index catproducts_product_id,category_product_index category_product_index 8 NULL 941343 Using index; Using temporary; Using filesort
1 SIMPLE dept eq_ref PRIMARY PRIMARY 4 newdhf.cat_product.category_id 1 Using where
1 SIMPLE team eq_ref PRIMARY PRIMARY 4 newdhf.dept.parent_id 1 Using where
1 SIMPLE league eq_ref PRIMARY PRIMARY 4 newdhf.team.parent_id 1 Using where
1 SIMPLE product eq_ref PRIMARY PRIMARY 4 newdhf.cat_product.product_id 1 Using where
CREATE
ALGORITHM=UNDEFINED VIEW v_prod_cat AS
select
dept.id AS dept_id,team.short_name AS shortteamname,team.url AS team_url,team.id AS team_id,league.id AS league_id,product.product_id AS product_id,product.product_status AS product_status,product.upload_image_l AS upload_image_l,dept.name AS department,team.name AS team,league.name AS league,product.title AS title,cat_product.product_url AS product_url,product.discount AS discount,product.discount_start_date AS discount_start_date,product.discount_end_date AS discount_end_date,product.extra_discount AS extra_discount,product.extra_discount_start_date AS extra_discount_start_date,product.extra_discount_end_date AS extra_discount_end_date,product.global_alt_tag AS global_alt_tag,product.msrp AS msrp,product.cost AS cost,product.vendor_id AS vendor_id,if((cat_product.is_default > 0),1,0) AS is_default,
concat(league.name,_utf8' ',team.name,_utf8' ',dept.name,_utf8' ',replace(replace(replace(replace(product.title,'$leaguename',league.name),'$teamname',team.name),'$shortteamname',team.short_name),'$departmentname',dept.name),' ',product.sku_code,_utf8' ',replace(replace(replace(replace(product.site_search_keyword,'$leaguename',league.name),'$teamname',team.name),'$shortteamname',team.short_name),'$departmentname',dept.name)) AS search_text
from
((((categories dept join categories team on(((team.id = dept.parent_id) and (team.category_type = _utf8'team')))) join categories league on(((league.id = team.parent_id) and (league.category_type = _utf8'league')))) join category_products cat_product on((cat_product.category_id = dept.id))) join products product on((product.product_id = cat_product.product_id))) where (dept.category_type = _utf8'department')
order by
dept.id desc;
If you add an index to your 'v_prod_cat' table on the columns that you are searching on then this should help speed up your view.

Optimize a query

I got this query. It take ~0.0854 seconds to excutes. I find it a little slow. Below see my explain
SELECT
stops.stop_number,
stops.stop_name_1,
stops.stop_name_2
FROM
tranzit.stops_times
INNER JOIN
tranzit.stops
ON
(
stops_times.stop_id = stops.stop_id
)
INNER JOIN
tranzit.trips
ON
(
stops_times.trip_id = trips.trip_id
)
WHERE
trips.route_id = 109 AND
trips.trip_direction = 1 AND
trips.trip_period_start <= "2011-11-24" AND
trips.trip_period_end >= "2011-11-24"
GROUP BY
stops.stop_id
ORDER BY
stops_times.time_sequence ASC
LIMIT
0, 200
Explain
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE trips index_merge trip_id,trip_period_start,trip_period_end,trip_dir... route_id,trip_direction 3,1 NULL 271 Using intersect(route_id,trip_direction); Using wh...
1 SIMPLE stops_times ref stop_id,trip_id trip_id 16 tranzit.trips.trip_id 24
1 SIMPLE stops ref stop_id stop_id 3 tranzit.stops_times.stop_id 1 Using where
And I have indexe on trips :
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
trips 1 agency_id 1 agency_id A 2 NULL NULL BTREE
trips 1 trip_id 1 trip_id A 9361 NULL NULL BTREE
trips 1 trip_period_start 1 trip_period_start A 2 NULL NULL BTREE
trips 1 trip_period_end 1 trip_period_end A 2 NULL NULL BTREE
trips 1 trip_direction 1 trip_direction A 2 NULL NULL BTREE
trips 1 route_id 1 route_id A 106 NULL NULL BTREE
trips 1 shape_id 1 shape_id A 520 NULL NULL BTREE
trips 1 trip_terminus 1 trip_terminus A 301 NULL NULL BTREE
Indexes on stops
stop_number BTREE Non Non stop_number 4626 A
agency_id BTREE Non Non agency_id 1 A
stop_id BTREE Non Non stop_id 4626 A
Thanks for any help
Given how many rows you have in the tables it is already running pretty quick. You could try a few different approaches such as added more where conditions or performing a simple select and then running a second query to get the needed join fields. But these aren't where you really need to focus.
The important question is how will this query behave in the wild. If you are running it 100 times every second you need to know if it is going to degrade and become a bottleneck. If it can run in 0.08 every time, then that still allows for a very responsive application.
The most important strategy however, if it is possible and came be made effective, is using memcache or a similar option to prevent running the query all the time.
As people wrote before:
Split to 2 queries:
Trip information, by group_concat to make it faster
SELECT group_concat(trip_id) FROM trips WHERE
trips.route_id = 109 AND
trips.trip_direction = 1 AND
trips.trip_period_start = "2011-11-24"
Next Information
SELECT
stops.stop_number,
stops.stop_name_1,
stops.stop_name_2
FROM
tranzit.stops_times,
tranzit.stops
WHERE
stops_times.stop_id = stops.stop_id
AND
stops_times.trip_id in ( ...)
GROUP BY, ...
I think it will be faster, as you don't need other information from trips table outside the query.
the most tricky part is on the range query trip_period_start, trip_period_end,
I think you can consider a composite key like:-
alter table trips
add index testing
(
route_id, trip_direction, trip_period_start, trip_period_end
);
depend on how many unique value for trip_direction,
if always only a few unique values,
alter table trips
add index testing
(
route_id, trip_period_start, trip_period_end, trip_direction
);
Already less than 1 tenth of a second and you want it faster? ok...
I would build a composite index on ( route_id, trip_direction, trip_period_start ) as those are the three critical elements of your query. Also, in that order to have the smallest granularity to the front of the index (specific route). Then, within that, its direction, then, the dates. Next, I would swap the order of the query with the trips table up front since you are doing INNER joins. Additionally, have an index on your "stops_times" table on TRIP_ID. By starting with the first table with its qualifiers, then joining to the child-level tabls via relations, you still get the elements, but you are running against the smallest index set first on trips.
select STRAIGHT_JOIN
stops.stop_number,
stops.stop_name_1,
stops.stop_name_2
from
tranzit.trips
join tranzit.stops_times
on trips.trip_id = stops_times.trip_id
join tranzit.stops
on stops_times.stop_id = stops.stop_id
where
trips.route_id = 109
AND trips.trip_direction = 1
AND trips.trip_period_start <= "2011-11-24"
AND trips.trip_period_end >= "2011-11-24"
group by
stops.stop_id
ORDER BY
stops_times.time_sequence
LIMIT
0, 200
I found something that work like a charm. My results number are :
0.0011
0.0008
0.0017 (highest)
0.0006 (lowest)
0.0013
These result aren't from the cache. I switch all the WHERE in t (trips.agency_id, trips.route_id, trips.trip_direction, trips.trip_period_start, trips.trip_period_end) and it is working very good ! I can't explain why but if someone can, i'd like to see why. Thanks a lot everyone !
PS : Even without trips.agency_id it is working great.
SELECT
stops.stop_number,
stops.stop_name_1,
stops.stop_name_2
FROM
tranzit.stops_times,
tranzit.stops,
(
SELECT
trips.trip_id
FROM
tranzit.trips
WHERE
trips.agency_id = 5 AND
trips.route_id = 109 AND
trips.trip_direction = 0 AND
trips.trip_period_start <= "2011-12-01" AND
trips.trip_period_end >= "2011-12-01"
LIMIT 1
) as t
WHERE
stops_times.stop_id = stops.stop_id AND
stops_times.trip_id in (t.trip_id)
GROUP BY
stops_times.stop_id
ORDER BY
stops_times.time_sequence ASC
LIMIT
0, 200
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> system NULL NULL NULL NULL 1 Using temporary; Using filesort
1 PRIMARY stops_times ref trip_id,stop_id trip_id 16 const 33 Using where
1 PRIMARY stops ref stop_id stop_id 3 tranzit.stops_times.stop_id 1 Using where
2 DERIVED trips ref testing testing 4 275 Using where

How can I optimise my MySQL query?

I'm having real difficulties optimising a MySQL query. I have to use the existing database structure, but I am getting an extremely slow response under certain circumstances.
My query is:
SELECT
`t`.*,
`p`.`trp_name`,
`p`.`trp_lname`,
`trv`.`trv_prosceslevel`,
`trv`.`trv_id`,
`v`.`visa_destcountry`,
`track`.`track_id`,
`track`.`track_datetoembassy`,
`track`.`track_expectedreturn`,
`track`.`track_status`,
`track`.`track_comments`
FROM
(SELECT
*
FROM
`_transactions`
WHERE
DATE(`tr_datecreated`) BETWEEN DATE('2011-07-01 00:00:00') AND DATE('2011-08-01 23:59:59')) `t`
JOIN
`_trpeople` `p` ON `t`.`tr_id` = `p`.`trp_trid` AND `p`.`trp_name` = 'Joe' AND `p`.`trp_lname` = 'Bloggs'
JOIN
`_trvisas` `trv` ON `t`.`tr_id` = `trv`.`trv_trid`
JOIN
`_visas` `v` ON `trv`.`trv_visaid` = `v`.`visa_code`
JOIN
`_trtracking` `track` ON `track`.`track_trid` = `t`.`tr_id` AND `p`.`trp_id` = `track`.`track_trpid` AND `trv`.`trv_id` = `track`.`track_trvid` AND `track`.`track_status` IN ('New','Missing_Info',
'En_Route',
'Ready_Pickup',
'Received',
'Awaiting_Voucher',
'Sent_Client',
'Closed')
ORDER BY `tr_id` DESC
The results of an explain statement on the above is:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 164 Using temporary; Using filesort
1 PRIMARY track ALL status_index NULL NULL NULL 4677 Using where
1 PRIMARY p eq_ref PRIMARY PRIMARY 4 db.track.track_trpid 1 Using where
1 PRIMARY trv eq_ref PRIMARY PRIMARY 4 db.track.track_trvid 1 Using where
1 PRIMARY v eq_ref visa_code visa_code 4 db.trv.trv_visaid 1
2 DERIVED _transactions ALL NULL NULL NULL NULL 4276 Using where
The query times are acceptable until the value of 'Closed' is included in the very last track.track_status IN clause. The length of time is then increased about 10 to 15 times the other queries.
This makes sense as the 'Closed' status refers to all the clients whose transactions have been dealt with, wihich corresponds to about 90% to 95% of the database.
The issue is, is that in some cases, the search is taking about 45 seconds which is rediculous. I'm sure MySQL can do much better than that and it's just my query at fault, even if the tables do have 4000 rows, but I can't work out how to optimise this statement.
I'd be grateful for some advice about where I'm going wrong and how I should be implementing this query to produce a faster result.
Many thanks
Try this:
SELECT t.*,
p.trp_name,
p.trp_lname,
trv.trv_prosceslevel,
trv.trv_id,
v.visa_destcountry,
track.track_id,
track.track_datetoembassy,
track.track_expectedreturn,
track.track_status,
track.track_comments
FROM
_transactions t
JOIN _trpeople p ON t.tr_id = p.trp_trid
JOIN _trvisas trv ON t.tr_id = trv.trv_trid
JOIN _visas v ON trv.trv_visaid = v.visa_code
JOIN _trtracking track ON track.track_trid = t.tr_id
AND p.trp_id = track.track_trpid
AND trv.trv_id = track.track_trvid
WHERE DATE(t.tr_datecreated)
BETWEEN DATE('2011-07-01 00:00:00') AND DATE('2011-08-01 23:59:59')
AND track.track_status IN ('New','Missing_Info','En_Route','Ready_Pickup','Received','Awaiting_Voucher','Sent_Client', 'Closed')
AND p.trp_name = 'Joe' AND p.trp_lname = 'Bloggs'
ORDER BY tr_id DESC