【问题标题】:Uptimize select product details each customer purchased from sales tables优化每位客户从销售表中购买的精选产品详细信息
【发布时间】:2019-06-18 18:58:22
【问题描述】:

我有 4 个表,客户、产品、销售和销售项目。我使用下面的查询从中提取数据。

SELECT (
            SELECT c.name 
            FROM Customers c
            WHERE s.customer_id=c.id
            ) customer
    ,(
        Select group_concat(description)
        FROM (
            SELECT si.id
                ,si.sale_id
                ,concat("x", si.Qty, " ", p.name, " ",(si.total)) description
            FROM Sale_Items si
            LEFT JOIN Products p ON p.id = si.product_id
            ) p
        where s.id = Sale_ID
        GROUP BY Sale_ID
        ) detail,
                            s.total
FROM Sales s

查询会产生结果,但只有 2000 条记录会变得很慢(需要 114 秒才能完成)

Customer    Product            Total
--------------------------------------
James       x1 ItemA 10.00  75.00
            x3 ItemB 15.00
            x1 ItemC 20.00

Mark        x2 ItemA 10.00  50.00
            x2 ItemB 15.00

Bisi        x1 ItemC 20.00  30.00
            x2 ItemA 10.00

我怎样才能让它更快?

这里已经尝试过了

https://www.db-fiddle.com/f/pkL2HtsT659EXgRSevFSAm/4

【问题讨论】:

  • 考虑处理应用代码中数据显示的问题。我怀疑生成的查询会更简单更快。
  • 实现内联视图p 的成本会很高,因为我们要为销售返回的每一行都这样做。外部查询中的谓词不会被推送到视图定义中(可能在最新版本的 MySQL 中有所更改)。

标签: mysql sql performance select


【解决方案1】:

如果我们想坚持使用相关子查询,我们可以消除内联视图p

对于从Sales 检索到的每一行,这都会实现。外部查询中WHERE 子句中的谓词不会“下推”到视图中。所以物化视图(或 MySQL 用语中的“派生表”)将是一个完整的集合,我们将从中挑选几行。我们将对Sales 中的每一行重复此操作。

展开该派生表应该会给我们带来一些性能优势。对于从Sales 返回的少量行,这将是一种合理的方法,并定义了合适的索引。也就是说,如果我们使用WHERE 子句限制外部查询检查的行数。由于行数很多,这些相关的子查询会拖累性能。

SELECT ( SELECT c.name 
           FROM Customers c
          WHERE c.id = s.customer_id
       ) AS customer

     , ( SELECT GROUP_CONCAT(CONCAT('x',si.Qty,' ',p.name,' ',si.total) ORDER BY p.name SEPARATOR '\r\n')
           FROM Sale_Items si
           LEFT
           JOIN Products p
             ON p.id = si.product_id
          WHERE si.sale_id = s.id
       ) AS detail

     , s.total

  FROM Sales s

 WHERE ... 

 ORDER
    BY ...

如果查询返回来自Sales 的所有行并且我们正在执行整个bloomin 集,那么我倾向于避免相关子查询。 (这是因为外部查询返回的每一行都会执行子查询。就性能而言,这些子查询会吃掉我们的午餐,并返回大量的行。)

假设idcustomers 中是唯一的,我们通常会使用连接操作更好。

SELECT c.name AS customer
     , d.detail
     , s.total
  FROM Sales s
  LEFT
  JOIN Customers c
    ON c.id = s.customer_id
  LEFT
  JOIN ( SELECT si.sale_id
              , GROUP_CONCAT(CONCAT('x',si.Qty,' ',p.name,' ',si.total) ORDER BY p.name SEPARATOR '\r\n') AS detail
           FROM Sale_Items si
           LEFT
           JOIN Products p
             ON p.id = si.product_id
          GROUP
             BY si.sale_id
       ) d
    ON d.sale_id = s.id
 ORDER
    BY ...

内联视图d 在大型集合中会很昂贵;但至少我们只进行一次查询,将结果具体化为“派生表”。然后外部查询可以运行,并从派生表中检索行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-29
    • 2016-04-06
    • 2011-11-11
    • 2014-08-14
    相关资源
    最近更新 更多