I would like to ask, how can I optimize this query:
select
h.jmeno hrac,
n1.url hrac_url,
t.nazev tym,
n2.url tym_url,
ss.pocet_zapasu zapasy,
ss.pocet_minut minuty,
s.celkem_golu goly,
s.zk,
s.ck
from
hraci h
left join
(
select
hrac_id,
tym_id,
count(minut_celkem) pocet_zapasu,
sum(minut_celkem) pocet_minut
from
statistiky_stridani ss
join
zapasy z
on z.id = ss.zapas_id
join
souteze s
on s.id = z.soutez_id
join
souteze_nazev sn
on sn.id = s.soutez_id
where
s.rocnik_id = 2
group by
hrac_id
) ss on ss.hrac_id = h.id
left join
(
select
hrac_id,
tym_id,
sum(typ_id = 1 or typ_id = 3) as celkem_golu,
sum(typ_id = 4) as zk,
sum(typ_id = 5) as ck
from
statistiky st
join
zapasy z
on z.id = st.zapas_id
join
souteze s
on s.id = z.soutez_id
join
souteze_nazev sn
on sn.id = s.soutez_id
where
s.rocnik_id = 2
group by
hrac_id
) s on s.hrac_id = h.id
join
navigace n1
on n1.id = h.nav_id
join
tymy t
on t.id = ss.tym_id
join
navigace n2
on n2.id = t.nav_id
order by
s.celkem_golu desc
limit
10
Because query takes about 1,5 - 2 seconds. For example, table statistiky_stridani has about 500 000 rows and statistiky about 250 000 rows.
This returns EXPLAIN:
Thank you for your help
Don't use LEFT JOIN instead of JOIN unless you really need the empty rows.
Try to reformulate because JOIN ( SELECT ... ) JOIN ( SELECT ... ) optimizes poorly.
Please do not use the same alias (s) for two different tables; it confuses the reader.
Add the composite index INDEX(rocnik_id, soutez_id) to souteze.
LEFT JOIN ... JOIN ... -- Please add parentheses to show whether the JOIN should be before doing the LEFT JOIN or after:
either
FROM ...
LEFT JOIN ( ... JOIN ... )
or
FROM ( ... LEFT JOIN ... )
JOIN ...
It may make a big difference in how the Optimizer performs the query, which may change the speed.
There may be more suggestions; work through those and ask again (if it is still "too slow").
Related
Hi i want fetch the records depends on different condition i used union worked fine but taking more than 15 secs so how can we eliminate union or make the query faster
QUERY:
(SELECT p.professional_id,
p.company_name,
pbt.name AS professional_business_type_name,
pbtm.kukun_url,
p.kukun_score,
cc.year_founded,
p.contractor_category,
p.permit_data_count,
p.cost_range_code,
fpcr.cost_min_value,
fpcr.cost_max_value
FROM professional p
INNER JOIN company_contact cc
ON cc.company_contact_id = p.company_contact_id
INNER JOIN professional_business_type_map AS pbtm
ON pbtm.professional_id = p.professional_id
INNER JOIN of_professional_business_type_organization AS pbt
ON pbt.professional_business_type_organization_id =
pbtm.professional_business_type_organization_id
INNER JOIN f_professional_cost_range fpcr
ON fpcr.cost_range_code = p.cost_range_code
WHERE p.professional_id != 262100
AND cc.company_city_id = 5229
AND pbt.professional_business_type_organization_id = 2
AND p.cost_range_code = 4
ORDER BY p.kukun_score DESC
LIMIT 5)
UNION
(SELECT p.professional_id,
p.company_name,
pbt.name AS professional_business_type_name,
pbtm.kukun_url,
p.kukun_score,
cc.year_founded,
p.contractor_category,
p.permit_data_count,
p.cost_range_code,
fpcr.cost_min_value,
fpcr.cost_max_value
FROM professional p
INNER JOIN company_contact cc
ON cc.company_contact_id = p.company_contact_id
INNER JOIN professional_business_type_map AS pbtm
ON pbtm.professional_id = p.professional_id
INNER JOIN of_professional_business_type_organization AS pbt
ON pbt.professional_business_type_organization_id =
pbtm.professional_business_type_organization_id
INNER JOIN f_professional_cost_range fpcr
ON fpcr.cost_range_code = p.cost_range_code
WHERE p.professional_id != 262100
AND cc.company_city_id = 5229
AND pbt.professional_business_type_organization_id = 2
ORDER BY p.kukun_score DESC
LIMIT 5)
UNION
(SELECT p.professional_id,
p.company_name,
pbt.name AS professional_business_type_name,
pbtm.kukun_url,
p.kukun_score,
cc.year_founded,
p.contractor_category,
p.permit_data_count,
p.cost_range_code,
fpcr.cost_min_value,
fpcr.cost_max_value
FROM professional p
INNER JOIN company_contact cc
ON cc.company_contact_id = p.company_contact_id
INNER JOIN professional_business_type_map AS pbtm
ON pbtm.professional_id = p.professional_id
INNER JOIN of_professional_business_type_organization AS pbt
ON pbt.professional_business_type_organization_id =
pbtm.professional_business_type_organization_id
INNER JOIN f_professional_cost_range fpcr
ON fpcr.cost_range_code = p.cost_range_code
WHERE p.professional_id != 262100
AND cc.company_city_id = 5229
ORDER BY p.kukun_score DESC
LIMIT 5)
UNION
(SELECT p.professional_id,
p.company_name,
pbt.name AS professional_business_type_name,
pbtm.kukun_url,
p.kukun_score,
cc.year_founded,
p.contractor_category,
p.permit_data_count,
p.cost_range_code,
fpcr.cost_min_value,
fpcr.cost_max_value
FROM professional p
INNER JOIN company_contact cc
ON cc.company_contact_id = p.company_contact_id
INNER JOIN professional_business_type_map AS pbtm
ON pbtm.professional_id = p.professional_id
INNER JOIN of_professional_business_type_organization AS pbt
ON pbt.professional_business_type_organization_id =
pbtm.professional_business_type_organization_id
INNER JOIN f_professional_cost_range fpcr
ON fpcr.cost_range_code = p.cost_range_code
WHERE p.professional_id != 262100
AND cc.company_state_id = 5
ORDER BY p.kukun_score DESC
LIMIT 5)
LIMIT 5;
(Likely Bug) You need ORDER BY p.kukun_score DESC before the UNION's LIMIT 5. Today MySQL may sequentially perform all parts of the UNION, combine all of them, then do the LIMIT. In some future version, it is likely to, for example, perform the SELECTs in parallel, thereby jumbling the results.
Hence if you want the rows from the first SELECT to be delivered first, you must add a column and ORDER BY.
( SELECT 1 AS sequence, ... )
UNION ALL
( SELECT 2 AS sequence, ... )
...
ORDER BY sequence, kukun_score DESC
LIMIT 5
Also, UNION is the same as UNION DISTINCT, which add a de-dup pass to the operation. That is, the semantics requires evaluating all the selects.
These INDEXes may help:
cc: (company_state_id, company_contact_id, year_founded)
cc: (company_city_id, company_contact_id, year_founded)
fpcr: (cost_range_code, cost_max_value, cost_min_value)
Those indexes will be "covering" and optimal for the SQL you have.
Some benefit will come from moving fpcr out of the union. That is, first UNION all the other tables, then JOIN to fpcr. to get the two columns from it. This will speed things up because it it needs to reach into that table only 5 times, instead of thousands times (however many rows are in the 4 temporary tables).
I would like to search a keyword from the result of the subquery. In my subquery I already filtered the grants I need from different category required. Now I need to search the keyword in title for those results. Or is there efficient way to do this query because my work is not working after days stuck?
I tried working on the IN but still did not get it right.
SELECT DISTINCT gt.grant_id, gt.*,
infra.infra_name,
infrasub.infrasub_name,
lga.lga_name,
stream.stream_id,
stream.stream_n,
stream.stream_dept,
stream.stream_desc
FROM
grant_tbl AS gt
LEFT JOIN grant_details AS gd
ON (
gt.grant_id = gd.grant_id
)
LEFT JOIN infra_sub_tbl AS infrasub
ON (
infrasub.infra_sub_id = gd.infrasub_id
)
LEFT JOIN infra_tbl AS infra
ON (
infra.infra_id = gd.infra_id
)
LEFT JOIN lga_tbl AS lga
ON (
lga.lga_id = gd.lga_id
)
LEFT JOIN streams_tbl AS stream
ON (
stream.stream_id = gd.stream_id
)
WHERE gt.grant_id IN
(
SELECT DISTINCT gd.grant_id, CONCAT(gt.grant_name,"|",gt.grant_desc,"|",gt.keywords)
FROM grant_details AS gd
LEFT JOIN grant_tbl AS gt
ON gt.grant_id = gd.grant_id
WHERE gd.lga_id = 1
OR gd.lga_id = 2
AND gd.stream_id = 1
OR gd.stream_id = 2
GROUP BY gt.grant_id
)
my result should narrow down from my subquery. display only with matching keyworkds
You can use EXISTS instead of IN,
SELECT DISTINCT gt.grant_id, gt.*,
infra.infra_name,
infrasub.infrasub_name,
lga.lga_name,
stream.stream_id,
stream.stream_n,
stream.stream_dept,
stream.stream_desc
FROM grant_tbl AS gt
LEFT JOIN grant_details AS gd ON gt.grant_id = gd.grant_id
LEFT JOIN infrasub_tbl AS infrasub ON infrasub.infrasub_id = gd.infrasub_id
LEFT JOIN infra_tbl AS infra ON infra.infra_id = gd.infra_id
LEFT JOIN lga_tbl AS lga ON lga.lga_id = gd.lga_id
LEFT JOIN stream_tbl AS stream ON stream.stream_id = gd.stream_id
WHERE exists
(
SELECT DISTINCT gd.grant_id,CONCAT(gt2.grant_name,"|",gt2.grant_desc,"|",gt2.keywords)
FROM grant_details AS gd
LEFT JOIN grant_tbl AS gt2 ON gt2.grant_id = gd.grant_id
WHERE (gd.lga_id = 10 OR gd.lga_id = 20) AND (gd.stream_id = 100 OR gd.stream_id = 200)
and gt.grant_id=gt2.grant_id
GROUP BY gt.grant_id
)
Hope this helps.
I have the SQL to display ALL the activities and relative Admin permissions (if any) for that activity.
Current SQL Code:
SELECT `activities`.*, `admins`.`admin_role_id`
FROM (`activities`)
LEFT JOIN `admins` ON `admins`.`activity_id`=`activities`.`id` AND admins.member_id=27500
WHERE `activities`.`active` = 1
Returning:
id | name | description | active | admin_role_id (or null)
I then need to detect whether they are an active member within that Activity.
I have the following SQL code:
SELECT DISTINCT `products`.`activity_ID` as joinedID
FROM (`transactions_items`)
JOIN `transactions` ON `transactions`.`id` = `transactions_items`.`id`
JOIN `products` ON `products`.`id` = `transactions_items`.`product_id`
JOIN `activities` ON `activities`.`id` = `products`.`activity_ID`
WHERE `transactions`.`member_id` = 27500
AND `activities`.`active` = 1
Is there any way to merge this into one SQL query. I can't figure out how to use the correct JOIN queries, because of the complexity of the JOINs.
Help please, thanks! :)
Try like this
SELECT `activities`.*, `admins`.`admin_role_id`
FROM (`activities`)
LEFT JOIN `admins` ON `admins`.`activity_id`=`activities`.`id` AND admins.member_id=27500
JOIN (`transactions_items`
JOIN `transactions` ON `transactions`.`id` = `transactions_items`.`id`
JOIN `products` ON `products`.`id` = `transactions_items`.`product_id`)
ON `activities`.`id`=`products`.`activity_ID`
WHERE `transactions`.`member_id` = 27500
AND `activities`.`active` = 1
Seems to me that a query like this would be marginally more comprehensible and (I think) adhere more closely to the spec...
SELECT c.*
, d.admin_role_id
FROM activities c
LEFT
JOIN admins d
ON d.activity_id = c.id
AND d.member_id = 27500
LEFT
JOIN products p
ON p.activity_ID = c.id
LEFT
JOIN transactions_items ti
ON ti.product_id = p.id
LEFT
JOIN transactions t
ON t.id = ti.id
AND t.member_id = 27500
WHERE c.active = 1
Hi hope someone can advise
I have a sql query that went it runs it repeats the same result by the number of users (entries) made
for example:
post_id
20
20
19
19
18
18
Here is the query it takes no arguments, could someone explain why this is happening please?
Thanks
SELECT DISTINCT post_look.post_id, post_look.look_id, post_look.date_posted, looks.title, looks.item_id, user.user_id, user.first_name, user.last_name, user_account.profile_image, user_account.account_status, add_profile_images.image_name
FROM post_look
JOIN looks ON looks.look_id = post_look.look_id
JOIN add_look_item ON add_look_item.look_id = looks.look_id
JOIN item ON item.item_id = add_look_item.item_id
JOIN add_images ON add_images.item_id = item.item_id
JOIN user_item ON user_item.item_id = item.item_id
JOIN user_account ON user_account.account_id = user_item.account_id
JOIN user ON user.user_id = user_account.user_id
JOIN users_profile_images ON users_profile_images.account_id = user_account.account_id
JOIN add_profile_images ON add_profile_images.image_id = users_profile_images.image_id
ORDER BY post_look.post_id DESC
LIMIT 0 , 30
SELECT DISTINCT c1, c2, c3
means that {c1, c2, c3} will be distinct.
You should consider adding GROUP BY post_look.post_id to your query.
See the difference here:
DISTINCT
GROUP BY
Would you please try it?
SELECT post_look.post_id, post_look.look_id, post_look.date_posted, looks.title, looks.item_id, user.user_id, user.first_name, user.last_name, user_account.profile_image, user_account.account_status, add_profile_images.image_name
FROM post_look
JOIN looks ON looks.look_id = post_look.look_id
JOIN add_look_item ON add_look_item.look_id = looks.look_id
JOIN item ON item.item_id = add_look_item.item_id
JOIN add_images ON add_images.item_id = item.item_id
JOIN user_item ON user_item.item_id = item.item_id
JOIN user_account ON user_account.account_id = user_item.account_id
JOIN user ON user.user_id = user_account.user_id
JOIN users_profile_images ON users_profile_images.account_id = user_account.account_id
JOIN add_profile_images ON add_profile_images.image_id = users_profile_images.image_id
GROUP BY post_look.post_id
ORDER BY post_look.post_id DESC
LIMIT 0 , 30
I have a query which has multiple tables joined using distincct - left join - order by - limit clause.
The query looks like this:-
Select DISTINCT a.col1, b.col2, c.col3, d.col4, e.col5, f.col6, g.col7, h.col8,
i.col9, j.col10
From test_a a
left join test_b b on a.col1 = b.col2
left join test_c c on c.col1 = d.col2
left join test_d d on d.col1 = c.col2
left join test_e e on e.col1 = d.col2
left join test_f f on f.col1 = e.col2
left join test_g g on g.col1 = f.col2
left join test_h h on h.col1 = a.col1
left join test_i i on i.col1 = f.col2
left join test_j j on j.col1 = i.col2
Where a.col2 = 'Y'
and c.col4 = 1
Order by h.col5 desc
limit 50;
All the column used the in coditions has index on it. And explan output of this query gives resultset where I can see it uses all the index properly and total rows it scanned from all the tables is 18000.
What I am wondering in this query is. It runs within seconds if I run it without order by clause. Something like:
Select DISTINCT a.col1, b.col2, c.col3, d.col4, e.col5, f.col6, g.col7, h.col8,
i.col9, j.col10
From test_a a
left join test_b b on a.col1 = b.col2
left join test_c c on c.col1 = d.col2
left join test_d d on d.col1 = c.col2
left join test_e e on e.col1 = d.col2
left join test_f f on f.col1 = e.col2
left join test_g g on g.col1 = f.col2
left join test_h h on h.col1 = a.col1
left join test_i i on i.col1 = f.col2
left join test_j j on j.col1 = i.col2
Where a.col2 = 'Y'
and c.col4 = 1
limit 50;
And if I run it with order by clause then it takes 30-40 seconds to execute.
I tried using the index hint functionality provided by mysql:- USE INDEX FOR ORDER BY (idx_h_col5), but I am getting syntax error while executing this query. The error message says incorrect syntax near
I have one composite index on the column used in order by clause. I also tried creating a single index on this column but nothing really works.
MySQL can use keys for sorting instead of sorting the result after fetching the data, but only if several conditions are met.
You can see a list of these conditions here: http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html
In your case, I think that the multiple JOINs prevent the quick sorting. One of the mentioned cases in which MySQL can't use an index for sorting is:
You are joining many tables, and the
columns in the ORDER BY are not all
from the first nonconstant table that
is used to retrieve rows. (This is the
first table in the EXPLAIN output that
does not have a const join type.)
I am not sure if there is a way around it. It depends on the tables structure and the actual query.
To get more help, try posting the explain output of the ordered query.
I would first try adding compound indices on:
Table a
(col2, col1)
Table b
(col4, col1)
and a simple index on
Table h
(col5)