Why is the below query failing it use the index story_id, in the story_keywords table?
mysql> EXPLAIN SELECT `stories`.*
-> FROM (`stories`)
-> JOIN `story_keywords` ON `story_keywords`.`story_id` = `stories`.`id`
-> WHERE `image_full_url` != ''
-> AND `order` != 0
-> AND `news_type` IN ('movie', 'movie_review')
-> AND `keyword` IN ('topnews', 'toptablet')
-> GROUP BY `stories`.`id`
-> ORDER BY `created` DESC, `order` DESC
-> LIMIT 5 ;
+----+-------------+----------------+--------+---------------+---------+---------+---------------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+--------+---------------+---------+---------+---------------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | story_keywords | ALL | story_id | NULL | NULL | NULL | 42 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | stories | eq_ref | PRIMARY | PRIMARY | 767 | entertainment.story_keywords.story_id | 1 | Using where |
+----+-------------+----------------+--------+---------------+---------+---------+---------------------------------------+------+----------------------------------------------+
2 rows in set (0.00 sec)
mysql> show create table stories;
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| stories | CREATE TABLE `stories` (
`id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`news_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`created` datetime DEFAULT NULL,
`author` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`author_title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`image_caption` text COLLATE utf8_unicode_ci,
`image_credit` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`image_full_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`body` text COLLATE utf8_unicode_ci,
`summary` text COLLATE utf8_unicode_ci,
`external_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`order` int(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> show create table story_keywords;
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| story_keywords | CREATE TABLE `story_keywords` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`story_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`keyword` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `story_id` (`story_id`)
) ENGINE=MyISAM AUTO_INCREMENT=85 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
It is probably because MySQL believes it is cheaper to fetch ALL rows from story_keywords table and JOIN them in instead of using indexes. It sounds weird at first, but, you see, if you have to perform 100 index lookups on a table and this table has just about 100 rows – it will cost less to read all rows. The explanation is simple: index lookup (for BTREE indexes) is O(ln N), while reading N rows is O(N). Obviously, O(N) < N * O(ln N).
To prove it – try selecting just 1 row from stories (and by one I mean one row, not sorting the whole table and limiting the result ;), just like:
SELECT `stories`.*
FROM (`stories`)
JOIN `story_keywords` ON `story_keywords`.`story_id` = `stories`.`id`
WHERE `stories`.id = SOMETHING
This query is much more likely to turn to index on story_keywords.
Hope this answers your question :)
Anton is on the right track, but I believe there is more to the problem. As my comment on the OP says, the id columns should most likely be INT types. As the explain shows, the length of the primary key on stories is 767. Usually for an INT type the length would be in the low single digits, but since the column is a VARCHAR, the length is extremely long.
Back to the main problem, since there are no indexes on stories.news_type, stories.order, or story_keywords.story_keywords, the optimizer decided to do a full scan of story_keywords since it will yield the smallest initial result set. If there was an index on one of those columns, it would likely use that first. If you add an index that the query can use it will not need to do a full table scan.
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 news table defined like this:
CREATE TABLE `news` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`creation_date` datetime DEFAULT NULL,
`modification_date` datetime DEFAULT NULL,
`active` bit(1) DEFAULT NULL,
`mark_for_delete` bit(1) DEFAULT NULL,
`verified` bit(1) DEFAULT NULL,
`bot_id` int(11) DEFAULT NULL,
`description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`hash` varchar(100) NOT NULL,
`published_at` datetime DEFAULT NULL,
`source` varchar(255) DEFAULT NULL,
`title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`url` varchar(511) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UK_1dmji5m90xaiy84vttgkvsub2` (`hash`),
KEY `index_news_source` (`source`),
KEY `index_news_creation_date` (`creation_date`)
) ENGINE=InnoDB AUTO_INCREMENT=30887718 DEFAULT CHARSET=latin1
And a join table to tag news belonging to some popular names:
CREATE TABLE `star_news` (
`stars_id` bigint(20) NOT NULL,
`news_id` bigint(20) NOT NULL,
PRIMARY KEY (`stars_id`,`news_id`),
KEY `FK4eqjn8at6h4d9335q1plxkcnl` (`news_id`),
CONSTRAINT `FK1olc51y8amp8op1kbmx269bac` FOREIGN KEY (`stars_id`) REFERENCES `star` (`id`),
CONSTRAINT `FK4eqjn8at6h4d9335q1plxkcnl` FOREIGN KEY (`news_id`) REFERENCES `news` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Here is my query to return the latest news
SELECT DISTINCT n.*
FROM news n
JOIN star_news sn
ON n.id = sn.news_id
WHERE sn.stars_id IN (1234, 12345)
ORDER BY n.creation_date DESC
LIMIT 2;
Explain:
+----+-------------+-------+------------+--------+-------------------------------------+---------+---------+-----------------------+------+----------+-----------------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+-------------------------------------+---------+---------+-----------------------+------+----------+-----------------------------------------------------------+
| 1 | SIMPLE | sn | NULL | range | PRIMARY,FK4eqjn8at6h4d9335q1plxkcnl | PRIMARY | 8 | NULL |196225| 100.00 | Using where; Using index; Using temporary; Using filesort |
| 1 | SIMPLE | n | NULL | eq_ref | PRIMARY | PRIMARY | 8 | cosmos_dev.sn.news_id | 1 | 100.00 | NULL |
+----+-------------+-------+------------+--------+-------------------------------------+---------+---------+-----------------------+------+----------+-----------------------------------------------------------+
This query takes 20 seconds on my machine. If I remove the order by clause it returns in sub milli second. How do I make the order by run faster?
I tried using force index on creation_date since its an indexed column, but it worsened the performance
First, write the query as:
SELECT n.*
FROM news n
WHERE EXISTS (SELECT 1
FROM star_news sn
WHERE n.id = sn.news_id AND
sn.stars_id IN (1234, 12345)
)
ORDER BY n.creation_date DESC
LIMIT 2 ;
This eliminates the outer SELECT DISTINCT, which should help.
Then, create an index on star_news(news_id, stars_id). This might also take advantage of an index on news(creation_date desc, id).
So you have 196k news articles relating to those 2 stars? The explain extra tells you what is happening:
Using where; Using index; Using temporary; Using filesort
MySQL is creating a temporary file and sorting it to satisfy the order by because it could not use an index that would facilitate the join AND the ordering of articles by date.
My query is not using any indexes. Query performing full table scan. What can I do to avoid this?
explain select * from
timed_delivery_messages
where start_time <= '06:39'
and end_time > '06:39'
and mode='Active'
and rotation_weight like '%,45,%'
and substr(day_of_week, 2, 1) = 'T'
limit 1;
Explain Plan
+----+-------------+-------------------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | timed_delivery_messages | ALL | NULL | NULL | NULL | NULL | 22 | Using where |
+----+-------------+-------------------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
Tables:
mysql> show create table timed_delivery_messages\G
*************************** 1. row ***************************
Table: timed_delivery_messages
Create Table: CREATE TABLE `timed_delivery_messages` (
`row_create` datetime DEFAULT NULL,
`row_mod` datetime DEFAULT NULL,
`rule_id` int(11) NOT NULL,
`start_time` time DEFAULT NULL,
`end_time` time DEFAULT NULL,
`day_of_week` varchar(7) DEFAULT NULL,
`rotation_weight` varchar(50) DEFAULT NULL,
`mode` varchar(10) DEFAULT 'active',
`long_message` varchar(256) DEFAULT NULL,
`short_message` varchar(256) DEFAULT NULL,
PRIMARY KEY (`rule_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
You must create one group index with columns
start_time,
end_time,
mode
And also do experiment to include day_of_week into this index. Maybe it will speed up your system
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
I am wondering why my query isn't using the index "created_2" which covers all the fields used in the query. It seems to use a filesort. What are the rules for picking an index?
Query:
SELECT * FROM (`stories`) WHERE `image_full_url` != '' AND `order` != 0 ORDER BY `created` DESC, `order` DESC LIMIT 5
Create Table:
| stories | CREATE TABLE `stories` (
`id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`news_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`created` datetime DEFAULT NULL,
`author` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`author_title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`image_caption` text COLLATE utf8_unicode_ci,
`image_credit` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`image_full_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`body` text COLLATE utf8_unicode_ci,
`summary` text COLLATE utf8_unicode_ci,
`external_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`order` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `news_type` (`news_type`),
KEY `created` (`created`),
KEY `news_type_2` (`news_type`,`created`),
KEY `created_2` (`created`,`image_full_url`,`order`),
KEY `image_full_url` (`image_full_url`,`order`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
Explain:
mysql> explain SELECT * FROM (`stories`) WHERE `image_full_url` != '' AND `order` != 0 ORDER BY `created` DESC, `order` DESC LIMIT 5;
+----+-------------+---------+-------+----------------+----------------+---------+------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+----------------+----------------+---------+------+------+-----------------------------+
| 1 | SIMPLE | stories | range | image_full_url | image_full_url | 768 | NULL | 25 | Using where; Using filesort |
+----+-------------+---------+-------+----------------+----------------+---------+------+------+-----------------------------+
1 row in set (0.00 sec)
The full set of rules are here, and state that an order by can't use the index if it references non-consecutive parts of the index. If you change the index from (created,image_full_url,order) to (created,order,image_full_url), that will probably let it be used.