sunsa428
sunsa428

Reputation: 147

MySql: Multiple Left Joins makes query really slow

Running the following query takes forever. All the tables contain more than 200,000 records. Indexes exist on all the columns in the joining statements:

Select files.filename,
coalesce(temp_decmetadata.glare_roadGlare, 0) as glare_roadGlare,
coalesce(temp_decmetadata.glare_sun, 0) as glare_sun,
coalesce(temp_decmetadata.spray_heavySpray, 0) as spray_heavySpray,
coalesce(temp_kafaspdobjectdata.contrast_wellVisible, 0) as contrast_wellVisible,
coalesce(temp_kafaspdobjectdata.roadSafety_zebraCrossing, 0) as roadSafety_zebraCrossing,
coalesce(temp_visionmetadata.roadUser_bicycle, 0) as roadUser_bicycle,
coalesce(temp_visionmetadata.roadUser_car, 0) as roadUser_car,
coalesce(temp_visionmetadata.roadUser_pedestrian, 0) as roadUser_pedestrian
from files
left join 
(
 Select id,
 count(case when glare like '%roadGlare%' then 1 end) as glare_roadGlare,
 count(case when glare like '%sun%' then 1 end) as glare_sun,
 count(case when spray like '%heavySpray%' then 1 end) as spray_heavySpray
 from decmetadata
 group by id 
) temp_decmetadata on temp_decmetadata.id = files.id 
left join 
(
 Select id,
 count(case when contrast like '%wellVisible%' then 1 end) as contrast_wellVisible,
 count(case when roadSafety like '%zebraCrossing%' then 1 end) as roadSafety_zebraCrossing
 from kafaspdobjectdata
 group by id 
) temp_kafaspdobjectdata on temp_kafaspdobjectdata.id = files.id 
left join 
(
 Select id,
 count(case when roadUser like '%bicycle%' then 1 end) as roadUser_bicycle,
 count(case when roadUser like '%car%' then 1 end) as roadUser_car,
 count(case when roadUser like '%pedestrian%' then 1 end) as roadUser_pedestrian
 from visionmetadata
 group by id 
) temp_visionmetadata on temp_visionmetadata.id = files.id 

Result of "Explain Select..." is attached below:

Explain Select...

Upvotes: 2

Views: 628

Answers (2)

Gerardo Lima
Gerardo Lima

Reputation: 6703

I'm not a MySQL specialist, but you can sure improve the sub-queries by moving the JOIN condition to the inner WHERE conditions and filtering the rows to only those that satisfies any CASE condition, this will decrease the number of rows that must be evaluated by the LIKE operator (this is the most expensive operation in this query). The following script should give you the idea:

...
CROSS JOIN  (
  SELECT
  SUM(CASE WHEN glare LIKE '%roadGlare%' THEN 1 ELSE 0 END) AS glare_roadGlare,
  SUM(CASE WHEN glare LIKE '%sun%' THEN 1 ELSE 0 END) AS glare_sun,
  SUM(CASE WHEN spray LIKE '%heavySpray%' THEN 1 ELSE 0 END) AS spray_heavySpray
  FROM decmetadata
  WHERE ( id = files.id ) -- benefits from an index over DECMETADATA.ID
    AND ( 1=2
      OR glare LIKE '%roadGlare%'
      OR glare LIKE '%sun%'
      OR spray LIKE '%heavySpray%'
    )
) temp_decmetadata
...

Upvotes: 1

D'Arcy Rittich
D'Arcy Rittich

Reputation: 171411

Your query is well-structured. The issue is all of the like '%xxx%' queries. Indexes will not help those clauses when you are substring matching like that.

Try using full text search instead.

Upvotes: 0

Related Questions