MySQL ORDER BY 极慢。如何优化?

Posted

技术标签:

【中文标题】MySQL ORDER BY 极慢。如何优化?【英文标题】:MySQL ORDER BY extremely slow. How to optimize? 【发布时间】:2014-02-19 18:05:27 【问题描述】:

我正在为我的查询速度极慢的问题寻找解决方案,希望您能帮助我。

首先,我想做的是: 我有一张桌子,我们将其命名为 item_table,并附上一些关于商品的信息。每个项目都有一个 orderid。这里的问题是:这个订单 ID 不是唯一的。 项目的每一次变化都可以说是“逐步”记录下来的。这是一个例子:

             order_id     max_vol   remain_vol
Purchase 1   2007468329   8753      4126
Purchase 2   2007468329   8753      4122
Purchase 3   2007468329   8753      4006

稍微解释一下: 每次有人购买商品时,都会有一个新条目具有相同的订单 ID 和更改的剩余数量 (remain_vol)。 max_vol 是卖家在开始时输入的库存总量。一个项目可以有多个订单 ID,但每次卖家插入一些东西(即使它是同一个项目),它都会获得一个新的订单 ID。

我现在想做的是: 我想获得销量最高的商品。这意味着我只想得到MAX(remain_vol)MIN(remain_vol) 之间的区别,我只想得到任何东西都被出售的物品(=max_vol != remain_vol)

更具体一点: 这是我的数据表的创建表:

CREATE TABLE `data` (    
    `orderid` bigint(20) DEFAULT NULL,    
    `regionid` int(11) DEFAULT NULL,    
    `systemid` int(11) DEFAULT NULL,
    `stationid` int(11) DEFAULT NULL,
    `typeid` int(11) DEFAULT NULL,
    `bid` int(11) DEFAULT NULL,
    `price` float DEFAULT NULL,
    `minvolume` int(11) DEFAULT NULL,
    `volremain` int(11) DEFAULT NULL,
    `volenter` int(11) DEFAULT NULL,
    `issued` datetime DEFAULT NULL,
    `duration` varchar(32) DEFAULT NULL,
    `range` int(11) DEFAULT NULL,
    `reportedby` int(11) DEFAULT NULL,
    `reportedtime` datetime DEFAULT NULL,
      KEY `orderid` (`orderid`) USING BTREE,
      KEY `volremain` (`volremain`) USING BTREE,
      KEY `volenter` (`volenter`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8

我提到的列max_row在表volenter中,remain_volvolremain

此表包含大约 6000 万个条目

有人知道如何解决这个问题吗? 我已经尝试了一些查询,但它们都需要很长时间才能执行。

亲切的问候并希望得到解决方案 - 天琴座

【问题讨论】:

您尝试优化什么 SQL? 您是否设置了任何索引? @AlmaDo 我正在使用 mysql 5.6.16。 @WillP。如您所见,我已经在 orderid、volremain 和 volenter 上设置了密钥。我没有主键。 ic,我也认为 Alma 的意思是您要优化什么查询 【参考方案1】:

我认为问题在于您的表格的结构方式。当用户购买商品时,您不应该在表格中添加新条目。这种方法有很多问题。

首先,订单应该有一个唯一的订单 ID,除非有充分的理由不这样做。相反,您应该做的是使订单 ID 唯一,并为其指定字段 init_volmax_volsold。当用户购买商品时,您增加字段sold。如果您想获得销量最多的商品,请按sold 降序订购。

这样您就不会不必要地扩大表格。您的所有查询都变得更加简单和快捷。

【讨论】:

我的问题是我从 API 获取全部数据,我只想处理它们。我也不喜欢这种结构,但我对如何获取这些数据没有任何影响。我可以在获取它们之后对其进行预处理,但无论如何我必须按原样处理它们。【参考方案2】:

根据提出的问题和一些假设,希望这个答案可以帮助您。

我会在你的数据表上创建一个覆盖索引

( typeid, orderid, remain_vol )

不知道列的基础,我假设(是的,我知道假设)TYPEID 是某种关于买入或卖出的指标。如果您只寻找“出售”,那么这可以帮助查询。也有 orderid 将有助于分组,而剩余卷列可以防止需要返回原始数据页面来应用您的查询。

我也会在你的“item_table”上有一个覆盖索引,比如

(orderid, item)

所以它可以有效地连接到结果卖单,和项目(如股票名称) 也可以在那里快速参考,而无需进入原始数据页面。

也就是说,我会尝试类似的东西

SELECT
      t.item,
      SUM( PreAgg.MaxVol ) as TotalVolPerItem,
      SUM( PreAgg.MinVol ) as TotalRemainingToSell
   from
      item_table t
      JOIN (SELECT
                  d.orderid,
                  MAX( d.remain_vol ) as MaxVol,
                  MIN( d.remain_vol ) as MinVol
               from
                  data d
               where
                  d.typeid = 'sell'  (or whatever flag indicator if this is correct assumption)
               group by
                  d.orderid
               having
                  MIN( d.remain_vol ) > 0 ) PreAgg
         ON t.orderid = PreAgg.orderID
   group by
      t.item

“HAVING”子句基于剩余的最小剩余值。例如,如果订单是 500 件,然后逐渐卖到 400、300、200、150、76 件,那么剩余的 76 件将是您正在考虑的数量。

【讨论】:

正如我已经发布的那样,我无法影响我获得的数据。我从 API 中以 CSV 格式获取它。我还应该提到的是:这 6000 万个条目不是多年来收集的。他们在不到一周的时间内聚集在一起。这是我的主要问题。

以上是关于MySQL ORDER BY 极慢。如何优化?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL调优--05---多表查询优化子查询优化 ORDER BY优化GROUP BY优化分页查询优化

优化包含 WHERE 和 ORDER BY 的 MySQL UPDATE 查询?

MYSQL性能调优05_覆盖索引索引下推如何选择合适的索引Order by与Group by优化索引设计原则

mysql GROUP BY、DISTINCT、ORDER BY语句优化

如何优化这个简单的 JOIN+ORDER BY 查询?

Mysql之order by|group by 排序优化