How to improve a MYSQL Query with multiple JOINS - mysql
I have 2 search pages that are super slow in getting results.
I did not write the queries, but I know they are not written in an efficient way; I just do not have enough practice in MYSQL to figure out how to make them more efficient.
What should I do to improve the following query?
SELECT DISTINCT m.id AS memberID , m.login , m.age , p.gender
, p.name AS header , p.id AS profileID , p.city , p.state , p.lastlogin
, o.login AS online , c.name AS country , ph.filename_1 AS pic
FROM dt_members AS m
INNER JOIN dt_profile_approved AS p ON m.id=p.member_id
LEFT JOIN dt_privacy AS pv ON m.id=pv.member_id
INNER JOIN dt_countries AS c ON c.id=p.country
LEFT JOIN dt_photos AS ph ON m.id=ph.member_id
LEFT JOIN dt_usersonline AS o ON m.login=o.login
WHERE p.status=1 AND (pv.unsearchable IS NULL OR pv.unsearchable='')
AND p.gender='Female' AND m.age BETWEEN 25 AND 40
ORDER BY p.lastlogin DESC
LIMIT 0, 21;
it is terribly slow and showing 500 error often.
Output of explain:
Show Create Table:
CREATE TABLE `dt_members` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`login` varchar(25) DEFAULT NULL,
`pswd` varchar(20) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`name` varchar(40) DEFAULT NULL,
`gender` varchar(10) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`country` varchar(255) DEFAULT NULL,
`looking_for` varchar(255) DEFAULT NULL,
`ip_addr` varchar(15) DEFAULT NULL,
`reg_date` int(11) DEFAULT NULL,
`status` int(11) DEFAULT NULL,
`system_status` int(11) DEFAULT '0',
`system_status_end` int(11) DEFAULT NULL,
`unlimited` int(11) DEFAULT '0',
`unlimited_end` int(11) DEFAULT NULL,
`matchfinder` int(1) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `login` (`login`),
KEY `pswd` (`pswd`),
KEY `email` (`email`),
KEY `name` (`name`),
KEY `gender` (`gender`),
KEY `age` (`age`),
KEY `country` (`country`),
KEY `looking_for` (`looking_for`),
KEY `ip_addr` (`ip_addr`),
KEY `reg_date` (`reg_date`),
KEY `status` (`status`),
KEY `system_status` (`system_status`),
KEY `system_status_end` (`system_status_end`),
KEY `unlimited` (`unlimited`),
KEY `unlimited_end` (`unlimited_end`),
KEY `matchfinder` (`matchfinder`)
) ENGINE=MyISAM AUTO_INCREMENT=29150 DEFAULT CHARSET=latin1
CREATE TABLE `dt_profile` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`member_id` int(11) DEFAULT NULL,
`country` int(11) DEFAULT NULL,
`state` varchar(255) DEFAULT NULL,
`city` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`gender` varchar(20) DEFAULT NULL,
`birth_day` int(11) DEFAULT NULL,
`birth_month` varchar(6) DEFAULT NULL,
`birth_year` int(11) DEFAULT NULL,
`marital_status` int(11) DEFAULT NULL,
`children` int(11) DEFAULT NULL,
`drinking` int(11) DEFAULT NULL,
`smoking` int(11) DEFAULT NULL,
`food` int(11) DEFAULT NULL,
`eye_color` int(11) DEFAULT NULL,
`hair_color` int(11) DEFAULT NULL,
`height` int(11) DEFAULT NULL,
`body_type` int(11) DEFAULT NULL,
`race` int(11) DEFAULT NULL,
`religion` int(11) DEFAULT NULL,
`occupation` int(11) DEFAULT NULL,
`education` int(11) DEFAULT NULL,
`lang_1` int(11) DEFAULT NULL,
`lang_1_rate` int(11) DEFAULT NULL,
`lang_2` int(11) DEFAULT NULL,
`lang_2_rate` int(11) DEFAULT NULL,
`lang_3` int(11) DEFAULT NULL,
`lang_3_rate` int(11) DEFAULT NULL,
`lang_4` int(11) DEFAULT NULL,
`lang_4_rate` int(11) DEFAULT NULL,
`looking_for` varchar(10) DEFAULT NULL,
`age_from` int(11) DEFAULT NULL,
`age_to` int(11) DEFAULT NULL,
`general_info` text,
`appearance_info` text,
`looking_for_info` text,
`status` int(11) DEFAULT NULL,
`finish_status` int(11) DEFAULT NULL,
`not_newbie` int(11) DEFAULT NULL,
`lastlogin` int(10) NOT NULL DEFAULT '0',
`zipcode` varchar(5) NOT NULL DEFAULT '',
`longitude` double DEFAULT NULL,
`latitude` double DEFAULT NULL,
`photo_pass` varchar(25) NOT NULL DEFAULT '',
`view_count` int(11) DEFAULT '0',
`wants_kids` int(11) DEFAULT NULL,
`kids_okay` int(11) DEFAULT NULL,
`relocate_domestic` int(11) DEFAULT NULL,
`relocate_international` int(11) DEFAULT NULL,
`pioneer` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `member_id` (`member_id`),
KEY `country` (`country`),
KEY `state` (`state`),
KEY `city` (`city`),
KEY `email` (`email`),
KEY `name` (`name`),
KEY `gender` (`gender`),
KEY `birth_day` (`birth_day`),
KEY `birth_month` (`birth_month`),
KEY `birth_year` (`birth_year`),
KEY `marital_status` (`marital_status`),
KEY `children` (`children`),
KEY `drinking` (`drinking`),
KEY `smoking` (`smoking`),
KEY `food` (`food`),
KEY `eye_color` (`eye_color`),
KEY `hair_color` (`hair_color`),
KEY `height` (`height`),
KEY `body_type` (`body_type`),
KEY `race` (`race`),
KEY `religion` (`religion`),
KEY `occupation` (`occupation`),
KEY `education` (`education`),
KEY `lang_1` (`lang_1`),
KEY `lang_1_rate` (`lang_1_rate`),
KEY `lang_2` (`lang_2`),
KEY `lang_2_rate` (`lang_2_rate`),
KEY `lang_3` (`lang_3`),
KEY `lang_3_rate` (`lang_3_rate`),
KEY `lang_4` (`lang_4`),
KEY `lang_4_rate` (`lang_4_rate`),
KEY `looking_for` (`looking_for`),
KEY `age_from` (`age_from`),
KEY `age_to` (`age_to`),
KEY `status` (`status`),
KEY `finish_status` (`finish_status`),
KEY `not_newbie` (`not_newbie`),
KEY `lastlogin` (`lastlogin`),
KEY `zipcode` (`zipcode`),
KEY `longitude` (`longitude`),
KEY `latitude` (`latitude`),
KEY `photo_pass` (`photo_pass`),
KEY `view_count` (`view_count`),
KEY `wants_kids` (`wants_kids`),
KEY `kids_okay` (`kids_okay`),
KEY `relocate_domestic` (`relocate_domestic`),
KEY `relocate_international` (`relocate_international`),
KEY `pioneer` (`pioneer`)
) ENGINE=MyISAM AUTO_INCREMENT=18389 DEFAULT CHARSET=latin1
CREATE TABLE `dt_privacy` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`member_id` int(11) DEFAULT NULL,
`online_yn` char(1) DEFAULT NULL,
`vkiss_yn` char(1) DEFAULT NULL,
`profiles_yn` char(1) DEFAULT NULL,
`IM_yn` char(1) DEFAULT NULL,
`featured_yn` char(1) DEFAULT NULL,
`HL_messaged_yn` char(1) DEFAULT NULL,
`HL_im_yn` char(1) DEFAULT NULL,
`HL_viewed_yn` char(1) DEFAULT NULL,
`HL_kissed_yn` char(1) DEFAULT NULL,
`HL_favorite_yn` char(1) DEFAULT NULL,
`unsearchable` char(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `member_id` (`member_id`),
KEY `online_yn` (`online_yn`),
KEY `vkiss_yn` (`vkiss_yn`),
KEY `profiles_yn` (`profiles_yn`),
KEY `IM_yn` (`IM_yn`),
KEY `featured_yn` (`featured_yn`),
KEY `HL_messaged_yn` (`HL_messaged_yn`),
KEY `HL_im_yn` (`HL_im_yn`),
KEY `HL_viewed_yn` (`HL_viewed_yn`),
KEY `HL_kissed_yn` (`HL_kissed_yn`),
KEY `HL_favorite_yn` (`HL_favorite_yn`),
KEY `unsearchable` (`unsearchable`)
) ENGINE=MyISAM AUTO_INCREMENT=26305 DEFAULT CHARSET=latin1
CREATE TABLE `dt_countries` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=MyISAM AUTO_INCREMENT=226 DEFAULT CHARSET=latin1
CREATE TABLE `dt_photos` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`member_id` varchar(255) DEFAULT NULL,
`filename_1` varchar(255) DEFAULT NULL,
`filename_2` varchar(255) DEFAULT NULL,
`filename_3` varchar(255) NOT NULL DEFAULT '',
`filename_4` varchar(255) NOT NULL DEFAULT '',
`filename_5` varchar(255) NOT NULL DEFAULT '',
`filename_6` varchar(255) NOT NULL DEFAULT '',
`filename_7` varchar(255) NOT NULL DEFAULT '',
`filename_8` varchar(255) NOT NULL DEFAULT '',
`filename_9` varchar(255) NOT NULL DEFAULT '',
`filename_10` varchar(255) NOT NULL DEFAULT '',
`filename_11` varchar(255) NOT NULL DEFAULT '',
`filename_12` varchar(255) NOT NULL DEFAULT '',
`filename_13` varchar(255) NOT NULL DEFAULT '',
`filename_14` varchar(255) NOT NULL DEFAULT '',
`filename_15` varchar(255) NOT NULL DEFAULT '',
`filename_16` varchar(255) NOT NULL DEFAULT '',
`filename_17` varchar(255) NOT NULL DEFAULT '',
`filename_18` varchar(255) NOT NULL DEFAULT '',
`filename_19` varchar(255) NOT NULL DEFAULT '',
`filename_20` varchar(255) NOT NULL DEFAULT '',
`private_1` tinyint(1) NOT NULL DEFAULT '0',
`private_2` tinyint(1) NOT NULL DEFAULT '0',
`private_3` tinyint(1) NOT NULL DEFAULT '0',
`private_4` tinyint(1) NOT NULL DEFAULT '0',
`private_5` tinyint(1) NOT NULL DEFAULT '0',
`private_6` tinyint(1) NOT NULL DEFAULT '0',
`private_7` tinyint(1) NOT NULL DEFAULT '0',
`private_8` tinyint(1) NOT NULL DEFAULT '0',
`private_9` tinyint(1) NOT NULL DEFAULT '0',
`private_10` tinyint(1) NOT NULL DEFAULT '0',
`private_11` tinyint(1) NOT NULL DEFAULT '0',
`private_12` tinyint(1) NOT NULL DEFAULT '0',
`private_13` tinyint(1) NOT NULL DEFAULT '0',
`private_14` tinyint(1) NOT NULL DEFAULT '0',
`private_15` tinyint(1) NOT NULL DEFAULT '0',
`private_16` tinyint(1) NOT NULL DEFAULT '0',
`private_17` tinyint(1) NOT NULL DEFAULT '0',
`private_18` tinyint(1) NOT NULL DEFAULT '0',
`private_19` tinyint(1) NOT NULL DEFAULT '0',
`private_20` tinyint(1) NOT NULL DEFAULT '0',
`password` varchar(255) NOT NULL DEFAULT '',
`description_1` varchar(255) DEFAULT NULL,
`description_2` varchar(255) DEFAULT NULL,
`description_3` varchar(255) NOT NULL DEFAULT '',
`description_4` varchar(255) NOT NULL DEFAULT '',
`description_5` varchar(255) NOT NULL DEFAULT '',
`description_6` varchar(255) NOT NULL DEFAULT '',
`description_7` varchar(255) NOT NULL DEFAULT '',
`description_8` varchar(255) NOT NULL DEFAULT '',
`description_9` varchar(255) NOT NULL DEFAULT '',
`description_10` varchar(255) NOT NULL DEFAULT '',
`description_11` varchar(255) NOT NULL DEFAULT '',
`description_12` varchar(255) NOT NULL DEFAULT '',
`description_13` varchar(255) NOT NULL DEFAULT '',
`description_14` varchar(255) NOT NULL DEFAULT '',
`description_15` varchar(255) NOT NULL DEFAULT '',
`description_16` varchar(255) NOT NULL DEFAULT '',
`description_17` varchar(255) NOT NULL DEFAULT '',
`description_18` varchar(255) NOT NULL DEFAULT '',
`description_19` varchar(255) NOT NULL DEFAULT '',
`description_20` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `filename_12` (`filename_12`),
KEY `filename_13` (`filename_13`),
KEY `filename_14` (`filename_14`),
KEY `filename_15` (`filename_15`),
KEY `filename_16` (`filename_16`),
KEY `filename_17` (`filename_17`),
KEY `filename_18` (`filename_18`),
KEY `filename_19` (`filename_19`),
KEY `filename_20` (`filename_20`),
KEY `member_id` (`member_id`),
KEY `filename_1` (`filename_1`),
KEY `filename_2` (`filename_2`),
KEY `filename_3` (`filename_3`),
KEY `filename_4` (`filename_4`),
KEY `filename_5` (`filename_5`),
KEY `filename_6` (`filename_6`),
KEY `filename_7` (`filename_7`),
KEY `filename_8` (`filename_8`),
KEY `filename_9` (`filename_9`),
KEY `filename_10` (`filename_10`),
KEY `private_1` (`private_1`),
KEY `private_2` (`private_2`),
KEY `private_3` (`private_3`),
KEY `private_4` (`private_4`),
KEY `private_5` (`private_5`),
KEY `private_6` (`private_6`),
KEY `private_7` (`private_7`),
KEY `private_8` (`private_8`),
KEY `private_9` (`private_9`),
KEY `private_10` (`private_10`),
KEY `private_11` (`private_11`),
KEY `private_12` (`private_12`),
KEY `private_13` (`private_13`),
KEY `private_14` (`private_14`),
KEY `private_15` (`private_15`),
KEY `private_16` (`private_16`),
KEY `private_17` (`private_17`),
KEY `private_18` (`private_18`),
KEY `private_19` (`private_19`),
KEY `private_20` (`private_20`),
KEY `password` (`password`),
KEY `description_1` (`description_1`),
KEY `description_2` (`description_2`),
KEY `description_3` (`description_3`),
KEY `description_4` (`description_4`),
KEY `description_5` (`description_5`),
KEY `description_6` (`description_6`),
KEY `description_7` (`description_7`),
KEY `description_8` (`description_8`),
KEY `description_9` (`description_9`),
KEY `description_10` (`description_10`),
KEY `description_11` (`description_11`),
KEY `description_12` (`description_12`),
KEY `description_13` (`description_13`),
KEY `description_14` (`description_14`),
KEY `description_15` (`description_15`),
KEY `description_16` (`description_16`),
KEY `description_17` (`description_17`),
KEY `description_18` (`description_18`),
KEY `description_19` (`description_19`),
KEY `description_20` (`description_20`),
KEY `filename_10_2` (`filename_10`),
KEY `filename_10_3` (`filename_10`)
) ENGINE=MyISAM AUTO_INCREMENT=11174 DEFAULT CHARSET=latin1
CREATE TABLE `dt_usersonline` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`timestamp` int(15) NOT NULL DEFAULT '0',
`ip` varchar(40) NOT NULL DEFAULT '',
`login` varchar(25) NOT NULL DEFAULT '',
`userid` int(10) NOT NULL DEFAULT '0',
`session_id` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `id_2` (`id`),
KEY `timestamp` (`timestamp`),
KEY `ip` (`ip`),
KEY `login` (`login`),
KEY `userid` (`userid`),
KEY `session_id` (`session_id`)
) ENGINE=MyISAM AUTO_INCREMENT=4424348 DEFAULT CHARSET=latin1
CREATE TABLE `dt_members` (
`id` int(11) NOT NULL AUTO_INCREMENT,...
CREATE TABLE `dt_photos` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`member_id` varchar(255) DEFAULT NULL,..
You are joining on your query as:
LEFT JOIN dt_photos AS ph ON m.id=ph.member_id
Notice how every other time you join on member_id to m.id the column looks like member_id int(11) DEFAULT NULL. Your join criteria should be on the same data type, otherwise it looks like it is doing a full table scan. It's not using the key because it believes that it has to scan the varchar field rather than utilizing indexes for on clause.
Try Altering column member_id to that of m.id from dt_members
It is interesting to note, had you actually tried to create a foreign key constraint, it would not have allowed you to because of the mismatched data types...
Warning: MYISAM table will be locked during the duration of the later table process.
Try moving where conditions into the corresponding join condition:
SELECT DISTINCT m.id AS memberID , m.login , m.age , p.gender
, p.name AS header , p.id AS profileID , p.city , p.state , p.lastlogin
, o.login AS online , c.name AS country , ph.filename_1 AS pic
FROM dt_members AS m
INNER JOIN dt_profile_approved AS p ON m.id=p.member_id
AND p.status=1 AND p.gender='Female' -- Moved from WHERE clause
LEFT JOIN dt_privacy AS pv ON m.id=pv.member_id
AND (pv.unsearchable IS NULL OR pv.unsearchable='') -- Moved from WHERE clause
INNER JOIN dt_countries AS c ON c.id=p.country
LEFT JOIN dt_photos AS ph ON m.id=ph.member_id
LEFT JOIN dt_usersonline AS o ON m.login=o.login
WHERE m.age BETWEEN 25 AND 40
ORDER BY p.lastlogin DESC
LIMIT 0, 21;
While where conditions are made after all joins, join conditions are evaluated during the join, so vast numbers of unnecessary joins can be avoided early.
Although theoretically the query optimizer should do this for you, I have found the mysql can be particularly dense in this regard.
It looks like most of the selectivity on your query is on your dt_profile_approved table. Try creating a compound index on (status, gender, lastlogin)
This should allow an index-only selection and ordering.
Your query does the notorious SELECT a lot ORDER BY something DESC LIMIT tinynumber pattern. This is expensive. Try a deferred join. Start by getting the interesting items from your dt_profile_approved table, like this:
SELECT member_id, lastlogin
FROM dt_profile_approved
WHERE status=1
AND gender='Female'
ORDER BY lastlogin DESC
This subquery can be optimized very cleanly with a compound index on (status, gender, lastlogin, member_id). That's called a covering index. It has a great benefit: no extra sorting is required, because the index is already sorted.
Based on the exact query you showed us, the order in the index of gender and status doesn't matter. But I guess you have another query that looks for males, and you may have one that omits that. So status is likely to be the more selective field across all your queries. (Guessing.)
Then, join that subquery into the rest of your query... that will look something like this.
SELECT DISTINCT
m.id AS memberID , m.login , m.age,
p.gender. p.name AS header , p.id AS profileID ,
p.city , p.state , p.lastlogin,
o.login AS online ,
c.name AS country , ph.filename_1 AS pic
FROM (
SELECT member_id, lastlogin
FROM dt_profile_approved
WHERE status=1
AND gender='Female'
ORDER BY lastlogin DESC
) AS sel
INNER JOIN dt_profile_approved AS p ON sel.member_id = p.member_id
INNER JOIN dt_members AS m ON m.id=sel.member_id
LEFT JOIN dt_privacy AS pv ON m.id=pv.member_id
INNER JOIN dt_countries AS c ON c.id=p.country
LEFT JOIN dt_photos AS ph ON m.id=ph.member_id
LEFT JOIN dt_usersonline AS o ON m.login=o.login
WHERE (pv.unsearchable IS NULL OR pv.unsearchable='')
AND m.age BETWEEN 25 AND 40
ORDER BY sel.lastlogin DESC
LIMIT 0, 21;
If this works, it will be because it can limit the labor of sorting using the index.
Related
"1062 Duplicate entry" on SELECT
I've got a SELECT query that's returning the following error: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'user_id-name email#address.com--2018-11-04 01:24:38' for key '' (I replaced the user_id, name and email for privacy) SELECT users.user_id, users.fullname, users.email, users.phone_formatted, users.date_created, MAX(cards.card_id) AS latest_card_id, MAX(cards.date_created) AS latest_date_card, MAX(punches.date_created) AS date_lastvisited FROM users INNER JOIN cards ON cards.user_id = users.user_id INNER JOIN punches ON punches.card_id = cards.card_id WHERE punches.business_id=1626 GROUP BY users.user_id, users.fullname, users.email, users.phone_formatted, users.date_created ORDER BY users.fullname; Here are the table definitions for cards, punches and users: CREATE TABLE `cards` ( `card_id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) DEFAULT NULL, `business_id` int(11) DEFAULT NULL, `printjob_id` int(11) DEFAULT NULL, `temp` varchar(256) DEFAULT NULL, `active` tinyint(1) NOT NULL DEFAULT '1', `whitelabel_id` int(11) NOT NULL DEFAULT '0', `date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`card_id`), KEY `printjob_id` (`printjob_id`), KEY `active` (`active`), KEY `user_id` (`user_id`), KEY `business_id` (`business_id`) ) ENGINE=InnoDB AUTO_INCREMENT=576475 DEFAULT CHARSET=latin1; CREATE TABLE `punches` ( `punch_id` int(11) NOT NULL AUTO_INCREMENT, `punch_count` int(11) unsigned NOT NULL DEFAULT '1', `employeebonus` tinyint(1) NOT NULL DEFAULT '0', `details` text, `card_id` int(11) DEFAULT NULL, `behaviour` set('basicpunch','employeebonus','visitsregularly','broughtfriend','mytreat','firstcustomer','dailyrepeater','visitslocations','facebookshare','mostfrequent','longabsence','registerer','employeepromoter','luckiest','enroll','opportunist') NOT NULL DEFAULT 'basicpunch', `location_id` int(11) DEFAULT NULL, `business_id` int(11) DEFAULT NULL, `employee_id` int(11) DEFAULT NULL, `v1` float DEFAULT NULL, `eventcounter` smallint(5) unsigned NOT NULL DEFAULT '0', `date_local` timestamp NULL DEFAULT CURRENT_TIMESTAMP, `date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`punch_id`), KEY `business_id` (`business_id`), KEY `employee_id` (`employee_id`), KEY `card_id` (`card_id`), KEY `date_created` (`date_created`), KEY `behaviour_id` (`behaviour`), KEY `location_id` (`location_id`), KEY `employeebonus` (`employeebonus`), KEY `punch_count` (`punch_count`) ) ENGINE=InnoDB AUTO_INCREMENT=807402 DEFAULT CHARSET=latin1; CREATE TABLE `users` ( `user_id` int(11) NOT NULL AUTO_INCREMENT, `fullname` varchar(60) DEFAULT NULL, `email` varchar(50) NOT NULL, `undeliverable` tinyint(4) DEFAULT '0', `phone_formatted` varchar(25) DEFAULT NULL, `phone_unformatted` varchar(15) DEFAULT NULL, `password_hash` char(64) DEFAULT NULL, `password_salt` char(6) DEFAULT NULL, `reset_hash` binary(32) DEFAULT NULL, `date_reset` datetime DEFAULT NULL, `stripecustomer_id` int(11) DEFAULT NULL, `stripe_customer_id` varchar(40) DEFAULT NULL, `stripe_customer_access_id` varchar(40) DEFAULT NULL, `problemwithpayment` tinyint(1) NOT NULL DEFAULT '0', `enterprisemanager_whitelabel_id` int(11) NOT NULL DEFAULT '0', `god` tinyint(1) NOT NULL DEFAULT '0', `date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`user_id`), KEY `email` (`email`), KEY `phone_unformatted` (`phone_unformatted`), KEY `date_reset` (`date_reset`), KEY `undeliverable` (`undeliverable`) ) ENGINE=InnoDB AUTO_INCREMENT=16809 DEFAULT CHARSET=latin1; I don't understand how I can get this error with a SELECT query. When I remove the MAX() functions, I no longer get the error.
mysql 'slow queries log' return a huge number of rows examined but explain seems ok
The sql query # Query_time: 16.536276 Lock_time: 0.000159 Rows_sent: 756 Rows_examined: 8392194 SET timestamp=1555422526; SELECT c.id AS c__id, c.company_id AS c__company_id, c.ordinary_price AS c__ordinary_price, c.nights AS c__nights, c.food_type AS c__food_type, c.period AS c__period, c.period_desc AS c__period_desc, c.extra AS c__extra, c.coupons_bought AS c__coupons_bought, c.coupon_price AS c__coupon_price, c.coordinates AS c__coordinates, c.best_price AS c__best_price, c.from_price AS c__from_price, c.end_datetime AS c__end_datetime, c.hide_clock AS c__hide_clock, c.hide_discount AS c__hide_discount, c.booking_hotel_id AS c__booking_hotel_id, c.title AS c__title, c.option_people AS c__option_people, c.option_room AS c__option_room, c.option_period AS c__option_period, c.city AS c__city, c2.id AS c2__id, c2.people AS c2__people, c2.room AS c2__room, ( SELECT c8.url AS c8__url FROM campaign_images c8 WHERE (c8.campaign_id = c.id AND c8.photo_type = 'list') ORDER BY c8.ordering ASC LIMIT 1 ) AS c__0 FROM campaign c LEFT JOIN campaign_options c2 ON c.id = c2.campaign_id AND (c2.active = 1) LEFT JOIN city_in_campaign c3 ON c.id = c3.campaign_id LEFT JOIN city c4 ON c3.city_id = c4.id LEFT JOIN company c5 ON c.company_id = c5.id LEFT JOIN campaign_in_category c6 ON c.id = c6.campaign_id LEFT JOIN campaign_in_group c7 ON c.id = c7.campaign_id WHERE c.id IN ('13308', '13281', '13265') AND (c.status IN ('published') AND c.start_datetime <= NOW() AND c.end_datetime >= NOW() AND c5.id = '2111' AND c.id != '14624' AND (c7.group_id in (1) OR c7.group_id is NULL ) ) ORDER BY c.coupon_expire_datetime ASC; create table campaign CREATE TABLE `campaign` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `company_id` int(11) DEFAULT NULL, `source_id` int(11) DEFAULT NULL, `secondary_source_id` int(11) DEFAULT NULL, `source_hotel_id` int(11) DEFAULT NULL, `booking_hotel_id` int(11) DEFAULT NULL, `booking_board_id` int(11) DEFAULT NULL, `booking_rate` varchar(100) DEFAULT NULL, `ordinary_price` decimal(9,2) NOT NULL, `best_price` tinyint(1) NOT NULL DEFAULT '0', `from_price` tinyint(1) NOT NULL DEFAULT '0', `status` varchar(10) DEFAULT 'draft', `type` varchar(20) DEFAULT 'other', `deal_status` varchar(20) DEFAULT 'in_progress', `coupon_price` decimal(9,2) NOT NULL, `cosmote_discount` decimal(5,2) DEFAULT NULL, `nights` int(11) NOT NULL DEFAULT '0', `period` varchar(255) DEFAULT NULL, `period_desc` varchar(1000) DEFAULT NULL, `hide_period` tinyint(1) NOT NULL DEFAULT '0', `food_type` varchar(100) DEFAULT NULL, `stars` varchar(100) DEFAULT NULL, `adults` tinyint(1) DEFAULT NULL, `childs` tinyint(1) DEFAULT NULL, `extra` varchar(255) DEFAULT NULL, `best_point` varchar(511) DEFAULT NULL, `extra_night_price` decimal(9,2) NOT NULL DEFAULT '0.00', `high_season_price` decimal(9,2) NOT NULL DEFAULT '0.00', `high_season_desc` varchar(500) DEFAULT NULL, `high_season_extra_night_price` decimal(9,2) NOT NULL DEFAULT '0.00', `family_packages_desc` varchar(1000) DEFAULT NULL, `coordinates` varchar(70) DEFAULT NULL, `start_datetime` datetime DEFAULT NULL, `end_datetime` datetime DEFAULT NULL, `coupon_expire_datetime` datetime DEFAULT NULL, `active` tinyint(4) NOT NULL DEFAULT '1', `city` varchar(255) DEFAULT NULL, `min_coupons` int(11) NOT NULL DEFAULT '0', `is_global` tinyint(4) NOT NULL DEFAULT '0', `hide_clock` tinyint(1) NOT NULL DEFAULT '0', `hide_discount` tinyint(1) NOT NULL DEFAULT '0', `hide_purchases` tinyint(1) NOT NULL DEFAULT '0', `booking_enabled` tinyint(1) NOT NULL DEFAULT '0', `booking_phone` varchar(50) DEFAULT NULL, `refresh` tinyint(1) NOT NULL DEFAULT '0', `installments` tinyint(1) NOT NULL DEFAULT '1', `receipt` enum('0','1') NOT NULL DEFAULT '0', `newsletters_sent` tinyint(4) NOT NULL DEFAULT '0', `max_coupons` int(11) NOT NULL DEFAULT '0', `max_coupons_per_user` int(11) DEFAULT NULL, `coupons_bought` int(11) unsigned NOT NULL DEFAULT '0', `fake_orders` int(11) DEFAULT '0', `title` varchar(255) DEFAULT NULL, `newsletter_title` varchar(500) DEFAULT NULL, `linkwise_title` varchar(500) DEFAULT NULL, `option_title` varchar(255) DEFAULT NULL, `option_title_en` varchar(255) DEFAULT NULL, `option_people` varchar(150) DEFAULT NULL, `option_room` varchar(150) DEFAULT NULL, `option_period` varchar(150) DEFAULT NULL, `name` varchar(1200) DEFAULT NULL, `description` text, `highlights` text, `coupon_instructions` text, `show_in_recent_deals` tinyint(4) NOT NULL DEFAULT '1', `youtube_video_id` varchar(100) DEFAULT NULL, `in_side` tinyint(4) NOT NULL DEFAULT '0', `family` tinyint(1) NOT NULL DEFAULT '0', `send_newsletter` tinyint(4) NOT NULL DEFAULT '1', `resend_newsletter` tinyint(4) NOT NULL DEFAULT '0', `modified_datetime` timestamp NULL DEFAULT NULL, `created_datetime` datetime NOT NULL, `ordering` int(11) unsigned DEFAULT '0', PRIMARY KEY (`id`), KEY `company_id_idx` (`company_id`), KEY `user_id_idx` (`user_id`), KEY `status_indx` (`status`), KEY `str_dt_indx` (`start_datetime`), KEY `end_dt_indx` (`end_datetime`), KEY `side_indx` (`in_side`), KEY `ord_indx` (`ordering`), KEY `global_indx` (`is_global`), KEY `act_indx` (`active`), KEY `coup_expr_index` (`coupon_expire_datetime`) ) ENGINE=InnoDB AUTO_INCREMENT=14788 DEFAULT CHARSET=utf8 create table campaign_options CREATE TABLE `campaign_options` ( `id` int(11) NOT NULL AUTO_INCREMENT, `campaign_id` int(11) NOT NULL, `coupons_bought` int(11) unsigned NOT NULL DEFAULT '0', `name` varchar(255) NOT NULL, `name_en` varchar(255) DEFAULT NULL, `people` varchar(100) DEFAULT NULL, `room` varchar(100) DEFAULT NULL, `food` varchar(100) DEFAULT NULL, `period` varchar(100) DEFAULT NULL, `coupon_price` decimal(9,2) NOT NULL, `extra_night_price` decimal(9,2) NOT NULL DEFAULT '0.00', `high_season_price` decimal(9,2) DEFAULT '0.00', `high_season_extra_night_price` decimal(9,2) NOT NULL DEFAULT '0.00', `modified_datetime` timestamp NULL DEFAULT NULL, `created_datetime` datetime NOT NULL, `main` tinyint(1) NOT NULL DEFAULT '0', `family` tinyint(1) NOT NULL DEFAULT '0', `active` tinyint(4) NOT NULL DEFAULT '1', PRIMARY KEY (`id`), KEY `campaign_id_idx` (`campaign_id`), KEY `active_indx` (`active`), KEY `family_indx` (`family`), KEY `main_indx` (`main`) ) ENGINE=InnoDB AUTO_INCREMENT=48990 DEFAULT CHARSET=utf8 create table city_in_campaign CREATE TABLE `city_in_campaign` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `campaign_id` int(11) DEFAULT NULL, `city_id` int(11) DEFAULT NULL, `ordering` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `campaign_id_idx` (`campaign_id`), KEY `city_id_idx` (`city_id`), KEY `order_indx` (`ordering`) ) ENGINE=InnoDB AUTO_INCREMENT=227176 DEFAULT CHARSET=utf8 create table city CREATE TABLE `city` ( `id` int(11) NOT NULL AUTO_INCREMENT, `country_id` int(11) DEFAULT NULL, `name` varchar(100) DEFAULT NULL, `is_active` tinyint(3) unsigned DEFAULT NULL, `modified_datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `country_id_idx` (`country_id`), KEY `is_active_indx` (`is_active`) ) ENGINE=InnoDB AUTO_INCREMENT=254 DEFAULT CHARSET=utf8 create table company CREATE TABLE `company` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `ref_id` int(11) DEFAULT NULL, `name` varchar(100) DEFAULT NULL, `description` text, `logo` varchar(255) DEFAULT NULL, `phone_number` varchar(100) DEFAULT NULL, `address` varchar(200) DEFAULT NULL, `coordinates` varchar(70) DEFAULT NULL, `email` varchar(100) DEFAULT NULL, `website` varchar(255) DEFAULT NULL, `skype_name` varchar(50) DEFAULT NULL, `icq_number` varchar(255) DEFAULT NULL, `payment_information` text, `extra1` text, `extra2` text, `extra3` text, `video` varchar(500) DEFAULT NULL, `checked` tinyint(1) NOT NULL DEFAULT '0', `ordering` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `checked_indx` (`checked`), KEY `ordering_indx` (`ordering`) ) ENGINE=InnoDB AUTO_INCREMENT=2519 DEFAULT CHARSET=utf8 create table campaign_in_category CREATE TABLE `campaign_in_category` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `campaign_id` int(11) NOT NULL, `category_id` int(11) DEFAULT NULL, `ordering` int(11) NOT NULL DEFAULT '0', `created_datetime` datetime NOT NULL, PRIMARY KEY (`id`), KEY `campaign_id_idx` (`campaign_id`), KEY `category_id_idx` (`category_id`), KEY `order_indx` (`ordering`) ) ENGINE=InnoDB AUTO_INCREMENT=457080 DEFAULT CHARSET=utf8 create table campaign_in_group CREATE TABLE `campaign_in_group` ( `id` int(11) NOT NULL AUTO_INCREMENT, `campaign_id` int(11) DEFAULT NULL, `group_id` int(11) DEFAULT NULL, `created_datetime` datetime DEFAULT NULL, `modified_datetime` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `camp_group_indx` (`campaign_id`,`group_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1175 DEFAULT CHARSET=utf8 campaign total rows: 12,657 campaign_options total rows: 43,714 city_in_campaign total rows: 15,162 city total rows: 215 company total rows: 1,756 campaign_in_category total rows: 38,817 campaign_in_group total rows: 395 explain of the query
which ones have index it looks you need composite index because file sorting. usage: CREATE INDEX index_name ON table_name(c2,c3,c4);
You are getting above result because some time o/p of explain gives different result as response of query of prod. For optimization of query you can't have a fix answer. it varies from case to case. As for this situation I think you need to perform performance testing of this query. You can do this by inserting some records in all referenced table and then checking it's performance using explain.
LEFT JOIN campaign_in_category c6 ON c.id = c6.campaign_id seems to be totally useless. But the Optimizer may not realize it. Remove it and any other dead code.
MySQL Slow ORDER BY when done on JOIN value?
I have this query: SELECT c.*, cv.views FROM content AS c JOIN content_views AS cv ON cv.content = c.record_num WHERE c.enabled = 1 ORDER BY cv.views Quite simple, but it's really slow... Is there a way to make it faster ? This is my EXPLAIN: id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE c ref enabled_2,enabled enabled 4 const 23947 Using temporary; Using filesort 1 SIMPLE cv eq_ref PRIMARY PRIMARY 4 c.record_num 1 EDIT 2016-02-24 Please note that usually, I use a LIMIT so the number of records returned in the EXPLAIN isn't entirely accurate, however for the sake of simplicity and because the performance doesn't change with the LIMIT or without it, I have removed it. As requested in the comments, this is the result of my SHOW CREATE TABLE. As you can see, one of my table is MyISAM while the other is InnoDB. CREATE TABLE `content` ( `title` varchar(255) NOT NULL DEFAULT '', `filename` varchar(255) NOT NULL DEFAULT '', `filename_2` varchar(255) NOT NULL, `filename_3` varchar(255) NOT NULL, `orig_filename` varchar(255) NOT NULL, `trailer_filename` varchar(255) NOT NULL, `thumbnail` varchar(255) NOT NULL DEFAULT '', `embed` text NOT NULL, `description` text NOT NULL, `paysite` int(11) NOT NULL DEFAULT '0', `keywords` varchar(255) NOT NULL, `model` varchar(255) NOT NULL DEFAULT '', `scheduled_date` date NOT NULL DEFAULT '0000-00-00', `date_added` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `encoded_date` datetime NOT NULL, `rating` int(5) NOT NULL DEFAULT '0', `length` int(11) NOT NULL DEFAULT '0', `submitter` int(11) NOT NULL DEFAULT '0', `ip` varchar(15) NOT NULL, `approved` int(11) NOT NULL DEFAULT '0', `hotlinked` varchar(1024) NOT NULL, `plug_url` varchar(255) NOT NULL, `enabled` int(11) NOT NULL DEFAULT '0', `main_thumb` int(11) NOT NULL DEFAULT '3', `xml` varchar(32) NOT NULL, `photos` int(11) NOT NULL DEFAULT '0', `mobile` varchar(255) NOT NULL, `modeltmp` varchar(255) NOT NULL, `movie_width` int(11) NOT NULL, `movie_height` int(11) NOT NULL, `token` varchar(255) DEFAULT NULL, `source_thumb_url` varchar(255) NOT NULL, `related` varchar(1024) NOT NULL, `force_related` varchar(255) NOT NULL, `record_num` int(11) NOT NULL AUTO_INCREMENT, `webvtt_src` text NOT NULL, `category_thumb` int(11) NOT NULL, `related_date` date NOT NULL, `publish_ready` tinyint(1) NOT NULL, PRIMARY KEY (`record_num`), KEY `encoded_date` (`encoded_date`,`photos`,`enabled`), KEY `filename` (`filename`), KEY `scheduled_date` (`scheduled_date`), KEY `enabled_2` (`enabled`,`length`,`photos`), KEY `enabled` (`enabled`,`encoded_date`,`photos`), KEY `rating` (`rating`,`enabled`,`photos`), KEY `token` (`token`), KEY `submitter` (`submitter`), FULLTEXT KEY `keywords` (`keywords`,`title`), FULLTEXT KEY `title` (`title`), FULLTEXT KEY `description` (`description`), FULLTEXT KEY `keywords_2` (`keywords`) ) ENGINE=MyISAM AUTO_INCREMENT=124207 DEFAULT CHARSET=latin1 CREATE TABLE `content_views` ( `views` int(11) NOT NULL, `content` int(11) NOT NULL, PRIMARY KEY (`content`), KEY `views` (`views`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1
For this query: SELECT c.*, cv.views FROM content c JOIN content_views cv ON cv.content = c.record_num WHERE c.enabled = 1 ORDER BY cv.views; The best indexes are probably content(enabled, record_num) and content_views(content, views). I am guessing that the performance even with these indexes will be similar to what you have now.
Indexes in Mysql table
I have such tables: CREATE TABLE `skadate_newsfeed_action` ( `id` int(11) NOT NULL AUTO_INCREMENT, `entityId` int(11) NOT NULL, `entityType` varchar(100) NOT NULL, `feature` varchar(100) NOT NULL, `data` longtext NOT NULL, `status` varchar(20) NOT NULL DEFAULT 'active', `createTime` int(11) NOT NULL, `updateTime` int(11) NOT NULL, `userId` int(11) NOT NULL, `visibility` int(11) NOT NULL, `privacy` enum('everybody','friends_only') NOT NULL DEFAULT 'everybody', PRIMARY KEY (`id`), KEY `userId` (`userId`), KEY `privacy` (`visibility`), KEY `updateTime` (`updateTime`), KEY `entity` (`entityType`,`entityId`) ) ENGINE=MyISAM; CREATE TABLE `skadate_profile` ( `profile_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `email` varchar(128) NOT NULL DEFAULT '', `username` varchar(32) NOT NULL DEFAULT '', `password` varchar(40) NOT NULL, `sex` bigint(20) DEFAULT NULL, `match_sex` bigint(20) DEFAULT NULL, `birthdate` date NOT NULL DEFAULT '0000-00-00', `headline` varchar(128) DEFAULT '', `general_description` text, `match_agerange` varchar(6) DEFAULT NULL, `custom_location` varchar(255) DEFAULT NULL, `country_id` char(2) NOT NULL DEFAULT '', `zip` varchar(10) DEFAULT NULL, `state_id` varchar(5) DEFAULT NULL, `city_id` int(11) DEFAULT '0', `join_stamp` int(10) unsigned NOT NULL DEFAULT '0', `activity_stamp` int(10) unsigned NOT NULL DEFAULT '0', `membership_type_id` int(10) unsigned NOT NULL DEFAULT '18', `affiliate_id` int(8) unsigned NOT NULL DEFAULT '0', `email_verified` enum('undefined','yes','no') NOT NULL DEFAULT 'undefined', `reviewed` enum('n','y') NOT NULL DEFAULT 'n', `has_photo` enum('n','y') NOT NULL DEFAULT 'n', `has_media` enum('n','y') NOT NULL DEFAULT 'n', `status` enum('active','on_hold','suspended') NOT NULL DEFAULT 'active', `featured` enum('n','y') NOT NULL DEFAULT 'n', `register_invite_score` tinyint(3) NOT NULL DEFAULT '0', `rate_score` tinyint(3) unsigned NOT NULL DEFAULT '0', `rates` bigint(20) unsigned NOT NULL DEFAULT '0', `language_id` int(10) unsigned NOT NULL DEFAULT '0', `join_ip` int(11) unsigned NOT NULL DEFAULT '0', `neigh_location` enum('country','state','city','zip') DEFAULT NULL, `neigh_location_distance` int(10) unsigned NOT NULL DEFAULT '0', `bg_color` varchar(32) DEFAULT NULL, `bg_image` varchar(32) DEFAULT NULL, `bg_image_url` varchar(255) DEFAULT NULL, `bg_image_mode` tinyint(1) DEFAULT NULL, `bg_image_status` enum('active','approval') NOT NULL DEFAULT 'active', `has_music` enum('n','y') NOT NULL DEFAULT 'n', `is_private` tinyint(1) NOT NULL DEFAULT '0', `subscription_id_offerit` text, PRIMARY KEY (`profile_id`), UNIQUE KEY `email` (`email`), UNIQUE KEY `username` (`username`), KEY `membership_id` (`membership_type_id`), KEY `zip` (`zip`), KEY `country_id` (`country_id`), KEY `state_id` (`state_id`), KEY `city_id` (`city_id`), KEY `sex` (`sex`), KEY `match_sex` (`match_sex`), KEY `activity_stamp` (`activity_stamp`), KEY `join_stamp` (`join_stamp`), KEY `birthdate` (`birthdate`), KEY `featured` (`featured`,`has_photo`,`activity_stamp`) ) ENGINE=MyISAM; And try to perform this query: SELECT DISTINCT `na`.* FROM `skadate_newsfeed_action` AS `na` LEFT JOIN `skadate_profile` AS `profile` ON ( `na`.`userId` = `profile`.`profile_id` ) WHERE ( profile.email_verified='yes' OR profile.email_verified='no' OR profile.email_verified='undefined' ) AND `profile`.`status`='active' AND `na`.`status`='active' AND `na`.`privacy`='everybody' AND `na`.`visibility` & 1 AND `na`.`updateTime` < 1455885224 ORDER BY `na`.`updateTime` DESC, `na`.`id` DESC LIMIT 0, 10 But when I see EXPLAIN: Maybe someone can help me, how I can improve this query?
If you want records from only one table, then use exists rather than a join and select distinct. So: SELECT na.* FROM `skadate_newsfeed_action` na WHERE EXISTS (SELECT 1 FROM skadate_profile p WHERE na.userId = p.profile_id AND p.email_verified IN ('yes', 'no', 'undefined') AND p.status = 'active' ) AND na.status = 'active' AND na.privacy = 'everybody' AND na.visibility & 1 > 0 AND na.updateTime < 1455885224 ORDER BY na.`updateTime` DESC, na.`id` DESC LIMIT 0, 10; For this query, you want an index on skadate_profile(profile_id, status, verified). Also, the following index is probably helpful: skadate_newsfeed_action(status, privacy, updateTime, visibility, userId).
This is probably because of the DISTICT keyword. To remove duplicates MySQL needs to sort the result by every selected column.
Perf of select mysql query is really bad
I'm not sure why this query is taking 4 minutes to complete: SELECT su.sid,u.uid,u.display_name,u.locale FROM user u LEFT JOIN subscription_user su ON su.uid = u.uid ORDER BY u.display_name DESC LIMIT 0,25; Well, I know it's due to the order, remove it and it's very fast. If I change to using INNER JOIN instead it's fast but the issue is not all users may be in the subscription_user table. CREATE TABLE `user` ( `uid` int(11) NOT NULL AUTO_INCREMENT, `password` varchar(100) DEFAULT NULL, `user_type` varchar(10) NOT NULL DEFAULT 'user', `display_name` varchar(50) NOT NULL, `email` varchar(100) NOT NULL, `locale` varchar(8) DEFAULT 'en', `last_login` datetime DEFAULT NULL, `auth_type` varchar(10) DEFAULT NULL, `auth_data` varchar(500) DEFAULT NULL, `inactive` tinyint(4) NOT NULL DEFAULT '0', `receive_email` tinyint(4) NOT NULL DEFAULT '1', `stateid` int(10) DEFAULT NULL, `owner_group_id` int(11) DEFAULT NULL, `signature` varchar(500) DEFAULT NULL, `raw_signature` varchar(500) DEFAULT NULL, `round_robin` smallint(5) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`uid`), UNIQUE KEY `email` (`email`), KEY `stateid` (`stateid`) USING BTREE, KEY `user_type` (`user_type`) USING BTREE, KEY `name` (`display_name`) ) ENGINE=InnoDB AUTO_INCREMENT=28343 DEFAULT CHARSET=latin1; CREATE TABLE `subscription_user` ( `sid` varchar(50) NOT NULL, `uid` int(11) NOT NULL, `deleted` tinyint(4) NOT NULL DEFAULT '0', `forum_user` varchar(50) NOT NULL, PRIMARY KEY (`sid`,`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
When you have an SQL query, the index can only really help you if the first column in the index is part of the query. Your query joins su.uid = u.uid and the optimizer will not be able to use that to reference the first column in the subscription primary key index. You should either reverse the order of the columns in the primary key, or alternatively, you should add a foreign key index, or an independent index on the uid