MAX(ID)具有IN()比较功能

时间:2013-08-06 03:21:26

标签: mysql sql

我偶然发现了此查询的性能问题。我已经盯着这个问题很长一段时间了。这个查询实际上非常快,但是一旦数据增长,它变得越来越慢。 'Posts'表有+5百万行,'Items'表有+6000行。这些表每天都在不断增长。

SELECT Posts.itemID, Items.itemName, Items.itemImage, Items.guid, Posts.price,
Posts.quantity, Posts.date, Games.name, Items.profit FROM Items 
INNER JOIN Posts ON Items.itemID=Posts.itemID 
INNER JOIN Games ON Posts.gameID=Games.gameID 
WHERE Posts.postID IN (SELECT MAX(postID) FROM Posts GROUP BY itemID) AND Posts.gameID=:gameID 
    AND Posts.price BETWEEN :price_min AND :price_max
    AND Posts.quantity BETWEEN :quant_min AND :quant_max
    AND Items.profit BETWEEN :profit_min AND :profit_max
ORDER BY Items.profit DESC LIMIT 0, 20

在代码中我将查询和子查询分成两部分。他们一起表现得更慢。这一切都很好,直到帖子和项目中的数据开始增长。我放入的'where'语句会根据设置的过滤器进行连接。

这是我得到的EXPLAIN。 (这是没有子查询的查询) https://docs.google.com/file/d/0B1jxMdMfC35VeDBEbnJISmNGb3c/edit?usp=sharing

显示帖子的索引

+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Posts |          0 | PRIMARY  |            1 | postID      | A         |     5890249 |     NULL | NULL   |      | BTREE      |         |               |
| Posts |          1 | itemID   |            1 | itemID      | A         |       16453 |     NULL | NULL   | YES  | BTREE      |         |               |
| Posts |          1 | gameID   |            1 | gameID      | A         |          18 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

显示来自项目的索引;

+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Items |          0 | PRIMARY  |            1 | itemID      | A         |        6452 |     NULL | NULL   |      | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

显示游戏的索引;

 +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
 | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
 +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
 | Games |          0 | PRIMARY  |            1 | gameID      | A         |        2487 |     NULL | NULL   |      | BTREE      |         |               |
 +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

无论如何我可以更快地进行此查询吗?你们有什么建议吗?有没有更好的方法来编写此查询?感谢所有帮助。

EXPLAIN建议查询:

  +----+-------------+------------+--------+-----------------------+---------+---------+----------------------------+---------+----------------------------------------------+
  | id | select_type | table      | type   | possible_keys         | key     | key_len | ref                        | rows    | Extra                                        |
  +----+-------------+------------+--------+-----------------------+---------+---------+----------------------------+---------+----------------------------------------------+
  |  1 | PRIMARY     | <derived2> | ALL    | NULL                  | NULL    | NULL    | NULL                       |      19 | Using temporary; Using filesort              |
  |  1 | PRIMARY     | p          | eq_ref | PRIMARY,itemID,gameID | PRIMARY | 4       | q.postID                   |       1 |                                              |
  |  1 | PRIMARY     | i          | eq_ref | PRIMARY               | PRIMARY | 2       | db323245342342345.p.itemID |       1 | Using where                                  |
  |  1 | PRIMARY     | g          | eq_ref | PRIMARY               | PRIMARY | 4       | db323245342342345.p.gameID |       1 | Using where                                  |
  |  2 | DERIVED     | p          | ref    | itemID,gameID         | gameID  | 2       |                            | 2945124 | Using where; Using temporary; Using filesort |
  |  2 | DERIVED     | i          | eq_ref | PRIMARY               | PRIMARY | 2       | db323245342342345.p.itemID |       1 | Using where                                  |
  +----+-------------+------------+--------+-----------------------+---------+---------+----------------------------+---------+----------------------------------------------+

2 个答案:

答案 0 :(得分:2)

尝试使用JOIN重写它。像

这样的东西
SELECT p.itemID, 
       i.itemName, 
       i.itemImage, 
       i.guid, 
       p.price,
       p.quantity, 
       p.date, 
       g.name, 
       i.profit 
  FROM 
(
    SELECT MAX(postID) postID 
      FROM Posts p JOIN Items i
        ON p.itemID = i.itemID
     WHERE p.gameID = :gameID 
       AND p.price    BETWEEN :price_min  AND :price_max
       AND p.quantity BETWEEN :quant_min  AND :quant_max 
       AND i.profit   BETWEEN :profit_min AND :profit_max
     GROUP BY itemID
) q JOIN Posts p 
    ON q.postID = p.postID JOIN Items i
    ON p.itemID = i.itemID JOIN Games g
    ON p.gameID = g.gameID
 ORDER BY i.profit DESC 
 LIMIT 0, 20

答案 1 :(得分:0)

不确定这是否有帮助,但尝试将子查询移动到where子句的末尾,并尝试将其作为相关子查询。将项目上的过滤器移到顶部。

SELECT 
 p1.itemID, 
 Items.itemName, 
 Items.itemImage, 
 Items.guid, 
 p1.price,
 p1.quantity, 
 p1.date, 
 Games.name, 
 Items.profit 
FROM Items 
INNER JOIN Posts p1 ON Items.itemID=p1.itemID 
INNER JOIN Games ON p1.gameID=Games.gameID 
WHERE Items.profit BETWEEN :profit_min AND :profit_max
    AND p1.gameID=:gameID 
    AND p1.price BETWEEN :price_min AND :price_max
    AND p1.quantity BETWEEN :quant_min AND :quant_max
    AND p1.postID IN (SELECT MAX(p2.postID) FROM posts p2 WHERE p2.itemID = p1.ItemID GROUP BY p2.itemID)
ORDER BY 
 Items.profit DESC 
LIMIT 0, 20
  • 此外,请确保在帖子(itemID,gameID,postID)
  • 上创建索引