如何提高MySQL查询的效率?

时间:2021-10-09 05:55:02

the following query executes in 0.12 seconds

以下查询在0.12秒内执行

SET @num :=0, @current_shop_id := NULL, @current_product_id := NULL;

SELECT * FROM (

SELECT fav1.user_id, @num := IF(@current_shop_id=shops.shop_id, IF(@current_product_id=products.product_id,@num,@num+1),0) AS row_number, @current_shop_id := shops.shop_id AS shop_dummy, @current_product_id := products.product_id AS product_dummy

    FROM favorites fav1 INNER JOIN
    products ON
    fav1.product_id=products.product_id AND 
    fav1.current=1 AND
    fav1.closeted=1 AND 
    fav1.user_id=30  INNER JOIN
    shops ON
    shops.shop_id = products.shop_id 

    GROUP BY fav1.product_id
    ORDER BY shops.shop ASC

    ) AS rowed_results WHERE rowed_results.row_number>=0 AND rowed_results.row_number<(0+5)

this second query executes in 0.00 seconds

第二个查询在0.00秒内执行

SELECT fav5.product_id AS product_id, SUM(CASE 
WHEN fav5.current = 1 AND fav5.closeted = 1 THEN 1
WHEN fav5.current = 1 AND fav5.closeted = 0 THEN -1
ELSE 0
END) AS favorites_count
FROM favorites fav5
GROUP BY fav5.product_id 

However, combining them as follows results in a query that executes in over 11 seconds

但是,如下组合它们会导致查询执行超过11秒

SET @num :=0, @current_shop_id := NULL, @current_product_id := NULL;

SELECT * FROM (

SELECT fav1.user_id, @num := IF(@current_shop_id=shops.shop_id, IF(@current_product_id=products.product_id,@num,@num+1),0) AS row_number, @current_shop_id := shops.shop_id AS shop_dummy, @current_product_id := products.product_id AS product_dummy

    FROM

    #limit results to products favorited by the user whose closet is being shown
    favorites fav1 INNER JOIN

    products ON
    fav1.product_id=products.product_id AND 
    fav1.current=1 AND
    fav1.closeted=1 AND 
    fav1.user_id=30  INNER JOIN

    shops ON
    shops.shop_id = products.shop_id 

    LEFT JOIN

    # this LEFT JOIN associates favorites_count table (adds up the scores for all the products in the favorites table)
    (
    SELECT fav5.product_id AS product_id, SUM(CASE 
    WHEN fav5.current = 1 AND fav5.closeted = 1 THEN 1
    WHEN fav5.current = 1 AND fav5.closeted = 0 THEN -1
    ELSE 0
    END) AS favorites_count
    FROM favorites fav5
    GROUP BY fav5.product_id 

    ) AS fav6 ON products.product_id=fav6.product_id

    GROUP BY fav1.product_id
    ORDER BY shops.shop ASC

    ) AS rowed_results WHERE rowed_results.row_number>=0 AND rowed_results.row_number<(0+5)

How can I speed it up?

我怎样才能加快速度?

EXPLAIN EXTENDED for the first query is

第一个查询的EXPLAIN EXTENDED是

+----+-------------+------------+--------+------------------------------------------------+---------+---------+------------------------------+------+----------+----------------------------------------------+
| id | select_type | table      | type   | possible_keys                                  | key     | key_len | ref                          | rows | filtered | Extra                                        |
+----+-------------+------------+--------+------------------------------------------------+---------+---------+------------------------------+------+----------+----------------------------------------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL                                           | NULL    | NULL    | NULL                         | 8846 |   100.00 | Using where                                  |
|  2 | DERIVED     | fav1       | ref    | user_id,user_id_2,product_id,closeted          | user_id | 4       |                              | 9624 |   100.00 | Using where; Using temporary; Using filesort |
|  2 | DERIVED     | products   | eq_ref | PRIMARY,shop_id,shop_id_2,product_id,shop_id_3 | PRIMARY | 4       | my_database.fav1.product_id  |    1 |   100.00 |                                              |
|  2 | DERIVED     | shops      | eq_ref | PRIMARY                                        | PRIMARY | 4       | my_database.products.shop_id |    1 |   100.00 |                                              |
+----+-------------+------------+--------+------------------------------------------------+---------+---------+------------------------------+------+----------+----------------------------------------------+
4 rows in set, 1 warning (0.12 sec)

SHOW WARNINGS for the first query is

显示第一个查询的警告是

+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | select `rowed_results`.`user_id` AS `user_id`,`rowed_results`.`row_number` AS `row_number`,`rowed_results`.`shop_dummy` AS `shop_dummy`,`rowed_results`.`product_dummy` AS `product_dummy` from (select `my_database`.`fav1`.`user_id` AS `user_id`,(@num:=if(((@current_shop_id) = `my_database`.`shops`.`shop_id`),if(((@current_product_id) = `my_database`.`products`.`product_id`),(@num),((@num) + 1)),0)) AS `row_number`,(@current_shop_id:=`my_database`.`shops`.`shop_id`) AS `shop_dummy`,(@current_product_id:=`my_database`.`products`.`product_id`) AS `product_dummy` from `my_database`.`favorites` `fav1` join `my_database`.`products` join `my_database`.`shops` where ((`my_database`.`fav1`.`user_id` = 30) and (`my_database`.`products`.`product_id` = `my_database`.`fav1`.`product_id`) and (`my_database`.`shops`.`shop_id` = `my_database`.`products`.`shop_id`) and (`my_database`.`fav1`.`current` = 1) and (`my_database`.`fav1`.`closeted` = 1)) group by `my_database`.`fav1`.`product_id` order by `my_database`.`shops`.`shop`) `rowed_results` where ((`rowed_results`.`row_number` >= 0) and (`rowed_results`.`row_number` < 5)) |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

EXPLAIN EXTENDED for the second query is

第二个查询的EXPLAIN EXTENDED是

+----+-------------+-------+------+---------------+------+---------+------+-------+----------+---------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | filtered | Extra                           |
+----+-------------+-------+------+---------------+------+---------+------+-------+----------+---------------------------------+
|  1 | SIMPLE      | fav5  | ALL  | NULL          | NULL | NULL    | NULL | 16377 |   100.00 | Using temporary; Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+-------+----------+---------------------------------+
1 row in set, 1 warning (0.00 sec)

SHOW WARNINGS for the second query is

显示第二个查询的警告是

+-------+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                                                                                                                                                                            |
+-------+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | select `my_database`.`fav5`.`product_id` AS `product_id`,sum((case when ((`my_database`.`fav5`.`current` = 1) and (`my_database`.`fav5`.`closeted` = 1)) then 1 when ((`my_database`.`fav5`.`current` = 1) and (`my_database`.`fav5`.`closeted` = 0)) then -(1) else 0 end)) AS `favorites_count` from `my_database`.`favorites` `fav5` group by `my_database`.`fav5`.`product_id` |
+-------+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

EXPLAIN EXTENDED for the final query is

最终查询的EXPLAIN EXTENDED是

+----+-------------+------------+--------+------------------------------------------------+-----------+---------+------------------------------+-------+----------+----------------------------------------------+
| id | select_type | table      | type   | possible_keys                                  | key       | key_len | ref                          | rows  | filtered | Extra                                        |
+----+-------------+------------+--------+------------------------------------------------+-----------+---------+------------------------------+-------+----------+----------------------------------------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL                                           | NULL      | NULL    | NULL                         |  8846 |   100.00 | Using where                                  |
|  2 | DERIVED     | fav1       | ref    | user_id,user_id_2,product_id,closeted          | user_id_2 | 4       |                              |  9624 |   100.00 | Using where; Using temporary; Using filesort |
|  2 | DERIVED     | products   | eq_ref | PRIMARY,shop_id,shop_id_2,product_id,shop_id_3 | PRIMARY   | 4       | my_database.fav1.product_id  |     1 |   100.00 |                                              |
|  2 | DERIVED     | shops      | eq_ref | PRIMARY                                        | PRIMARY   | 4       | my_database.products.shop_id |     1 |   100.00 |                                              |
|  2 | DERIVED     | <derived3> | ALL    | NULL                                           | NULL      | NULL    | NULL                         | 15764 |   100.00 |                                              |
|  3 | DERIVED     | fav5       | ALL    | NULL                                           | NULL      | NULL    | NULL                         | 16377 |   100.00 | Using temporary; Using filesort              |
+----+-------------+------------+--------+------------------------------------------------+-----------+---------+------------------------------+-------+----------+----------------------------------------------+
6 rows in set, 1 warning (11.50 sec)

SHOW WARNINGS for the final query is

显示最终查询的警告是

+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | select `rowed_results`.`user_id` AS `user_id`,`rowed_results`.`row_number` AS `row_number`,`rowed_results`.`shop_dummy` AS `shop_dummy`,`rowed_results`.`product_dummy` AS `product_dummy` from (select `my_database`.`fav1`.`user_id` AS `user_id`,(@num:=if(((@current_shop_id) = `my_database`.`shops`.`shop_id`),if(((@current_product_id) = `my_database`.`products`.`product_id`),(@num),((@num) + 1)),0)) AS `row_number`,(@current_shop_id:=`my_database`.`shops`.`shop_id`) AS `shop_dummy`,(@current_product_id:=`my_database`.`products`.`product_id`) AS `product_dummy` from `my_database`.`favorites` `fav1` join `my_database`.`products` join `my_database`.`shops` left join (select `my_database`.`fav5`.`product_id` AS `product_id`,sum((case when ((`my_database`.`fav5`.`current` = 1) and (`my_database`.`fav5`.`closeted` = 1)) then 1 when ((`my_database`.`fav5`.`current` = 1) and (`my_database`.`fav5`.`closeted` = 0)) then -(1) else 0 end)) AS `favorites_count` from `my_database`.`favorites` `fav5` group by `my_database`.`fav5`.`product_id`) `fav6` on(((`my_database`.`products`.`product_id` = `my_database`.`fav1`.`product_id`) and (`fav6`.`product_id` = `my_database`.`fav1`.`product_id`))) where ((`my_database`.`fav1`.`user_id` = 30) and (`my_database`.`products`.`product_id` = `my_database`.`fav1`.`product_id`) and (`my_database`.`shops`.`shop_id` = `my_database`.`products`.`shop_id`) and (`my_database`.`fav1`.`current` = 1) and (`my_database`.`fav1`.`closeted` = 1)) group by `my_database`.`fav1`.`product_id` order by `my_database`.`shops`.`shop`) `rowed_results` where ((`rowed_results`.`row_number` >= 0) and (`rowed_results`.`row_number` < 5)) |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

1 个解决方案

#1


1  

Using a subquery creates a temporary table without any indexes. You're always doing a full table scan when joining the subqueries.

使用子查询可创建不带任何索引的临时表。加入子查询时,您总是在进行全表扫描。

Without having looking fully into your SQL, creating a temporary table with a primary key will probably work.

如果没有完全了解您的SQL,使用主键创建临时表可能会有效。

CREATE TEMPORARY TABLE fav6 (product_id INT, favorites_count INT, PRIMARY KEY (product_id));

INSERT INTO fav6
    SELECT fav5.product_id AS product_id, SUM(CASE 
        WHEN fav5.current = 1 AND fav5.closeted = 1 THEN 1
        WHEN fav5.current = 1 AND fav5.closeted = 0 THEN -1
        ELSE 0
        END) AS favorites_count
    FROM favorites fav5
    GROUP BY fav5.product_id;

SET @num :=0, @current_shop_id := NULL, @current_product_id := NULL;

SELECT * FROM (

SELECT fav1.user_id, @num := IF(@current_shop_id=shops.shop_id, IF(@current_product_id=products.product_id,@num,@num+1),0) AS row_number, @current_shop_id := shops.shop_id AS shop_dummy, @current_product_id := products.product_id AS product_dummy

    FROM

    #limit results to products favorited by the user whose closet is being shown
    favorites fav1 INNER JOIN

    products ON
    fav1.product_id=products.product_id AND 
    fav1.current=1 AND
    fav1.closeted=1 AND 
    fav1.user_id=30  INNER JOIN

    shops ON
    shops.shop_id = products.shop_id 

    LEFT JOIN

    fav6 ON products.product_id=fav6.product_id

    GROUP BY fav1.product_id
    ORDER BY shops.shop ASC

    ) AS rowed_results WHERE rowed_results.row_number>=0 AND rowed_results.row_number<(0+5)

#1


1  

Using a subquery creates a temporary table without any indexes. You're always doing a full table scan when joining the subqueries.

使用子查询可创建不带任何索引的临时表。加入子查询时,您总是在进行全表扫描。

Without having looking fully into your SQL, creating a temporary table with a primary key will probably work.

如果没有完全了解您的SQL,使用主键创建临时表可能会有效。

CREATE TEMPORARY TABLE fav6 (product_id INT, favorites_count INT, PRIMARY KEY (product_id));

INSERT INTO fav6
    SELECT fav5.product_id AS product_id, SUM(CASE 
        WHEN fav5.current = 1 AND fav5.closeted = 1 THEN 1
        WHEN fav5.current = 1 AND fav5.closeted = 0 THEN -1
        ELSE 0
        END) AS favorites_count
    FROM favorites fav5
    GROUP BY fav5.product_id;

SET @num :=0, @current_shop_id := NULL, @current_product_id := NULL;

SELECT * FROM (

SELECT fav1.user_id, @num := IF(@current_shop_id=shops.shop_id, IF(@current_product_id=products.product_id,@num,@num+1),0) AS row_number, @current_shop_id := shops.shop_id AS shop_dummy, @current_product_id := products.product_id AS product_dummy

    FROM

    #limit results to products favorited by the user whose closet is being shown
    favorites fav1 INNER JOIN

    products ON
    fav1.product_id=products.product_id AND 
    fav1.current=1 AND
    fav1.closeted=1 AND 
    fav1.user_id=30  INNER JOIN

    shops ON
    shops.shop_id = products.shop_id 

    LEFT JOIN

    fav6 ON products.product_id=fav6.product_id

    GROUP BY fav1.product_id
    ORDER BY shops.shop ASC

    ) AS rowed_results WHERE rowed_results.row_number>=0 AND rowed_results.row_number<(0+5)