我需要查询我的所有产品(sku's)他们最新的库存数量 我有一个表(称为“股票”),其中包含315k +记录,包含此信息(对于大多数sku来说,每天都会添加一批新数据)。参考数据在另一个表中(称为“stockfile”)。
这是查询:
SELECT s1 . * , f1 . *
FROM stock s1
JOIN stockfile f1 ON ( s1.stockfileid = f1.stockfileid )
LEFT OUTER JOIN ( stock s2
JOIN stockfile f2 ON ( s2.stockfileid = f2.stockfileid )
) ON ( s1.sku = s2.sku
AND ( f1.date < f2.date
OR f1.date = f2.date
AND f1.stockfileid < f2.stockfileid) )
WHERE s2.sku IS NULL
这些是表格定义
SHOW CREATE TABLE
股票:
CREATE TABLE `stock` (
`stockid` bigint(20) NOT NULL AUTO_INCREMENT,
`sku` char(25) NOT NULL,
`quantity` int(5) NOT NULL,
`creationdate` datetime NOT NULL,
`stockfileid` smallint(5) unsigned NOT NULL,
`touchdate` datetime NOT NULL,
PRIMARY KEY (`stockid`),
KEY `stock_sku` (`sku`),
KEY `stock_stockfileid` (`stockfileid`)
) ENGINE=MyISAM AUTO_INCREMENT=316039 DEFAULT CHARSET=latin1
SHOW CREATE TABLE
stockfile:
CREATE TABLE `stockfile` (
`stockfileid` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`filename` varchar(25) NOT NULL,
`creationdate` datetime DEFAULT NULL,
`touchdate` datetime DEFAULT NULL,
`date` datetime DEFAULT NULL,
`begindate` datetime DEFAULT NULL,
`enddate` datetime DEFAULT NULL,
PRIMARY KEY (`stockfileid`),
KEY `stockfile_date` (`date`)
) ENGINE=MyISAM AUTO_INCREMENT=266 DEFAULT CHARSET=latin1
没有任何额外的索引需要......永远。我添加了这些并加速了大约250秒:
CREATE INDEX stock_sku ON stock(sku);
CREATE INDEX stock_stockfileid ON stock(stockfileid);
CREATE INDEX stockfile_date ON stockfile(date);
这是原始查询的EXPLAIN
,带有这些索引。
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE s1 ALL stock_stockfileid NULL NULL NULL 316038
1 SIMPLE f1 eq_ref PRIMARY PRIMARY 2 kompare.s1.stockfileid 1
1 SIMPLE s2 ref stock_sku,stock_stockfileid stock_sku 25 kompare.s1.sku 12 Using where
1 SIMPLE f2 eq_ref PRIMARY,stockfile_date PRIMARY 2 kompare.s2.stockfileid 1
还有另一种方法可以加快速度吗?
答案 0 :(得分:4)
我不确定我的查询是否正确,但如果可以安全地假设最大日期也有一个最大的stockfileid(就像你的OR条件一半建议的话)也许像这样的查询会有所帮助:
SELECT s1.*, f1.*
FROM
stock s1 JOIN stockfile f1 USING (stockfileid)
JOIN (
SELECT sku, max(date) AS maxdate, max(stockfileid) AS maxfileid
FROM stock JOIN stockfile USING (stockfileid)
GROUP BY sku
) AS dfi ON (s1.sku,f1.date,f1.stockfileid)=(dfi.sku,maxdate,maxfileid);
不确定这是否是您想要的以及它是否更快,但它应该是。另一方面,如果fileid拥有全部内容,则根本不需要考虑日期。无论如何,我认为这种预过滤可能有助于作为起点。
答案 1 :(得分:3)
my.cnf中的默认值通常是根据今天的标准为具有非常小内存的系统设置的。如果您使用这些默认值,那么这可能是寻找性能提升的最佳位置。确保您将所有可以节省的内存分配给MySQL。
mysqltuner可以为在可以使用它的MySQL的各个部分之间分配内存提供良好的启动建议。
如果在添加大部分数据之前创建了索引,则可以通过在表上执行ANALYZE TABLE来获得巨大的改进。我只看到一个查询从24秒下降到1秒。
您的EXPLAIN表明MySQL在缩小搜索范围之前正在进行表扫描以满足WHERE s2.sku IS NULL
。这非常昂贵。
f1.date < f2.date
OR f1.date = f2.date
应该可以重写为
f1.date <= f2.date
虽然我怀疑这对优化器很重要。
您能用简单的英语解释您要对查询做什么吗?这可能有助于阐明如何简化它。
答案 2 :(得分:2)
数据的规范化将大大加快查询速度,此外,如果您在慢速计算机上运行,这将对结果返回的速度产生不利影响。向我展示一个对该表的示例查询,然后我可以更好地了解您在该角度上的尝试。
答案 3 :(得分:2)
我不确定这是否是您可以对您的应用进行的操作,但不是每次运行查询时计算每个sku的数量,将sku和数量存储在单独的内容会更有效表,然后只要收到新的stockfile就更新数据。这样你就会产生每个得分文件计算一次的成本,而不是每个查询计算一次。计算这个是一个前期成本,但它可以为您节省很多。