mysql - 优化SQL : How to rewrite this query to boost performance?(使用子查询,摆脱GROUP BY?)

标签 mysql sql performance query-optimization sql-optimization

我使用的是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/

相关文章:

mysql - 如何修复网络连接无法从我的数据库加载数据

php - 使用 mysqli_ 过程方法通过 foreach 循环操作 MySQL 结果

performance - MPI_Send/Recv 和 MPI_Scatter/Gather 的比较

sql-server - SQL 查询中的累积列

php - 如何找到 mySQL 行之间的相似性?

mysql 计数结果状态正确并按用户 ID 分组

sql - 查询两个相似的表并合并排序的结果

mysql - SQL 返回值 - 怎么做?

sql - 从 SQL 连接中删除镜像对

python - 为什么 "map"版本的ThreeSum这么慢?