2013-02-01 60 views
1

以下查询执行0.12秒我该如何提高MySQL查询的效率?

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) 

此第二查询中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 

然而,将它们结合起来,如下所示的,超过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) 
执行的查询结果

我该如何加快速度?

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警告是

+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| 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用于第二查询是

+----+-------------+-------+------+---------------+------+---------+------+-------+----------+---------------------------------+ 
| 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警告第二个查询是

+-------+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| 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延长了最终的查询是

+----+-------------+------------+--------+------------------------------------------------+-----------+---------+------------------------------+-------+----------+----------------------------------------------+ 
| 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警告是

+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| 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)) | 
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
+0

使用JOIN,而不是选择(SELECT FROM –

+0

@nathanhayfield我怕我不明白,我怎么可以使用JOIN同时保留行号。 – jela

回答

1

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

没有完全查看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) 
+0

此执行0.15秒,所以这是一个很大的当我测试它时,我发现它产生了比我原来的查询更大的结果集,如果我通过行号删除了外部查询限制结果,这种情况就不会发生,于是我注意到这个外部查询实际上并不像我预期(即对于给定的shop_id值,从具有不同product_id值的所有行开始,从0开始编号)。我注意到,如果我检索特定商店的结果,例如shops.shop = 48,结果会正确列举,但而不是其他的全部结果。是否有一些明显的原因? – jela

+0

我想通了,这是因为我[错误应用row_number值](http://stackoverflow.com/questions/14664516/why-is-this-mysql-query-producing-the-wrong-row-numbers)。最后一个问题是,在使用临时表时,是否有必要在执行查询后添加“DROP TABLE fav6”? – jela

+0

很酷,你有它正常工作。当连接关闭时该表会自动删除,如果需要,可以运行DROP TEMPORARY TABLE fav6。 ['TEMPORARY'](http://dev.mysql.com/doc/refman/5.5/en/drop-table.html)将确保您不会意外删除真正的表格。 –