Slow SQL join on 5000 rows - mysql

I have ran into a problem when I tried to check if there was a difference in the results between different tests. The inner select statement returns around 5000 rows but the join doesn't finish in one minute. I expect the output to be around 10 rows. Any reason that the join is so slow?
select * from(
select *
from R inner join C
on R.i = C.j
where C.j in (2343,3423,4222,1124,2344)
) AS A,(
select *
from R inner join C
on R.i = C.j
where C.j in (2343,3423,4222,1124,2344)
) AS B
where A.x = B.x and
A.y = B.y and
A.result <> B.result

I think you can do what you want with aggregation:
select x, y, group_concat(distinct result) as results
from R inner join
C
on R.i = C.j
where C.j in (2343, 3423, 4222, 1124, 2344)
group by x, y
having count(distinct result) > 1;
For this query, an index on C(j) and R(i) would be very helpful. I would add x and y to the appropriate index as well, but I don't know which table they are combing from.

Related

how to eliminate union for better performance in mysql

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).

How can I optimize this mysql query

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").

How to select distinct max value from multiple join table MySQL

This is my current query for selecting data:
select a.No_Registrasi, a.Nama_CTKI, b.Nama_Negara, c.ID_Rad, d.ID_Lab
FROM tb_registrasi a
JOIN tb_negara_tujuan b
ON a.ID_Negara = b.ID_Negara
JOIN tb_radiologi c
ON a.No_Registrasi = c.No_Registrasi
JOIN tb_laboratorium d
ON a.No_Registrasi = d.No_Registrasi
And here's the result:
How do i distinct those ID_Rad and ID_Lab and I need the max value from each ID_Rad and ID_Lab so it will be like this:
Use GROUP BY and MAX, try this;)
select a.No_Registrasi, a.Nama_CTKI, b.Nama_Negara, CONCAT('RA-', MAX(substring(c.ID_Rad, 4) + 0)) AS ID_Rad, CONCAT('Lab-',MAX(substring(d.ID_Lab, 5) + 0)) AS Id_Lab
FROM tb_registrasi a
JOIN tb_negara_tujuan b
ON a.ID_Negara = b.ID_Negara
JOIN tb_radiologi c
ON a.No_Registrasi = c.No_Registrasi
JOIN tb_laboratorium d
ON a.No_Registrasi = d.No_Registrasi
GROUP BY a.No_Registrasi, a.Nama_CTKI, b.Nama_Negara

MySQL UNION where clause condition from the first select

How can union two selections of the same tables but the second select condition depends on the first select attribute. Here is my query
SELECT *
FROM tbl_preference_header h
LEFT JOIN tbl_preference_detail d
OJ h.id = d.superid
WHERE h.type = 'CP'
UNION
SELECT *
FROM tbl_preference_header h2
LEFT JOIN tbl_preference_detail d2
ON h2.id = d2.superid
WHERE h2.type = 'GP' AND d2.cat3code NOT IN (d.cat3code)
What I want is in the second select statement it will not contain all the cat3code from first select statement. There is error in my query d is not recognized in the second select statement.
How can I accomplish this ? What another method can I use other than union ?
You won't be able to reference the original query directly, but you could bring the original query into a subquery as follows:
SELECT * FROM tbl_preference_header h left join tbl_preference_detail d on h.id = d.superid where type = 'CP'
union
select *
from
tbl_preference_header h2
left join tbl_preference_detail d2 on h2.id = d2.superid
where type = 'GP' and d2.cat3code not in (
select d.cat3code
from
tbl_preference_header h
left join tbl_preference_detail d on h.id = d.superid
where type = 'CP'
)
It is a bit hard to figure out exactly what you want. If I assume that type is part of tbl_preference_detail, then your query is equivalent to:
SELECT *
FROM tbl_preference_header h left join
tbl_preference_detail d
on h.id = d.superid
WHERE d.type = 'CP' or
(d.type = 'GP' and
not exists (select 1
from tbl_preference_detail d2
where d2.cat3code = d.cat3code and
d2.type = 'CP'
)
)

Separating out a subquery into its own SELECT statement

I'm working through some old code (not mine) and I need to optimise the following query because it is taking a long time to complete. My guess is the subquery is causing it
UPDATE topic a, cycle c
SET a.cycleId = c.id
WHERE a.id = 1
AND ((c.year * 100) + c.sequence) = (
SELECT MIN((`year` * 100) + sequence)
FROM cycle c2
WHERE c2.groupId = a.groupId)
I was thinking of selecting the cycleId (c.id) in a separate query before the update statement but I am having problems separating it. So far I have the following but I haven't accounted for the (c.year * 100) + c.sequence) and have to be honest I'm not sure what that is doing!
SELECT c.id
FROM cycle c
LEFT JOIN topic a ON c.groupId = a.groupId
WHERE a.id = 1;
This is my workaround for time being. Get the result from:
SELECT MIN((`year` * 100) + sequence)
FROM cycle c
INNER JOIN topic a ON c.groupId = a.groupId
WHERE a.id = 1;
and use in the main query:
UPDATE topic a, cycle c
SET a.cycleId = c.id
WHERE a.id = 1
AND ((c.year * 100) + c.sequence) = [result]