【问题标题】:MySQL - Slow Query when kept a ViewMySQL - 保持视图时查询慢
【发布时间】:2019-02-20 09:07:51
【问题描述】:

在 MySQL 中,我有两个表之间的简单连接。像

select a.id, SUM(b.qty) from a inner join b on a.id=b.id
where a.id=12345
group by a.id

它作为查询正常运行。但是当我保留查询时

select a.id, SUM(b.qty) from a inner join b on a.id=b.id
group by a.id

在名为view_ab 的视图中,当我在视图上运行以下查询时,该视图会花费大量时间。

select * from view_ab where id = 12345

这两张桌子都是大桌子。无法弄清楚性能下降的原因。请帮助解决此性能问题

编辑: 这是视图 SQL

CREATE VIEW view_ab AS SELECT 
r.drid            AS drid,
SUM(s.return_qty) AS return_qty
FROM tbl_deliveryroute r INNER JOIN tbl_deliveryroute_sku s ON r.drid = 
s.drid GROUP BY r.drid;

这是查询

SELECT 
r.drid            AS drid,
SUM(s.return_qty) AS return_qty
FROM tbl_deliveryroute r INNER JOIN tbl_deliveryroute_sku s ON r.drid = 
s.drid WHERE r.drid=12718651
GROUP BY r.drid;

这是 VIEW 上的查询

SELECT * FROM view_ab WHERE drid=12718651;

视图的执行计划

EXPLAIN EXTENDED SELECT * FROM view_ab WHERE drid=12718651;

身份证 选择类型 桌子 分区 类型 可能的键 钥匙 key_len 参考 行 过滤 额外的

1 基本的 (空值) 参考 4 常量 10 100.00 (空)

2 衍生的 s (空值) 全部 idx_tbl_deliverroute_sku_drid (空值) (空值) (空值) 15060913 100.00 使用临时的;使用文件排序

2 衍生的 r (空值) eq_ref PRIMARY,FK_tbl_deliveryroute_1 基本的 4 humdemotest.s.drid 1 100.00 使用索引

EXPLAIN EXTENDED  SELECT 
r.drid            AS drid,
SUM(s.return_qty) AS return_qty
FROM tbl_deliveryroute r INNER JOIN tbl_deliveryroute_sku s ON r.drid = 
s.drid WHERE r.drid=12718651
GROUP BY r.drid;

身份证 选择类型 桌子 分区 类型 可能的键 钥匙 key_len 参考 行 过滤 额外的

1 简单的 r (空值) 常量 基本的 基本的 4 常量 1 100.00 使用索引

1 简单的 s (空值) 参考 idx_tbl_deliverroute_sku_drid idx_tbl_deliverroute_sku_drid 4 常量 22 100.00 (空)

【问题讨论】:

  • 请检查两个查询的执行计划,方法是在每个查询前面加上EXPLAIN。请注意,对于前者,MySQL 可能先进行 filtering 然后 grouping,而对于后者,反之亦然,这可以解释问题。 (如果是这种情况,您可以改用存储过程。)
  • 感谢您的回复。这些陈述中的每一个的计划都是不同的。此外,我们最近设置了生产环境的暂存环境。这种观点被广泛使用。迁移到存储过程意味着很多工作
  • 同样的视图在生产环境中运行良好。仅在暂存环境中会遇到视图问题。
  • 发布EXPLAIN EXTENDED 查询结果(可能会审查敏感信息)会有所帮助。此外,可能值得检查暂存环境和生产环境的两种模式是否相同,尤其是 KEY / INDEX 部分。
  • 我建议您编辑您的问题并将结果放在那里(以及您在 cmets 中详细说明的所有其他内容)。提前致谢。

标签: mysql sql


【解决方案1】:

据我所见,您甚至不需要连接,因为您正在处理 A-B 的同一键列上的连接,该键已存在于表 B 中,只需按此查询分组即可。另外,我会在您的 DeliveryRoute_SKU 的路线 ID 列上建立一个索引

SELECT 
      s.drid,
      sum( s.return_qty ) Return_Qty
   from
      tbl_DeliveryRoute_Sku s
   where
      s.drID = 12718651
   group by
      s.drID;

由于您只做键和总和,因此您甚至不需要另一张表。现在,如果您需要第一个表中的其他列而不是键,那么是的,您将需要连接。您甚至可以进一步简化步骤,因为您只查询一个键 ID

SELECT 
      sum( s.return_qty ) Return_Qty
   from
      tbl_DeliveryRoute_Sku s
   where
      s.drID = 12718651;

【讨论】:

    【解决方案2】:

    视图缓慢的原因很简单。你正在执行:

    SELECT *
    FROM view_ab
    WHERE drid = 12718651;
    

    你要执行的是:

    select a.id, SUM(b.qty)
    from a inner join
         b
         on a.id = b.id
    where a.id = 12345
    group by a.id;
    

    实际执行的是:

    select ab.*
    from (select a.id, SUM(b.qty)
          from a inner join
               b
               on a.id = b.id
          group by a.id
         ) ab
    where ab.id = 12345;
    

    即先进行整个聚合。 然后应用where。您想要的是向上推谓词(MySQL 称之为合并)。您可以查看有关此主题的 documentation

    一种解决方案似乎是将查询改写为相关子查询:

    select a.id,
           (select sum(b.qty) from b where b.id = a.id) as qty
    from a 
    where a.id = 12345;
    

    唉,select 中的子查询具有相同的效果,所以这不起作用。

    我不知道使用视图的解决方案。您可以避免为此使用视图。最终的解决方案是实现一个触发器,将汇总结果存储在另一个表中——有效地实现视图。

    【讨论】:

      猜你喜欢
      • 2011-11-24
      • 1970-01-01
      • 2010-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-15
      • 1970-01-01
      • 2017-07-20
      相关资源
      最近更新 更多