简体   繁体   中英

MySQL query optimization, VERY SLOW

This is what I would like to achieve:

Show 50 last students and their cheapest products.

If product doesn't exist present empty values.

Here is the SELECT query:

SELECT 
students.*,
cs.cheapest_id,
cs.cheapest_price
FROM students
LEFT JOIN (SELECT iqs.* FROM (
        SELECT 
        student_id,
        id AS cheapest_id,
        price AS cheapest_price
        FROM products
        ORDER BY price ASC
) AS iqs
GROUP BY iqs.student_id) AS cs ON cs.student_id = students.id
ORDER BY students.name DESC
LIMIT 50;

Creating tables:

CREATE TABLE `students` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

INSERT INTO `students` VALUES ('1', 'Mark');
INSERT INTO `students` VALUES ('2', 'Chris');

CREATE TABLE `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `student_id` int(11) DEFAULT NULL,
  `price` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `student_id` (`student_id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

INSERT INTO `products` VALUES ('1', '1', '2');
INSERT INTO `products` VALUES ('2', '1', '3');

Result:

id  name    cheapest_id cheapest_price
1   Mark    1           2
2   Chris   (NULL)      (NULL)  

Here is the problem:

If there are many records in both tables query is very slow(minutes).

If I use INNER JOIN instead of LEFT JOIN or if I remove "ORDER BY students.name DESC" query is fast.

I have set index on student_id but still it is very slow.

Can anyone please help? I've been struggling with this for days...

Edit: The result of EXPLAIN

1   PRIMARY students    ALL 3   Using temporary; Using filesort
1   PRIMARY <derived2>  ALL 2   
2   DERIVED <derived3>  ALL 4   Using temporary; Using filesort 
3   DERIVED products    ALL 4   Using filesort

Try adding these indexes:

ALTER TABLE `students` ADD INDEX (`id`, `name`);
ALTER TABLE `products` ADD INDEX (`student_id`, `id`, `price`);

and write your query like this:

SELECT students.*,
   MIN(products.id) AS cheapest_id,
   MIN(products.price) AS cheapest_price

FROM students
LEFT JOIN products ON student_id = students.id

GROUP BY students.id
ORDER BY students.name DESC
LIMIT 50;

You should definately read about the EXPLAIN SELECT syntax and how to index properly: https://dev.mysql.com/doc/refman/5.6/en/explain.html https://dev.mysql.com/doc/refman/5.5/en/optimization-indexes.html

With EXPLAIN SELET %YOUR QUERY% you can see how MySQL is optimizing the query and how the engine is actually reading your datasets.

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM