Mysql 如何提升 Group by + Having 型子查询的查询速度(千万级别数据)

2015-03-18 16:59:41 +08:00
 abcfyk
如题所示。
有一出货记录表 outDetail。表中大约3000W条数据。
字段如 outId, skuId, outDate, outQty等。

现想查出最近三个月没有出货的SKU号。有如下SQL:
select skuId from outDetail group by skuId having max(outDate) < date_sub(curdate(), interval 90 day);

查询速度很慢。请问如何优化?
10988 次点击
所在节点    MySQL
25 条回复
npc0der
2015-03-18 17:11:32 +08:00
额 找出 最近90天出库的 那批 skuId

然后找出 整库的 skuId

差集。。。。skuId 有索引的吧 应该会很快。。。。
abcfyk
2015-03-18 17:16:20 +08:00
@npc0der 目前是这么做的。但是目前SKU总数100W+, 最近90天有出货的大约30W。用PHP来筛选。但是我想尽量能在mysql层面做就在mysql里面做算了。用php脚本跑的话效率太差了。
takatost
2015-03-18 17:20:50 +08:00
这么大级别的数据量为何不分表
Septembers
2015-03-18 17:27:40 +08:00
1. 建议做表分区
2. 给时间做索引
Septembers
2015-03-18 17:27:58 +08:00
1. 建议做表分区
2. 给时间(outDate)做索引
Septembers
2015-03-18 17:28:50 +08:00
@takatost 如果是PgSQL单表 15亿都压力不大
jk2r
2015-03-18 17:30:30 +08:00
你先贴出create的sql/explain的结果,大家才好帮你看
Mac
2015-03-18 18:33:59 +08:00
LZ先说说慢到什么程度?
abcfyk
2015-03-18 18:42:52 +08:00
@takatost 因为有很多统计数据的业务需求需要所有出货记录一起统计。类似这种需求。。所以没有统计。。
abcfyk
2015-03-18 18:43:47 +08:00
@Septembers 表分区。。暂时比较难,outDate 已加索引。。
abcfyk
2015-03-18 18:55:18 +08:00
@jk2r

类似这种:
CREATE TABLE `outDetail`{
`id` int(11) NOT NULL AUTO_INCREMENT,
`outId` int(11) NOT NULL,
`skuId` varchar(30) NOT NULL,
`outDate` datetime NOT NULL,
`outQty` int(11) NOT NULL
PRIMARY KEY (`id`),
KEY `indexOutId` (`outId`),
KEY `indexSkuId` (`skuId`),
KEY `indexOutDate` (`outDate`),
}ENGINE=InnoDB DEFAULT CHARSET=utf8


explain 结果大概如下
+----+-------------+-----------------+-------+---------------+-------------+---------+------+----------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+-------+---------------+-------------+---------+------+----------+-------+
| 1 | SIMPLE | outDetail | index | NULL | IndexSkuId | 92 | NULL | 23980757 | |
+----+-------------+-----------------+-------+---------------+-------------+---------+------+----------+-------+
abcfyk
2015-03-18 18:57:31 +08:00
@Mac PHP把全部100W 的 SKU查出来存入变量,大概需要一小时。查找最近三个月出货的SKU存到变量又要一小时。光取数据还没求差集的时间就2小时了。
O14
2015-03-18 19:13:30 +08:00
不知我理解的对不?
SELECT DISTINCT skuId FROM outDetail WHERE outDate < date_sub(curdate(), interval 90 day) AND skuId NOT IN (SELECT DISTINCT skuId FROM outDetail WHERE outDate > date_sub(curdate(), interval 90 day));
takatost
2015-03-18 19:53:40 +08:00
@Septembers 可惜是mysql
sohoer
2015-03-18 20:59:09 +08:00
select skuId from (select skuId from outDetail where outDate > date_sub(curdate(), interval 90 day)) as t group by skuId;
frankzeng
2015-03-18 21:39:46 +08:00
如果不是严格实时要求,你可以写个脚本把跑出来的数据存到另一张表里。
cevincheung
2015-03-18 21:49:53 +08:00
只有我来说上检索引擎吗?

https://www.elastic.co
yangqi
2015-03-18 22:51:26 +08:00
难道不是简单的一句
SELECT DISTINCT skuId FROM outDetail WHERE outDate < date_sub(curdate(), interval 90 day);

WispZhan
2015-03-18 23:08:30 +08:00
Group by + Having 本身就没有效率可言吧……
npc0der
2015-03-19 09:02:21 +08:00
取出你说的 30w 的这些skuId 不会很慢吧 3000w 的表不算很大啊 我这张表 38,643,224 记录 取出skuId 你到临时表里面去

或者你这样 skuID 你 100w 的那张表 加一个字段 标示为 90天内出库了 更新下 这样 筛选出来也快 做分页查询 其他业务也方便。


100w 表加个字段不会很慢的 表大了就不容易加字段了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/177804

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX