我使用的是MySQL 5.7.18-16。
我使用的表格:
CREATE TABLE `invoice` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`transaction_id` bigint(20) unsigned NOT NULL,
`transaction_name` varchar(50) NOT NULL,
`unit_price` decimal(19,5) DEFAULT NULL,
`quantity` decimal(19,5) DEFAULT NULL,
`customer_name` varchar(50) DEFAULT NULL,
`date` bigint(20) NOT NULL,
PRIMARY KEY (`ID`),
KEY `i_transaction_id` (`transaction_id`),
KEY `i_date` (`date`)
)
CREATE TABLE `transaction` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`transaction_id` bigint(20) unsigned NOT NULL,
....
)
CREATE TABLE `hierarchy` (
`PRODUCT_ID` int(11) unsigned NOT NULL,
`PRODUCT_NAME` varchar(255) NOT NULL,
`PRODUCT_FAMILY_ID` int(11) unsigned NOT NULL,
`PRODUCT_FAMILY_NAME` varchar(255) NOT NULL,
`ORG_ID` int(11) unsigned NOT NULL,
`ORG_NAME` varchar(255) NOT NULL
...
)
CREATE TABLE `product` (
`ID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`PRODUCT_NAME` varchar(50) NOT NULL,
`COMPONENT_NAME` varchar(50) NOT NULL,
...
)
每条发票记录都与一笔交易和一个客户名称相关,而每笔交易又与一种产品和组件相关。每个产品都属于一个产品系列,每个产品系列又属于一个组织。
我的要求:
我需要根据指定的发票日期计算不同层次结构级别(组织/产品系列/产品/组件)下每个客户名称的成本和数量,并按每个客户名称的成本进行排序。
我当前的查询,用于获取每个组织下每个客户的成本/数量:
SELECT
h.org_id,
h.org_name,
h.product_family_id,
h.product_family_name,
h.product_id,
h.product_name,
p.component_id,
p.component_name,
i.transaction_id,
i.customer_name,
sum(CASE WHEN i.transaction_name = 'TEST' THEN i.quantity END) AS records,
sum(i.unit_price * i.quantity) AS cost
FROM invoice i
LEFT JOIN transaction t
ON i.transaction_id = t.transaction_id
JOIN hierarchy h
ON t.product_id = h.product_id
JOIN product p
ON t.product_id = p.id
WHERE i.date >= 1514764800000
AND i.date <= 1543622400000
GROUP BY h.org_id, i.customer_name
ORDER by i.cost DESC;
对于其他级别的计算,我只需更改 WHERE 和 GROUP BY:
//By product_family under one specific org
WHERE h.org_id = 9
AND i.date >= 1514764800000
AND i.date <= 1543622400000
GROUP BY h.product_family_id, i.customer_name
ORDER by i.cost DESC;
//By product under one specific product family
WHERE h.product_family_id = 2011
AND i.date >= 1514764800000
AND i.date <= 1543622400000
GROUP BY h.product_id, i.customer_name
ORDER by i.cost DESC;
//By component under one specific product
WHERE h.product_id = 101
AND i.date >= 1514764800000
AND i.date <= 1543622400000
GROUP BY p.component_name, i.customer_name
ORDER by i.cost DESC;
在生产数据库上运行组织级别计算大约需要 3.5 秒,这太慢了。一个主要原因是“发票”表无法使用任何索引。 (我为“i.date”创建了索引,但由于日期范围太大,因此未使用该索引。)
是否有任何可能的方法来重写此查询以优化速度?
最佳答案
Use subqueries
这通常是最坏的结果而不是更好的结果。顾名思义,关系数据库与关系(又名 JOIN)配合得很好。
很可能索引设置不正确。为了显示它,有一个EXPLAIN
命令,只需在查询的开头写下这个词,看看优化器必须告诉什么。
https://dev.mysql.com/doc/refman/8.0/en/using-explain.html
然后需要进行一些挖掘来设置架构中的索引。您还可以将 EXPLAIN 结果粘贴到您的问题中。
关于mysql - 优化SQL : How to rewrite this query to boost performance?(使用子查询,摆脱GROUP BY?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59516107/