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_vol是volremain。
此表包含大约 6000 万个条目。
有人知道如何解决这个问题吗? 我已经尝试了一些查询,但它们都需要很长时间才能执行。
亲切的问候并希望得到解决方案 - 天琴座
【问题讨论】:
您尝试优化什么 SQL? 您是否设置了任何索引? @AlmaDo 我正在使用 mysql 5.6.16。 @WillP。如您所见,我已经在 orderid、volremain 和 volenter 上设置了密钥。我没有主键。 ic,我也认为 Alma 的意思是您要优化什么查询 【参考方案1】:我认为问题在于您的表格的结构方式。当用户购买商品时,您不应该在表格中添加新条目。这种方法有很多问题。
首先,订单应该有一个唯一的订单 ID,除非有充分的理由不这样做。相反,您应该做的是使订单 ID 唯一,并为其指定字段 init_vol
、max_vol
和 sold
。当用户购买商品时,您增加字段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优化索引设计原则