Mysql MAX(ID)与IN()比较函数性能
我在这个查询中偶然发现了一个性能问题。我已经盯着这个问题看了很长时间了,现在我抓狂了。这个查询实际上在某一点上相当快,但一旦数据增长,它就会变得越来越慢。“Posts”表有+500万行,“Items”表有+6000行。这些表格每天都在不断增长Mysql MAX(ID)与IN()比较函数性能,mysql,sql,Mysql,Sql,我在这个查询中偶然发现了一个性能问题。我已经盯着这个问题看了很长时间了,现在我抓狂了。这个查询实际上在某一点上相当快,但一旦数据增长,它就会变得越来越慢。“Posts”表有+500万行,“Items”表有+6000行。这些表格每天都在不断增长 SELECT Posts.itemID, Items.itemName, Items.itemImage, Items.guid, Posts.price, Posts.quantity, Posts.date, Games.name, Items.pro
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
在代码中,我将查询和子查询分为两部分。他们一起表现得比较慢。这一切都很好,直到帖子和项目中的数据开始增长。我放在**get中的“where”语句根据设置的过滤器进行连接
这是我得到的解释。这是没有子查询的查询
显示来自帖子的索引:
显示项目的索引
显示来自游戏的索引
是否有其他方法可以加快查询速度?你们有什么建议吗?是否有更好的方法编写此查询?感谢所有的帮助
解释提议的查询:
+----+-------------+------------+--------+-----------------------+---------+---------+----------------------------+---------+----------------------------------------------+
| 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 |
+----+-------------+------------+--------+-----------------------+---------+---------+----------------------------+---------+----------------------------------------------+
尝试用JOIN重写它。差不多
选择p.itemID,
i、 项目名称,
i、 itemImage,
i、 guid,
p、 价格,
p、 数量,
p、 日期,
g、 名字,
i、 利润
从…起
选择MAXpostID postID
从Posts p连接项目i
在p.itemID=i.itemID上
其中p.gameID=:gameID
和p.price介于:price_min和:price_max之间
和p.介于:quant_min和:quant_max之间的数量
i.利润介于:利润最小值和:利润最大值之间
按项目ID分组
q加入帖子p
在q.postID=p.postID连接项目i上
在p.itemID=i.itemID上加入游戏g
在p.gameID=g.gameID上
按i.利润说明订购
限制0,20
不确定这是否有帮助,但请尝试将子查询移动到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
另外,请确保在PostsitemID、gameID和postID上创建索引
也许你的数据已经过时了。使用ANALYZE TABLE命令为查询中的每个表更新它们。我也这么认为,但是它说“OK”从Posts GROUP BY itemID中选择MAXpostID对我来说毫无用处。我之所以对它们进行分组,是因为Posts表可以多次使用相同的itemID,基本上是跟踪每日统计数据,我们需要最新的帖子来获取表中的最新信息。@roadrunner有帮助吗?嗨,peterm。我只是在测试这个查询。它的表现似乎与另一个相似。执行大约需要5-6秒。是不是别的什么原因让这些问题变得缓慢了?@roadrunner-Hi。您是否对所加入的列具有所有必要的索引,并在WHERE子句中进行筛选?你能对提议的查询进行完整的解释并显示帖子中的索引吗;显示项目的索引;文本格式?谢谢@peterm。我已经按你的要求做了。所有信息都应该在主帖子中。嗨@sl0ppy!我试过你的问题,但也花了不少时间。我假设在400多万行的表上执行max需要一些时间。也许我可以通过重组数据库找到一个不同的解决方案。@roadrunner:你有我建议的索引吗?请注意,它是一个复合索引,而不是每列上的单个索引。此外,是的,这将是缓慢的,除非你能找到一种方法,过滤掉最大的子查询多一点。通常情况下,我建议您使用PostID DESC创建索引,但MySQL不支持DESC order。很抱歉回复太慢。谢谢你这么耐心。使用综合指数确实要快得多。不过我决定换一种方式。决定对其中一个表进行非规范化。
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| 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 | | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
+----+-------------+------------+--------+-----------------------+---------+---------+----------------------------+---------+----------------------------------------------+
| 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 |
+----+-------------+------------+--------+-----------------------+---------+---------+----------------------------+---------+----------------------------------------------+
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