Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql MAX(ID)与IN()比较函数性能_Mysql_Sql - Fatal编程技术网

Mysql MAX(ID)与IN()比较函数性能

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

我在这个查询中偶然发现了一个性能问题。我已经盯着这个问题看了很长时间了,现在我抓狂了。这个查询实际上在某一点上相当快,但一旦数据增长,它就会变得越来越慢。“Posts”表有+500万行,“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
在代码中,我将查询和子查询分为两部分。他们一起表现得比较慢。这一切都很好,直到帖子和项目中的数据开始增长。我放在**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