Query crashes phpMyadmin (very slow)

Hi Guys!

I have a query that is very very slow to the point where it doesn’t even load in phpMyadmin. The problem seems to relate to the users_job_types table (it has 33,000 entries). When I remove the left join on the users_job_types it loads in 0.33 seconds.

Any ideas what may be causing it to be so slow? Any idea how to fix this?


select 
	users.title, 
    users.first_name, 
    users.last_name, 
    users.gender, 
    users.city, 
    users.county, 
    users.cv_text, 
    users.signup_date, 
    users_profile.*, 
    o.occupation, j.job_type 
from users 
	inner join users_profile on users_profile.userid = users.id 
    left outer join 
    	( select user_id, group_concat(occupations.occupation SEPARATOR ', ') as occupation from users_occupations left join occupations on occupations.id = users_occupations.occupation group by user_id ) as o on o.user_id = users.id 
    left outer join 
    	( select user_id, group_concat(users_job_types.job_type SEPARATOR ', ') as job_type from users_job_types left join job_types on job_types.id = users_job_types.job_type group by user_id ) as j on j.user_id = users.id 
where users.status='1' 
group by users.id 
order by users.signup_date desc

do an EXPLAIN please

id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found
1 PRIMARY users_profile ALL NULL NULL NULL NULL 11076 Using temporary; Using filesort
1 PRIMARY users eq_ref PRIMARY PRIMARY 4 skilledp_jbs.users_profile.userid 1 Using where
1 PRIMARY <derived3> ALL NULL NULL NULL NULL 11076
3 DERIVED users_job_types ALL NULL NULL NULL NULL 33228 Using filesort
3 DERIVED job_types eq_ref PRIMARY PRIMARY 2 skilledp_jbs.users_job_types.job_type 1 Using index
2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table


select 
    user_id
  , group_concat(users_job_types.job_type SEPARATOR ', ') as job_type 
from users_job_types 
left join job_types 
on job_types.id = users_job_types.job_type 
group by user_id

I have a question about this part of your query: why are you (left) joining the job_types table? You aren’t selecting any column from it, are you?

No there is no column being selected. What do you propose?

How about this:


select 
    user_id
  , group_concat(users_job_types.job_type SEPARATOR ', ') as job_type 
from users_job_types 
group by user_id

Ok, but that still doesn’t resolve the slow query. It’s still crashing phpMyadmin.


select 
    users.title, 
    users.first_name, 
    users.last_name, 
    users.gender, 
    users.city, 
    users.county, 
    users.cv_text, 
    users.signup_date, 
    users_profile.*, 
    group_concat(o.occupation SEPARATOR ', ') as occupation, 
    group_concat(j.job_type SEPARATOR ', ') as job_type 
from users 
inner join users_profile 
on users_profile.userid = users.id 
left outer join users_occupations as uo 
on uo.user_id = users.id 
left join occupations  as o
on o.id = uo.occupation
left outer join users_job_types  as j 
on j.user_id = users.id 
where users.status='1' 
group by users.id 
order by users.signup_date desc  

How about this?
And make sure you have all the right indexes.

Thanks, that one didn’t crash my phpMyadmin, so we are getting somewhere! :slight_smile: Thanks so much

How do I determine which fields should have indexes?

by studying the EXPLAIN

Thanks guys. I seem to have resolved the slow issue, now the only problem is that the concat is pulling the information multiple times. Below is the query i’m using - any ideas what could be wrong with it?


SELECT users.title, users.first_name, users.last_name, users.gender, users.city, users.county, users.cv_text, users.signup_date, users_profile . * , group_concat( o.occupation
SEPARATOR ', ' ) AS occupation, group_concat( j.job_type
SEPARATOR ', ' ) AS job_type, group_concat( ks.key_skill
SEPARATOR ', ' ) AS key_skill
FROM users
INNER JOIN users_profile ON users_profile.userid = users.id
LEFT OUTER JOIN users_occupations AS uo ON uo.user_id = users.id
LEFT OUTER JOIN users_job_types AS j ON j.user_id = users.id
LEFT OUTER JOIN users_keyskills AS ks ON ks.user_id = users.id
LEFT JOIN occupations AS o ON o.id = uo.occupation
WHERE users.status = '1'
GROUP BY users.id
ORDER BY users.signup_date DESC

the problem is, you are seeing cross join effects for each user

if a given user has 2 occupations, 3 job types, and 4 skills, then your joins are going to produce 24 rows

to get around this problem, do the counting in subqueries…

SELECT users.title
     , users.first_name
     , users.last_name
     , users.gender
     , users.city
     , users.county
     , users.cv_text
     , users.signup_date
     , users_profile.* 
     , uo1.occupation
     , j1.job_type
     , ks1.key_skill 
  FROM users 
INNER 
  JOIN users_profile 
    ON users_profile.userid = users.id 
LEFT OUTER 
  JOIN ( SELECT user_id
              , GROUP_CONCAT( o.occupation SEPARATOR ', ' ) AS occupation
           FROM users_occupations AS uo
         INNER
           JOIN occupations AS o
             ON o.id = uo.occupation  
         GROUP
             BY user_id ) AS uo1 
    ON uo1.user_id = users.id 
LEFT OUTER 
  JOIN ( SELECT user_id
              , GROUP_CONCAT( j.job_type SEPARATOR ', ' ) AS job_type
           FROM users_job_types AS j
         GROUP
             BY user_id ) AS j1 
    ON j1.user_id = users.id 
LEFT OUTER 
  JOIN ( SELECT user_id
              , GROUP_CONCAT( ks.key_skill SEPARATOR ', ' ) AS key_skill 
           FROM users_keyskills AS ks
         GROUP
             BY user_id ) AS ks1
    ON ks1.user_id = users.id 
 WHERE users.status = '1' 
ORDER 
    BY users.signup_date DESC  

Right, I get it. So it’s getting a row for each occupation, job type and skill and returning them all.

Ok, I just tried that updated query, only problem is…it’s reverted back to it’s sluggish ways and takes ages (im actually still waiting for it to complete the query as I write this post).

Would it help if I posted the table structure?

Thanks for your help.

do an EXPLAIN please

id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY users_profile ALL userid NULL NULL NULL 11078 Using temporary; Using filesort
1 PRIMARY users eq_ref PRIMARY PRIMARY 4 skilledp_jbs.users_profile.userid 1 Using where
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2
1 PRIMARY <derived3> ALL NULL NULL NULL NULL 11078
1 PRIMARY <derived4> ALL NULL NULL NULL NULL 1
4 DERIVED ks ALL NULL NULL NULL NULL 2 Using filesort
3 DERIVED j ALL NULL NULL NULL NULL 33233 Using filesort
2 DERIVED uo ALL NULL NULL NULL NULL 4 Using filesort
2 DERIVED o eq_ref PRIMARY PRIMARY 4 skilledp_jbs.uo.occupation 1

yes :slight_smile:

please use SHOW CREATE TABLE because this will also reveal your indexes


CREATE TABLE `users` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `title` varchar(100) NOT NULL,
 `first_name` varchar(100) NOT NULL,
 `last_name` varchar(100) NOT NULL,
 `gender` varchar(30) NOT NULL,
 `dob` date DEFAULT NULL,
 `address_1` varchar(100) NOT NULL,
 `address_2` varchar(100) DEFAULT NULL,
 `city` varchar(100) NOT NULL,
 `county` varchar(100) NOT NULL,
 `postcode` varchar(20) NOT NULL,
 `telephone` varchar(30) NOT NULL,
 `mobile` varchar(30) DEFAULT NULL,
 `email` varchar(255) NOT NULL,
 `username` varchar(100) NOT NULL,
 `password` varchar(32) NOT NULL,
 `salt` varchar(10) NOT NULL,
 `cv` varchar(255) DEFAULT NULL,
 `cv_text` text,
 `cv_date` datetime DEFAULT NULL,
 `cv_hide` enum('0','1') DEFAULT NULL,
 `signup_date` datetime NOT NULL,
 `ip` varchar(30) DEFAULT NULL,
 `status` enum('0','1') DEFAULT '1',
 `lastlogin` datetime DEFAULT NULL,
 `thislogin` datetime DEFAULT NULL,
 `token` varchar(32) DEFAULT NULL,
 `activation` varchar(32) DEFAULT NULL,
 `account_expiry` datetime DEFAULT NULL,
 `skilled_ref` varchar(20) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=12080 DEFAULT CHARSET=latin1


CREATE TABLE `users_job_types` (
 `user_id` int(6) NOT NULL,
 `job_type` int(6) NOT NULL,
 KEY `job_type` (`job_type`),
 KEY `user_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1


CREATE TABLE `users_keyskills` (
 `user_id` int(6) NOT NULL,
 `key_skill` int(6) NOT NULL,
 KEY `user_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1


CREATE TABLE `users_occupations` (
 `user_id` int(6) NOT NULL,
 `occupation` int(6) NOT NULL,
 KEY `user_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

you do have indexes, but they aren’t being used…

personally, i would use compound indexes, and i would get them via PRIMARY KEY

so instead of this –

CREATE TABLE `users_job_types` (
 `user_id` int(6) NOT NULL,
 `job_type` int(6) NOT NULL,
 KEY `job_type` (`job_type`),
 KEY `user_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

i would do this –

CREATE TABLE users_job_types 
( user_id INTEGER NOT NULL
, job_type INTEGER NOT NULL
, PRIMARY KEY ( user_id , job_type )
, INDEX job_type_user ( job_type , user_id )
) ENGINE=MyISAM DEFAULT CHARSET=latin1

try this, and similar changes on your other many-to-many tables

i’m not sure these changes will actually help this particular query, though

Thanks, I tried your suggestion r937 - but the query is still not loading. I have no clue why this is happenning :frowning:

Do you think I should revert back to the way I had it before - without subquery? It was loading then, but just loading the information multiple times. Or is subquery the only way out?

Thanks.

Still having issues with this guys…any ideas?

Thanks in advance.