The more records are added to database the query becomes slower. From 1 sec. to few seconds now, in result webpage load time is way to long
CREATE TABLE `ads` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`user_status` enum('register','unregister') COLLATE latin1_general_ci NOT NULL DEFAULT 'register',
`title` varchar(255) COLLATE latin1_general_ci NOT NULL,
`tags` varchar(255) COLLATE latin1_general_ci NOT NULL,
`ad_type` enum('offer','want') COLLATE latin1_general_ci NOT NULL,
`price` float NOT NULL,
`image` varchar(255) COLLATE latin1_general_ci NOT NULL,
`address` varchar(255) COLLATE latin1_general_ci NOT NULL,
`google_address` varchar(255) COLLATE latin1_general_ci NOT NULL,
`country_id` int(11) NOT NULL,
`state_id` int(11) NOT NULL,
`address2` text COLLATE latin1_general_ci NOT NULL,
`city` varchar(255) COLLATE latin1_general_ci NOT NULL,
`location` int(11) NOT NULL,
`postal_code` varchar(255) COLLATE latin1_general_ci NOT NULL,
`Latitude` varchar(255) COLLATE latin1_general_ci NOT NULL,
`Longitude` varchar(255) COLLATE latin1_general_ci NOT NULL,
`working_remote` varchar(255) COLLATE latin1_general_ci NOT NULL,
`emergency_service` varchar(255) COLLATE latin1_general_ci NOT NULL,
`ad_description` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`cat_id` int(11) NOT NULL,
`sub_cat_id` int(11) NOT NULL,
`sub_sub_cat_id` int(11) NOT NULL,
`status` enum('0','1') COLLATE latin1_general_ci NOT NULL,
`delete_status` enum('0','1') COLLATE latin1_general_ci NOT NULL DEFAULT '0',
`publication_days` varchar(255) COLLATE latin1_general_ci NOT NULL,
`publication_total` float(11,2) NOT NULL,
`added_date` datetime NOT NULL,
`expiry_date` datetime NOT NULL,
`payment_status` enum('pending','paid','cancel') COLLATE latin1_general_ci NOT NULL,
`closed_date` datetime NOT NULL,
`deleted_date` datetime NOT NULL,
`ad_status` enum('active','closed') COLLATE latin1_general_ci NOT NULL DEFAULT 'active',
`user_first_name` varchar(255) COLLATE latin1_general_ci NOT NULL,
`user_last_name` varchar(255) COLLATE latin1_general_ci NOT NULL,
`user_phone_number` varchar(255) COLLATE latin1_general_ci NOT NULL,
`user_email_id` varchar(255) COLLATE latin1_general_ci NOT NULL,
`ads_extend_date` datetime NOT NULL,
`ads_extend_expiry_date` datetime NOT NULL,
`ads_extend_status` enum('yes','no') COLLATE latin1_general_ci NOT NULL DEFAULT 'no',
`actvation_notification` enum('yes','no') COLLATE latin1_general_ci NOT NULL DEFAULT 'no',
`ads_view_count` int(11) NOT NULL,
`md5_key` varchar(100) COLLATE latin1_general_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`,`user_status`,`title`,`ad_type`,`price`),
KEY `title` (`title`),
KEY `ad_type` (`ad_type`),
KEY `price` (`price`),
KEY `google_address` (`google_address`),
KEY `country_id` (`country_id`),
KEY `state_id` (`state_id`),
KEY `city` (`city`),
KEY `postal_code` (`postal_code`),
KEY `cat_id` (`cat_id`),
KEY `sub_cat_id` (`sub_cat_id`),
KEY `sub_sub_cat_id` (`sub_sub_cat_id`),
KEY `status` (`status`),
KEY `payment_status` (`payment_status`),
KEY `ad_status` (`ad_status`),
KEY `added_date` (`added_date`),
KEY `expiry_date` (`expiry_date`),
KEY `id_2` (`id`,`user_id`,`user_status`,`title`,`ad_type`,`country_id`,`state_id`,`city`,`postal_code`,`cat_id`,`sub_cat_id`,`sub_sub_cat_id`,`added_date`,`expiry_date`,`payment_status`,`ad_status`)
) ENGINE=MyISAM AUTO_INCREMENT=1208 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci
Slow query log
# Query_time: 3.859838 Lock_time: 0.000368 Rows_sent: 340 Rows_examined: 1248768
SET timestamp=1448331158;
SELECT ads.id,ads.user_id, ads.user_status, ads.title, ads.ad_type,ads.price, ads.address, ads.google_address, ads.state_id, ads.address2, ads.city as city_id, ads. location as location_id, ads.postal_code, ads.Latitude, ads.Longitude, ads.working_remote, ads.emergency_service, ads.ad_description, ads.cat_id, ads. sub_cat_id, ads.sub_sub_cat_id, ads.status, ads.publication_total, ads.ads_view_count, ads.added_date,cat.category_name, sub_cat.category_name as sub_category_name, sub_sub_cat.category_name as sub_sub_category_name, usr.id as user_id, usr.username as user_name, usr.first_name as first_name, usr.rating as rating, adimg.thumbnail, state.state,state.state_abbr, city.city, location.location as locationname,
(SELECT added_date
FROM ads_publication as pub
WHERE pub.ad_id = ads.id
AND pub.publication_id != '0'
ORDER BY pub.sort_type ASC LIMIT 0,1) as publication_srt_id,
SQRT((((69.1*(ads.Latitude -(0)))*(69.1*(ads.Latitude -(0))))+((53*(ads.Longitude -(0)))*(53*(ads.Longitude -(0)))))) as dist_in_miles
FROM ads as ads
LEFT JOIN ads_images as adimg ON (ads.id = adimg.ad_id AND default_image = '1')
LEFT JOIN workrange as wr ON ads.user_id = wr.user_id
LEFT JOIN users as usr ON ads.user_id = usr.id
LEFT JOIN ads_service as price_list ON ads.id = price_list.ad_id
LEFT JOIN ads_publication as promot ON ads.id = promot.ad_id
LEFT JOIN user_languages as language ON ads.id = language.ad_id
LEFT JOIN categories as cat ON (ads.cat_id = cat.id AND cat.parent_category_id = 0)
LEFT JOIN categories as sub_cat ON ads.sub_cat_id = sub_cat.id
LEFT JOIN categories as sub_sub_cat ON ads.sub_sub_cat_id = sub_cat.id
LEFT JOIN location as state ON ads.state_id = state.locationId
LEFT JOIN location as city ON ads.city = city.locationId
LEFT JOIN location as location ON ads.location = location.locationId
WHERE ads.status = '1'
AND ads.payment_status = 'paid'
AND ads.delete_status = '0'
AND ads.expiry_date >= '2015-11-23 21:12:38'
AND ads.ad_status = 'active'
AND ads.ad_type = 'offer'
GROUP BY ads.id
ORDER BY ads.user_status ASC, publication_srt_id DESC, ads.added_date DESC;
Explain
id | select_type |table | type | possible_keys | key | key_len | ref | rows | Extra
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 | PRIMARY | ads | index_merge | "ad_type,status,payment_status,ad_status,expiry_dat..." | "status,ad_status" | "1,1" | NULL | 173 | "Using intersect(status,ad_status); Using where; Us..."
1 | PRIMARY | adimg | index | NULL | id | 526 | NULL | 1398 | Using index
1 | PRIMARY | wr | ALL | NULL | NULL | NULL | NULL | 75 |
1 | PRIMARY | usr | eq_ref | PRIMARY | PRIMARY | 4 | serv_co_za.ads.user_id | 1 |
1 | PRIMARY | price_list | ALL | NULL | NULL | NULL | NULL | 57 |
1 | PRIMARY | promot | ref | "ad_id,ad_id_2,ad_id_3" | ad_id_3 | 4 | serv_co_za.ads.id | 11 | Using index
1 | PRIMARY | language | ALL | NULL | NULL | NULL | NULL | 393 |
1 | PRIMARY | cat | eq_ref | "PRIMARY,id" | PRIMARY | 4 | serv_co_za.ads.cat_id | 1 |
1 | PRIMARY | sub_cat | eq_ref | "PRIMARY,id" | PRIMARY | 4 | serv_co_za.ads.sub_cat_id | 1 |
1 | PRIMARY | state | eq_ref | PRIMARY | PRIMARY | 4 | serv_co_za.ads.state_id | 1 |
1 | PRIMARY | city | eq_ref | PRIMARY | PRIMARY | 4 | serv_co_za.ads.city | 1 |
1 | PRIMARY | location | eq_ref | PRIMARY | PRIMARY | 4 | serv_co_za.ads.location | 1 |
1 | PRIMARY | sub_sub_cat | index | NULL | id | 111 | NULL | 1193 | Using index
2 | DEPENDENT SUBQUERY | pub | ref | "ad_id,ad_id_2,ad_id_3" | ad_id | 4 | func | 115 | Using where; Using filesort
Config:
key_buffer_size 33554432
max_allowed_packet 268435456
query_cache_limit 1048576
query_cache_min_res_unit 4096
query_cache_size 33554432
myisam_sort_buffer_size 16777216
sort_buffer_size 524288
thread_cache_size 4
thread_concurrency 10
interactive_timeout 28800
wait_timeout 28800
What I noticed is when this part is removed from the very end of query
GROUP BY ads.id ORDER BY ads.user_status ASC, publication_srt_id DESC, ads.added_date DESC;
query time is about 0.06 sec.
Any help or starting point is highly appreciated.
Thank you in advance,
Derek
Using intersect(status,ad_status) -- A composite index will always beat that. So add INDEX(status, ad_status). Assuming those columns are simply flags, get rid of the individual indexes on them. (Get rid of other simple indexes on other status fields.)
WHERE ads.status = '1'
AND ads.payment_status = 'paid'
AND ads.delete_status = '0'
AND ads.expiry_date >= '2015-11-23 21:12:38'
AND ads.ad_status = 'active'
AND ads.ad_type = 'offer'
For that WHERE, this is better:
INDEX(status, payment_status, delete_status, ad_status, at_type, -- in any order
expiry_date) -- deliberately last
This will make the first step more efficient. Index Cookbook explains how I got that.
Remove LEFT unless the 'right' table is really optional. This could give the optimizer more choices on evaluating the query.
wr, price_list, and language need to scan ALL rows. Let's figure out why. They need indexes on user_id, ad_id, and ad_id respectively. And the datatypes must match what you are comparing to.
Don't use (M,N) (eg, float(11,2)) in FLOAT or DOUBLE, it leads to an extra rounding that could cause surprises. For currency, switch to DECIMAL(11,2) (or similar).
Don't use VARCHAR for continuous, numeric, values such as Latitude and Longitude. FLOAT or DOUBLE is good.
Consider moving to InnoDB. MyISAM is dying off.
DROP INDEX id_2 -- it is likely to serve no purpose.
Possible reasons for the query getting slower and slower:
wr, price_list, and language are getting larger. The indexes should cure that.
MyISAM involves table locks.
key_buffer_size should be set about 20% of available ram. As the tables grow, the key_buffer may be thrashing. (Note: a different setting is needed for InnoDB.)
((Edit))
Since Latitude needs to be converted for expression evaluation, it is even more important to use some numeric datatype.
pub needs INDEX(ads_id, sort_type)
publication_id may get in the way of the above INDEX; can you get rid of the test?
Related
My table consist of 600K records. The below queries have been troubling me for a while.
DDL:
CREATE TABLE `cvprofiles` (
`tid` bigint(20) NOT NULL AUTO_INCREMENT,
`partnerId` bigint(20) DEFAULT '0' COMMENT 'resume owner',
`tenant` bigint(20) DEFAULT '0' COMMENT 'sellercompany',
`lngId` int(4) DEFAULT '0',
`firstName` varbinary(150) DEFAULT '',
`lastName` varbinary(150) DEFAULT '',
`profilePicture` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT '',
`mobileIsd` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT '',
`mobileNumber` varbinary(80) DEFAULT '',
`emailId` varbinary(250) DEFAULT '',
`altEmailId` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`cvPath` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT '',
`cvFileName` varchar(250) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`genderCode` int(4) DEFAULT '0',
`dob` date DEFAULT NULL,
`presentLocation` varchar(350) COLLATE utf8mb4_unicode_ci DEFAULT '',
`presentLocationId` bigint(20) DEFAULT NULL,
`countryId` bigint(20) DEFAULT '0' COMMENT 'country to be maintained',
`latitude` decimal(19,15) DEFAULT '0.000000000000000',
`longitude` decimal(19,15) DEFAULT '0.000000000000000',
`totalExp` decimal(5,2) DEFAULT '0.00',
`anyKeywords` varchar(4000) COLLATE utf8mb4_unicode_ci DEFAULT '',
`cvKeywords` mediumtext COLLATE utf8mb4_unicode_ci,
`presentEmployer` varchar(400) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`noticePeriod` int(4) DEFAULT '0',
`presentSalaryCurrId` bigint(20) DEFAULT '0',
`crDate` datetime DEFAULT NULL,
`crUserId` bigint(20) DEFAULT '0',
`luDate` datetime DEFAULT NULL,
`luUserId` bigint(20) DEFAULT '0',
`skillKeywords` text COLLATE utf8mb4_unicode_ci,
`industryKeywords` varchar(2000) COLLATE utf8mb4_unicode_ci DEFAULT '',
`certiKeywords` varchar(2000) COLLATE utf8mb4_unicode_ci DEFAULT '',
`prefLocKeywords` varchar(2000) COLLATE utf8mb4_unicode_ci DEFAULT '',
`educationKeywords` varchar(2000) COLLATE utf8mb4_unicode_ci DEFAULT '',
`roleKeywords` tinytext COLLATE utf8mb4_unicode_ci,
`abilityKeywords` text COLLATE utf8mb4_unicode_ci,
`lngKeywords` text COLLATE utf8mb4_unicode_ci,
`infoKeywords` varchar(600) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'combination of fn,ln,mno,email,present employer designation',
`jobTitleId` bigint(20) DEFAULT NULL,
`source` bigint(6) DEFAULT NULL,
`portalUid` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`salutationId` int(5) DEFAULT NULL,
PRIMARY KEY (`tid`),
KEY `partnerId` (`partnerId`),
KEY `crDate` (`crDate`),
KEY `idx_cvprofiles_firstName` (`firstName`),
KEY `idx_cvprofiles_mobileIsd` (`mobileIsd`),
KEY `idx_cvprofiles_mobileNumber` (`mobileNumber`),
KEY `idx_cvprofiles_emailId` (`emailId`),
KEY `idx_cvprofiles_dob` (`dob`),
KEY `luDate` (`luDate`),
KEY `idx_s_p_m_e` (`tenant`,`partnerId`,`mobileNumber`,`emailId`),
KEY `idx_s_f_l_c_s` (`tenant`,`firstName`,`lastName`,`crDate`),
KEY `sel` (`tenant`),
KEY `c_c` (`crDate`,`crUserId`),
FULLTEXT KEY `fx_cat` (`skillKeywords`,`anyKeywords`,`cvKeywords`,`infoKeywords`,`abilityKeywords`,`lngKeywords`,`roleKeywords`,`industryKeywords`,`educationKeywords`,`prefLocKeywords`)
) ;
Query1: Below fulltext query takes "0.43 sec" for word "java" :
select count(*)
from cvprofiles
where match(`skillKeywords`,`anyKeywords`,`cvKeywords`,`infoKeywords`,
`abilityKeywords`,`lngKeywords`,`roleKeywords`,
`industryKeywords`,`educationKeywords`,`prefLocKeywords`)
against ('java' in boolean mode);
Result: 168944 records
Explain:
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+
Query2:
select count(*) from cvprofiles where tenant=429;
Response time: 0.18 sec , Result : 845 records
Explain:
+----+-------------+-----------------+------------+------+-------------------------------+------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------------+------------+------+-------------------------------+------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | icrd_resumeBank | NULL | ref | idx_s_p_m_e,idx_s_f_l_c_s,sel | sel | 9 | const | 845 | 100.00 | Using index |
Query3: Combine fulltext with integer field takes more then 45 sec+.
select count(*)
from cvprofiles
where match(`skillKeywords`,`anyKeywords`,`cvKeywords`,`infoKeywords`,
`abilityKeywords`,`lngKeywords`,`roleKeywords`,
`industryKeywords`,`educationKeywords`,`prefLocKeywords`)
against ('java' in boolean mode)
and tenant=429;
Response time: 40.12 sec, Result : 452 records
Explain:
+----+-------------+-----------------+------------+----------+--------------------------------------+--------+---------+-------+------+----------+-----------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------------+------------+----------+--------------------------------------+--------+---------+-------+------+----------+-----------------------------------+
| 1 | SIMPLE | icrd_resumeBank | NULL | fulltext | idx_s_p_m_e,idx_s_f_l_c_s,sel,fx_cat | fx_cat | 0 | const | 1 | 5.00 | Using where; Ft_hints: no_ranking |
+----+-------------+-----------------+------------+----------+--------------------------------------+--------+---------+-------+------+----------+-----------------------------------+
None of the combinations of the query are working. How to improve performance of the query of fulltext with integer fields?
Using MySQL version: 5.7
Storage Engine: InnoDB
The Optimizer is caught between a rock and a hard place --
whether to use the FULLTEXT index, then filter out those with the wrong tenant. (This is probably faster, and the formulation below may trick it into using it.)
Or to start by fetching on tenant first, then do the FULLTEXT tests. (Please provide SHOW CREATE TABLE cvprofiles so we can see if this is even viable.)
This kludge may make it run faster:
select count(*)
from cvprofiles
where match(`skillKeywords`,`anyKeywords`,`cvKeywords`,`infoKeywords`,
`abilityKeywords`,`lngKeywords`,`roleKeywords`,
`industryKeywords`,`educationKeywords`,`prefLocKeywords`)
against ('java' in boolean mode)
HAVING tenant=429;
The CREATE TABLE may point out flaws in the schema that led to slugishness.
On second thought, my kludge may not help in this case. It will fetch 168944 rows, then reach into the table to check that many value of tenant; this will be 168944 random lookups. The speed of that depends on disk type (SSD vs HDD) and size of innodb_buffer_pool_size. So, which disk type and what is that setting, plus how much RAM on the server?
Where I am going with the previous paragraph... If cache space is tight, it will be slow.
This looks like a case where "index merge intersect" would be useful, but the EXPLAIN says it did not try that. So,... Consider filing a bug report at bugs.mysql.com .
Hard to say without the EXPLAIN statement and table indexes, however most likely MySQL is making a huge temporary table to store the result of the first match and then tries the second filter.
I would recommend setting the 'tenant=429' part as a subquery instead.
select count(*) from
( SELECT `skillKeywords`,`anyKeywords`,`cvKeywords`,`infoKeywords`,`abilityKeywords`,`lngKeywords`,`roleKeywords`,`industryKeywords`,`educationKeywords`,`prefLocKeywords`
from cvprofiles
where tenant=429
) AS x
WHERE match(`skillKeywords`,`anyKeywords`,`cvKeywords`,`infoKeywords`,`abilityKeywords`,`lngKeywords`,`roleKeywords`,`industryKeywords`,`educationKeywords`,`prefLocKeywords`)
against ('java' in boolean mode) ;
Note that you will most likely need to name the columns in the subquery and access that that way.
I have the following entry in mysql-slow.log:
# Time: 180506 21:57:03
# User#Host: mysqlserver[mysqlserver] # localhost []
# Query_time: 88.963476 Lock_time: 0.000088 Rows_sent: 50 Rows_examined: 114197
SET timestamp=1525633023;
SELECT n1.full_name AS sender_full_name, s1.email AS sender_email, e.subject, e.body,
e.attach, e.date, e.id, r.status, n2.full_name AS receiver_full_name,
s2.email AS receiver_email, r.basket
FROM people_emails p
JOIN email_routing r ON r.receiver_email_id = 3223 AND r.status = 2
JOIN email e ON e.id = r.message_id
JOIN people_emails s1 ON s1.id = r.sender_email_id
JOIN people n1 ON n1.id = s1.people_id
JOIN people_emails s2 ON s2.id = r.receiver_email_id
JOIN people n2 ON n2.id = s2.people_id
WHERE p.internal_user_id = 314
ORDER BY e.date desc
LIMIT 0, 50;
The result of that query is similar to this:
----------------------------------------------------------------------------------------------------
|sender_full_name|sender_email|subject|body| attach | date | id |status|receiver_full_name|basket|
----------------------------------------------------------------------------------------------------
|John Blow |jb#corp.lan |Aloha |Text| |180506|856050|2 |Mary Johns |1 |
----------------------------------------------------------------------------------------------------
Here is all the data about the query and the used tables:
EXPLAIN SELECT n1.full_name AS sender_full_name, s1.email AS sender_email,
e.subject, e.body, e.attach, e.date, e.id, r.status, n2.full_name AS receiver_full_name,
s2.email AS receiver_email, r.basket, 'user777' FROM people_emails p
JOIN email_routing r ON r.receiver_email_id = 3233 AND r.status = 2
JOIN email e ON e.id = r.message_id
JOIN people_emails s1 ON s1.id = r.sender_email_id
JOIN people n1 ON n1.id = s1.people_id
JOIN people_emails s2 ON s2.id = r.receiver_email_id
JOIN people n2 ON n2.id = s2.people_id
WHERE p.internal_user_id = 314 ORDER BY e.date desc LIMIT 0, 50;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE s2 const PRIMARY PRIMARY 4 const 1 Using temporary; Using filesort
1 SIMPLE n2 const PRIMARY PRIMARY 4 const 1
1 SIMPLE p ALL NULL NULL NULL NULL 18631 Using where
1 SIMPLE r ALL NULL NULL NULL NULL 899567 Using where; Using join buffer
1 SIMPLE e eq_ref PRIMARY PRIMARY 4 server.r.message_id 1
1 SIMPLE s1 eq_ref PRIMARY PRIMARY 4 server.r.sender_email_id1
1 SIMPLE n1 eq_ref PRIMARY PRIMARY 4 server.s1.people_id 1
SHOW CREATE TABLE people_emails;
CREATE TABLE `people_emails` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nick` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`key_name` varchar(255) NOT NULL,
`people_id` int(11) NOT NULL,
`status` int(11) NOT NULL DEFAULT '0',
`activity` int(11) NOT NULL,
`internal_user_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
FULLTEXT KEY `email` (`email`)
) ENGINE=MyISAM AUTO_INCREMENT=22114 DEFAULT CHARSET=utf8
SHOW CREATE TABLE email_routing;
CREATE TABLE `email_routing` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`message_id` int(11) NOT NULL,
`sender_email_id` int(11) NOT NULL,
`receiver_email_id` int(11) NOT NULL,
`basket` int(11) NOT NULL,
`status` int(11) NOT NULL,
`popup` int(11) NOT NULL,
`tm` int(11) NOT NULL,
KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=987389 DEFAULT CHARSET=utf8
SHOW CREATE TABLE email;
CREATE TABLE `email` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`subject` text NOT NULL,
`body` text NOT NULL,
`date` datetime NOT NULL,
`attach` text NOT NULL,
`attach_ondisk` text NOT NULL,
`attach_dir` varchar(255) CHARACTER SET cp1251 DEFAULT NULL,
`attach_subject` varchar(255) DEFAULT NULL,
`attach_content` longtext,
PRIMARY KEY (`id`),
KEY `Index_2` (`attach_dir`),
FULLTEXT KEY `path` (`attach_dir`)
) ENGINE=MyISAM AUTO_INCREMENT=856151 DEFAULT CHARSET=utf8
SHOW CREATE TABLE people;
CREATE TABLE `people` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`fname` varchar(255) CHARACTER SET cp1251 NOT NULL,
`lname` varchar(255) CHARACTER SET cp1251 NOT NULL,
`patronymic` varchar(255) CHARACTER SET cp1251 NOT NULL,
`gender` tinyint(1) NOT NULL,
`full_name` varchar(255) NOT NULL DEFAULT ' ',
`category` int(11) NOT NULL,
`people_type_id` int(255) DEFAULT NULL,
`tags` varchar(255) CHARACTER SET cp1251 NOT NULL,
`job` varchar(255) CHARACTER SET cp1251 NOT NULL,
`post` varchar(255) CHARACTER SET cp1251 NOT NULL,
`profession` varchar(255) CHARACTER SET cp1251 DEFAULT NULL,
`zip` varchar(16) CHARACTER SET cp1251 NOT NULL,
`country` int(11) DEFAULT NULL,
`region` varchar(10) NOT NULL,
`city` varchar(255) CHARACTER SET cp1251 NOT NULL,
`address` varchar(255) CHARACTER SET cp1251 NOT NULL,
`address_date` date DEFAULT NULL,
`inner` tinyint(4) NOT NULL,
`contact_through` varchar(255) DEFAULT '',
`next_call` date NOT NULL,
`additional` text CHARACTER SET cp1251 NOT NULL,
`user_id` int(11) NOT NULL,
`changed` datetime NOT NULL,
`status` int(11) DEFAULT NULL,
`nick` varchar(255) DEFAULT NULL,
`birthday` date DEFAULT NULL,
`last_update_ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`area` text NOT NULL,
`reviewed_` tinyint(4) NOT NULL,
`phones_old` text NOT NULL,
`post_sticker` text NOT NULL,
`permissions` int(120) NOT NULL DEFAULT '0',
`internal_user_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `most_used` (`category`,`status`,`city`,`lname`,`next_call`),
KEY `registrars` (`category`,`status`,`contact_through`,`next_call`),
FULLTEXT KEY `lname` (`lname`),
FULLTEXT KEY `fname` (`fname`),
FULLTEXT KEY `mname` (`patronymic`),
FULLTEXT KEY `Full Name` (`full_name`)
) ENGINE=MyISAM AUTO_INCREMENT=415009 DEFAULT CHARSET=utf8
While getting the above output as per request from the comment I have also noticed that my tables are all in different format - MyISAM and InnoDB. Can that be a part of the problem too?
Did I made the tables structure too complicated? I would like to understand what part of the query makes this so slow so I can re-arrange my tables.
In general, you want to eliminate the entries from your EXPLAIN report where type=ALL. This means it's doing a table-scan, and that's bad for performance if it happens on a large table.
In your case, you have two tables that are doing table-scans. Check the numbers in the row column of the explain, 18631 and 899567. Multiply them together = 16,759,832,777. That's how many row combinations the query will potentially examine!
Part of the problem is that your query is doing a Cartesian product. You have no conditions relating your table p to the other tables. So for every row examined in p, it combines this with the rows examined in other tables. This has a very high cost.
It's not clear why you even have p in your query, since it's not related to the other tables, and you don't fetch any columns from it in the select-list. I can produce the result set you described even when I take p out of the query:
SELECT n1.full_name AS sender_full_name, s1.email AS sender_email,
e.subject, e.body, e.attach, e.date, e.id, r.status, n2.full_name AS receiver_full_name,
s2.email AS receiver_email, r.basket, 'user777'
FROM email_routing r
JOIN email e ON e.id = r.message_id
JOIN people_emails s1 ON s1.id = r.sender_email_id
JOIN people n1 ON n1.id = s1.people_id
JOIN people_emails s2 ON s2.id = r.receiver_email_id
JOIN people n2 ON n2.id = s2.people_id
WHERE r.receiver_email_id = 3233 AND r.status = 2
ORDER BY e.date desc LIMIT 0, 50;
I also suggest adding this index:
ALTER TABLE email_routing ADD KEY bk1 (receiver_email_id, status,
sender_email_id, message_id, basket);
This helps the search for r.receiver_email_id = 3233 AND r.status = 2.
The additional columns are in the index to make it a covering index. This means the query doesn't have to read the email_routing table at all, if it gets all the columns it needs from the index.
EXPLAIN for this query looks better, now that none of the tables are doing type=ALL, and one of them shows "Using index" which is the indicator of the covering index.
+----+-------------+-------+--------+---------------+---------+---------+------------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+------------------------+------+---------------------------------+
| 1 | SIMPLE | s2 | const | PRIMARY | PRIMARY | 4 | const | 1 | Using temporary; Using filesort |
| 1 | SIMPLE | n2 | const | PRIMARY | PRIMARY | 4 | const | 1 | NULL |
| 1 | SIMPLE | r | ref | bk1 | bk1 | 8 | const,const | 1 | Using index |
| 1 | SIMPLE | s1 | eq_ref | PRIMARY | PRIMARY | 4 | test.r.sender_email_id | 1 | NULL |
| 1 | SIMPLE | n1 | eq_ref | PRIMARY | PRIMARY | 4 | test.s1.people_id | 1 | NULL |
| 1 | SIMPLE | e | eq_ref | PRIMARY | PRIMARY | 4 | test.r.message_id | 1 | NULL |
+----+-------------+-------+--------+---------------+---------+---------+------------------------+------+---------------------------------+
P.S.: MyISAM vs. InnoDB makes little difference for this query optimization. The index will help a lot for both storage engines. But I always recommend to convert to InnoDB (see my answer to MyISAM versus InnoDB).
This looks wrong:
FROM people_emails p
JOIN email_routing r ON r.receiver_email_id = 3223
AND r.status = 2
p is not used in any ON clauses. Perhaps you are missing so way to tie p and r together? Without it, you have a "cross join". If there are 1K rows in each, you end up with 1M rows in the join.
Also, please use ON for showing how tables relate; use WHERE for filtering (3222 & 2).
I have a SQL query with 3 tables joined on a distant MySQL DB- Two of these tables have size of about 18GByte (STEP_RESULT and meas_numericlimit) and then the distant server create a TMP table which takes age (about 25 min) to end
How can I optimize this query ?
select
t1.UUT_NAME,
t1.STATION_NUM,
t1.START_DATE_TIME,
t3.LOW_LIMIT,
t3.DATA,
t3.HIGH_LIMIT,
t3.UNITS,
t2b.STEP_NAME
from
meas_numericlimit t3
inner join STEP_RESULT t2a on t3.ID = t2a.STEP_ID
inner join STEP_RESULT t2b on t2a.STEP_PARENT = t2b.STEP_ID
inner join uut_result t1 on t2b.UUT_RESULT = t1.ID
where
t1.UUT_NAME like 'Variable1-1%' and
t1.STATION_NUM = 'variable2' and
t2b.STEP_NAME = 'variable3' and
t2b.STEP_TYPE = 'constant'
Here the SHOW TABLES and EXPLAIN output queries :
+--------------------+
| Tables_in_spectrum |
+--------------------+
| cal_dates |
| calibrage |
| execution_time |
| meas_numericlimit |
| station_feature |
| step_callexe |
| step_graph |
| step_msgjnl |
| step_msgpopup |
| step_passfail |
| step_result |
| step_seqcall |
| step_stringvalue |
| syst_event |
| uptime |
| users |
| uut_result |
+--------------------+
and
+----+-------------+-------+--------+-------------------------+---------+
| id | select_type | table | type | possible_keys | key |
+----+-------------+-------+--------+-------------------------+---------+
| 1 | SIMPLE | t2a | ALL | NULL | NULL |
| 1 | SIMPLE | t3 | eq_ref | PRIMARY | PRIMARY |
| 1 | SIMPLE | t2b | ALL | NULL | NULL |
| 1 | SIMPLE | t1 | eq_ref | PRIMARY,FK_uut_result_1 | PRIMARY |
+----+-------------+-------+--------+-------------------------+---------+
---------+----------------------+----------- +---------------------------+
key_len | ref | rows | Extra |
---------+----------------------+----------- +---------------------------+
NULL | NULL | 48120004 | |
40 | spectrum.t2a.STEP_ID | 1 | |
NULL | NULL | 48120004 | Using where; Using join
buffer |
40 | spectrum.t2b.UUT_RESULT | 1 | Using where |
-------+----------------------+------------+---------------------------+
Here the SHOW CREATE TABLE :
CREATE TABLE `uut_result` (
`ID` varchar(38) NOT NULL DEFAULT '',
`STATION_NUM` varchar(255) DEFAULT NULL,
`SOFTVER_ODTGEN` varchar(10) DEFAULT NULL,
`HARDVER_ODTGEN` varchar(10) DEFAULT NULL,
`NEXT_CAL_DATE` date DEFAULT NULL,
`UUT_NAME` varchar(255) DEFAULT NULL,
`UUT_SERIAL_NUMBER` varchar(255) DEFAULT NULL,
`UUT_VERSION` varchar(255) DEFAULT NULL,
`USER_LOGIN_NAME` varchar(255) DEFAULT NULL,
`USER_LOGIN_LOGIN` varchar(255) NOT NULL DEFAULT '',
`START_DATE_TIME` datetime DEFAULT NULL,
`EXECUTION_TIME` float DEFAULT NULL,
`UUT_STATUS` varchar(255) DEFAULT NULL,
`UUT_ERROR_CODE` int(11) DEFAULT NULL,
`UUT_ERROR_MESSAGE` varchar(1023) DEFAULT NULL,
`PAT_NAME` varchar(255) NOT NULL DEFAULT '',
`PAT_VERSION` varchar(10) NOT NULL DEFAULT '',
`TEST_LEVEL` varchar(50) DEFAULT NULL,
`INTERFACE_ID` int(10) unsigned NOT NULL DEFAULT '0',
`EXECUTION_MODE` varchar(45) DEFAULT NULL,
`LOOP_MODE` varchar(45) DEFAULT NULL,
`STOP_ON_FAIL` tinyint(4) unsigned NOT NULL DEFAULT '0',
`EXECUTION_COMMENT` text,
PRIMARY KEY (`ID`),
KEY `FK_uut_result_1` (`STATION_NUM`)
) ENGINE=MyISAM DEFAULT CHARSET=latin;
and
CREATE TABLE `meas_numericlimit` (
`ID` varchar(38) NOT NULL DEFAULT '',
`STEP_RESULT` varchar(38) NOT NULL DEFAULT '',
`NAME` varchar(255) DEFAULT NULL,
`COMP_OPERATOR` varchar(30) DEFAULT NULL,
`HIGH_LIMIT` double DEFAULT NULL,
`LOW_LIMIT` double DEFAULT NULL,
`UNITS` varchar(255) DEFAULT NULL,
`DATA` double DEFAULT NULL,
`STATUS` varchar(255) DEFAULT NULL,
`FORMAT` varchar(15) DEFAULT NULL,
`NANDATA` int(11) DEFAULT '0',
PRIMARY KEY (`ID`),
KEY `FK_meas_numericlimit_1` (`STEP_RESULT`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
and
CREATE TABLE `step_result` (
`ID` varchar(38) NOT NULL DEFAULT '',
`UUT_RESULT` varchar(38) NOT NULL DEFAULT '',
`STEP_PARENT` varchar(38) DEFAULT NULL,
`STEP_NAME` varchar(255) DEFAULT NULL,
`STEP_ID` varchar(38) NOT NULL DEFAULT '',
`STEP_TYPE` varchar(255) DEFAULT NULL,
`STATUS` varchar(255) DEFAULT NULL,
`REPORT_TEXT` text,
`DIAG` text,
`ERROR_OCCURRED` tinyint(1) NOT NULL DEFAULT '0',
`ERROR_CODE` int(11) DEFAULT NULL,
`ERROR_MESSAGE` varchar(1023) DEFAULT NULL,
`MODULE_TIME` float DEFAULT NULL,
`TOTAL_TIME` float DEFAULT NULL,
`NUM_LOOPS` int(11) DEFAULT NULL,
`NUM_PASSED` int(11) DEFAULT NULL,
`NUM_FAILED` int(11) DEFAULT NULL,
`ENDING_LOOP_INDEX` int(11) DEFAULT NULL,
`LOOP_INDEX` int(11) DEFAULT NULL,
`INTERACTIVE_EXENUM` int(11) DEFAULT NULL,
`STEP_GROUP` varchar(30) DEFAULT NULL,
`STEP_INDEX` int(11) DEFAULT NULL,
`ORDER_NUMBER` int(11) DEFAULT NULL,
PRIMARY KEY (`ID`),
KEY `FK_step_result_1` (`UUT_RESULT`),
KEY `IDX_step_parent` (`STEP_PARENT`)
) ENGINE=MyISAM DEFAULT CHARSET=latin
Thank you for your help
What is the value of join_buffer_size? It should not be more than about 1% of RAM. If it is much bigger, you run the risk of swapping, which is especially bad for performance.
One thing jumps out in the EXPLAIN: NULL | 48120004 saying that this is needed: INDEX(STEP_ID);
However, the SELECT and the EXPLAIN do not seem to match. Please double check.
uut_result needs INDEX(station_num, uut_name) -- in that order; replaces just (station_num).
What is varchar(38)? UUIDs are only 36. IPv6 needs 39.
UUIDs are terribly inefficient when the data is too big to be cached. More discussion: http://mysql.rjweb.org/doc.php/uuid
Lots of datatypes could (should) be shrunken -- this shrinkage will cut down on I/O, which will speed up queries. If you provide some sample values for some typical columns, I can give more advice.
For example, STATUS is (usually) a small number of distinct values. That could be represented as a 1-byte ENUM or a 1-byte TINYINT; but maybe your app has hundreds of different status values? If so, "normalizing" it may be the better answer.
DOUBLE takes 8 bytes; FLOAT takes only 4 bytes, but limits precision to only ~7 significant digits -- perhaps that is sufficient?
(Presumably you meant latin1, not latin?)
Also consider switching to InnoDB.
How much RAM do you have? How big (GB) are the tables?
I try to join a filed that is a int(13) on to a field that is varchar(50).
If I only use (a.id = b.id) the DESCRIBE says type: ref.
If I use (a.id = CONCAT(b.id)) the DESCRIBE says type: eq_ref. (where b.id is the integer)
The use of CONCAT to cast a field is ugly, so I tried to use CAST() or CONVERT().
If I use (a.id = CAST(b.id AS CHAR(50))) the DESCRIBE says type: ref.
How do I write a correct cast/convert, that gives a eq_ref join?
UPDATE 1:
DESCRIBE SELECT.. with CONCAT
+------+-------------+-----------------------+--------+-----------------------------------+----------------+---------+-------------------------------------+------+----------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-----------------------+--------+-----------------------------------+----------------+---------+-------------------------------------+------+----------------------------------------+
| 1 | SIMPLE | ext_icecat_prodmatch | ref | PRIMARY,our_article_id,product_id | our_article_id | 152 | const | 3016 | Using index condition; Using temporary |
| 1 | SIMPLE | ext_icecat_product | eq_ref | PRIMARY,product_id | PRIMARY | 4 | ext_icecat_prodmatch.product_id | 1 | |
| 1 | SIMPLE | ext_icecat_supplier | eq_ref | PRIMARY | PRIMARY | 4 | ext_icecat_product.supplier_id | 1 | |
| 1 | SIMPLE | products | eq_ref | PRIMARY | PRIMARY | 152 | ext_icecat_prodmatch.our_article_id | 1 | |
| 1 | SIMPLE | partner_product_saved | eq_ref | PRIMARY | PRIMARY | 155 | const,func | 1 | Using where |
| 1 | SIMPLE | category_names | eq_ref | PRIMARY | PRIMARY | 6 | products.category_id,const | 1 | Using where |
+------+-------------+-----------------------+--------+-----------------------------------+----------------+---------+-------------------------------------+------+----------------------------------------+
The Select:
SELECT
partner_product_saved.*,
ext_icecat_product.product_id,
CONCAT(ext_icecat_supplier.name, ' ', ext_icecat_product.name) AS export_product_name,
ext_icecat_product.catid_match AS category_id,
GROUP_CONCAT(ext_icecat_prodmatch.our_article_id) AS oais,
products.file_name,
category_names.category_path
FROM ext_icecat_product
LEFT JOIN ext_icecat_prodmatch USING (product_id)
LEFT JOIN ext_icecat_supplier USING (supplier_id)
LEFT JOIN products USING (our_article_id)
LEFT JOIN partner_product_saved ON (partner_product_saved.partner_id = 29 AND partner_product_saved.product_id = CONCAT(ext_icecat_product.product_id))
LEFT JOIN category_names ON (category_names.category_id = products.category_id AND category_names.language_id = 2)
WHERE ext_icecat_prodmatch.our_article_id = '0EF03850-D25A-1174-BCDC-EC67352010A6'
GROUP BY ext_icecat_product.product_id
ORDER BY NULL;
SHOW CREATE TABLE
CREATE TABLE `partner_product_saved` (
`partner_id` mediumint(8) NOT NULL,
`product_id` varchar(50) CHARACTER SET utf8 NOT NULL,
`product_name` varchar(100) CHARACTER SET utf8 NOT NULL,
`our_article_id` varchar(50) CHARACTER SET utf8 DEFAULT NULL,
`our_category_id` mediumint(8) DEFAULT NULL,
`manufacture_id` mediumint(8) DEFAULT NULL,
`manufacturer_partnr` varchar(255) COLLATE utf8_bin NOT NULL,
`manufacturer_upc` varchar(255) COLLATE utf8_bin NOT NULL,
`image` tinytext COLLATE utf8_bin NOT NULL,
`image_small` tinytext COLLATE utf8_bin NOT NULL,
`image_big` tinytext COLLATE utf8_bin NOT NULL,
`image_200` tinytext COLLATE utf8_bin NOT NULL,
`image_original` tinytext COLLATE utf8_bin NOT NULL,
`image_width` int(11) DEFAULT NULL,
`image_height` int(11) DEFAULT NULL,
`birth` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_updated` timestamp NULL DEFAULT NULL,
`saved` tinyint(3) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`partner_id`,`product_id`),
KEY `our_article_id` (`our_article_id`),
KEY `our_category_id` (`our_category_id`),
KEY `manufacture_id` (`manufacture_id`,`manufacturer_partnr`),
KEY `manufacturer_upc` (`manufacturer_upc`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `ext_icecat_product` (
`product_id` int(13) NOT NULL,
`supplier_id` int(13) NOT NULL DEFAULT '0',
`prod_id` varchar(235) COLLATE utf8_bin NOT NULL DEFAULT '',
`prod_id_clean` varchar(255) CHARACTER SET utf8 NOT NULL,
`catid` int(13) NOT NULL DEFAULT '0',
`catid_match` varchar(50) CHARACTER SET utf8 NOT NULL,
`name` varchar(255) CHARACTER SET utf8 NOT NULL,
`name_clean` varchar(255) CHARACTER SET utf8 NOT NULL,
`low_pic` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '',
`high_pic` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '',
`thumb_pic` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`family_id` int(13) NOT NULL DEFAULT '0',
`low_pic_size` int(13) DEFAULT '0',
`high_pic_size` int(13) DEFAULT '0',
`thumb_pic_size` int(13) DEFAULT '0',
`import_date` datetime NOT NULL,
`release_date` datetime NOT NULL,
`updated` datetime NOT NULL,
`need_update` tinyint(1) NOT NULL DEFAULT '0',
`deleted` tinyint(1) NOT NULL DEFAULT '0',
`keyword` tinyint(1) NOT NULL DEFAULT '0',
`special_match` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`product_id`),
KEY `supplier_id` (`supplier_id`),
KEY `catid` (`catid`),
KEY `prod_id` (`prod_id`),
KEY `product_id` (`product_id`,`prod_id`,`supplier_id`),
KEY `release_Date` (`release_date`),
KEY `prod_id_clean` (`prod_id_clean`),
KEY `name_clean` (`name_clean`),
KEY `need_update` (`need_update`),
KEY `deleted` (`deleted`),
KEY `keyword` (`keyword`),
KEY `catid_2` (`catid`,`import_date`),
KEY `catid_match` (`catid_match`),
KEY `special_match` (`special_match`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
WHERE indexed_column = any_function(any_column) -- can use index. WHERE non_indexed_column = any_function(indexed_column) -- cannot use index.
The difference between ref and eq_ref is minor. I think that eq_ref is where the optimizer decides that there cannot be more than one match, often because of UNIQUE.
WHERE ext_icecat_prodmatch.our_article_id = '0EF03850-D25A-1174-BCDC-EC67352010A6' -- is our_article_id INDEXed? or UNIQUE? Sounds like it is only an INDEX, so multiple rows might ensue. To make it eq_ref, you need UNIQUE. But only if the data supports such. The stats imply there might be 3016 rows with that article_id.
Do not use LEFT unless you need it. Note how the Optimizer turned LEFT JOIN ext_icecat_prodmatch USING (product_id) into JOIN and decided (rightly) to start with ext_icecat_prodmatch.
Back to other discussions...
AND partner_product_saved.product_id = CONCAT(ext_icecat_product.product_id))
can go one way, but not the other. That is, it can efficiently go from eip to pps, but not the other way. And EXPLAIN indicated such with const,func.
There is this query that have been bugging me in two days now, it used to work good but now it slows down the entire cluster environment, the query is as seen below:
SELECT userUploads.*,
users_avatar.avatar AS avatar
FROM userUploads
LEFT JOIN users_avatar
ON userUploads.udid = users_avatar.udid
INNER JOIN user_subscription
ON (
user_subscription.sub_1 = 'G:123456789'
AND user_subscription.sub_2 = userUploads.udid
)
WHERE userUploads.platform = 'Private'
AND userUploads.STATUS IN ( 'featured', 'approved' )
ORDER BY userUploads.id DESC
LIMIT 50 OFFSET 0
I would really appreciate if anyone can help out with this query.
Below is the explain of the query:
+----+-------------+-------------------+--------+----------------------+----------+---------+------------------------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------------+--------+----------------------+----------+---------+------------------------+------+-----------------------------+
| 1 | SIMPLE | userUploads | range | platform,udid,status | platform | 154 | NULL | 12 | Using where; Using filesort |
| 1 | SIMPLE | users_avatar | eq_ref | PRIMARY | PRIMARY | 182 | Seeds.userUploads.udid | 1 | |
| 1 | SIMPLE | user_subscription | ref | sub_1,sub_2 | sub_1 | 93 | const | 7 | Using where |
+----+-------------+-------------------+--------+----------------------+----------+---------+------------------------+------+-----------------------------+
Thanks in advance
EDIT** show create table can seen below
Below is the show create table for the tables hope you have any ideas dancrumb.
| users_avatar | CREATE TABLE `users_avatar` (
`udid` varchar(60) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`avatar` varchar(448) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`udid`)
) ENGINE=ndbcluster DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
| userUploads | CREATE TABLE `userUploads` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`bdaha` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`user` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL,
`direktoren` text COLLATE utf8_unicode_ci,
`filnamnet` varchar(180) COLLATE utf8_unicode_ci DEFAULT NULL,
`karhes` varchar(150) COLLATE utf8_unicode_ci DEFAULT NULL,
`version` char(10) COLLATE utf8_unicode_ci DEFAULT NULL,
`rostat` int(10) DEFAULT NULL,
`stars` int(11) DEFAULT NULL,
`statyn` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
`platform` char(30) COLLATE utf8_unicode_ci DEFAULT NULL,
`images` int(2) DEFAULT NULL,
`date` char(10) COLLATE utf8_unicode_ci DEFAULT NULL,
`udid` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
`favorirepris` int(8) DEFAULT NULL,
`hikes` char(4) COLLATE utf8_unicode_ci DEFAULT 'no',
`dbn` char(6) COLLATE utf8_unicode_ci DEFAULT NULL,
`timestamp` char(20) COLLATE utf8_unicode_ci DEFAULT NULL,
`comments` int(5) DEFAULT NULL,
`klistret` enum('no','yes') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'no',
PRIMARY KEY (`id`),
KEY `platform` (`platform`,`status`),
KEY `udid` (`udid`),
KEY `hikes` (`hikes`),
KEY `bdaha` (`bdaha`),
KEY `statyn` (`statyn`),
KEY `version` (`version`)
) ENGINE=ndbcluster AUTO_INCREMENT=118831 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
| user_subscription | CREATE TABLE `user_subscription` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`sub_1` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL,
`sub_2` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `sub_1` (`sub_1`),
KEY `sub_2` (`sub_2`)
) ENGINE=ndbcluster AUTO_INCREMENT=155184 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
Well, you have a filesort on userUploads which is always slow. You may want to play with indices to remove that. For example, you may want to start with an index on udid, platform, and status.
In general when querying you want to perform the most limiting operations in terms of data returned first so that other operations are only performed on the data that is actually in the results.
In this case try reordering the inner join to user_subscription and the left join to users_avatar. This way it will only attempt to even get the avatar for a user if they are actually in the result set rather than it looking up all the avatars first then filtering based on joins and where clauses.
SELECT userUploads.*,
users_avatar.avatar AS avatar
FROM userUploads
INNER JOIN user_subscription
ON (
user_subscription.sub_1 = 'G:123456789'
AND user_subscription.sub_2 = userUploads.udid
)
LEFT JOIN users_avatar
ON userUploads.udid = users_avatar.udid
WHERE userUploads.platform = 'Private'
AND userUploads.STATUS IN ( 'featured', 'approved' )
ORDER BY userUploads.id DESC
LIMIT 50 OFFSET 0