MYSQL 查看查询性能问题

Posted

技术标签:

【中文标题】MYSQL 查看查询性能问题【英文标题】:MYSQL View Query Performance Issue 【发布时间】:2021-07-10 14:30:58 【问题描述】:

我有 5 个 SQL 表

商店 员工 部门 sold_items staff_rating

我创建了一个将这四个表连接在一起的视图。最后一张表(staff_rating),我想在接近视图行的商品售出时间(sold_items.date)的时间获取评级列。 我尝试了以下 SQL 查询,这些查询有效但存在性能问题。

SQL 查询 1

SELECT s.name,
       s.country,
       d.name,
       si.item, 
       si.date, 
       (SELECT rating 
        FROM staff_ratings 
        WHERE staff_id = s.id 
        ORDER BY DATEDIFF(date, si.date) LIMIT 1) AS rating, 
       st.name, 
       st.owner
   FROM store st
   LEFT OUTER JOIN staff s ON s.store_id = st.id
   LFET JOIN departments d ON d.store_id = st.id
   LEFT JOIN sold_items si ON si.store_id = st.id

SQL 查询 2

SELECT s.name,
       s.country,
       d.name,
       si.item, 
       si.date, 
       si.rating , 
       st.name, 
       st.owner
FROM store st
LEFT OUTER JOIN staff s ON s.store_id = st.id
LFET JOIN departments d ON d.store_id = st.id
LEFT JOIN (SELECT *,
                  (SELECT rating 
                   FROM staff_ratings 
                   WHERE staff_id = si.staff_id 
                   ORDER BY DATEDIFF(date, si.date) LIMIT 1) AS rating 
           FROM sold_items) si ON si.store_id = st.id

SQL Query 2 比 SQL Query 1 快。但两者都存在性能问题。感谢对性能更好的查询的帮助。提前致谢。

【问题讨论】:

第二个查询看起来在语法上是错误的。它必须产生“未知列”错误。 mysql 5.x 还是 MySQL 8+?此外,您的表上存在哪些索引等?如果您希望我们了解您现有查询的行为,也总是值得在您的查询上运行EXPLAIN。最后,如前所述,您的查询在语法上似乎不正确;请确保您包含使用的确切工作查询 - 要求我们尝试通过您的拼写错误进行解释只会使一切变得不必要地困难。 请read this 然后edit 你的问题。我们需要更多信息来帮助您。 @MatBailie,它是 MYSQL 5.x 您将商店加入其员工看起来很“奇怪”,然后当您加入已售商品时,您不包括 staff_id(例如,如果商店售出 100 件商品并且有8 名员工,你最终得到 800 种组合,然后你去查看每一种组合的员工评级......)这真的正确吗?请编辑您的问题以包含完整的表定义,以便我们可以查看实际存在哪些外键。 【参考方案1】:

您的查询对我来说看起来不正确(如对原始帖子的评论中所述;在销售的联接中缺少 staff_id 等)

忽略这一点,您最大的性能打击之一可能是这个......

ORDER BY DATEDIFF(date, si.date) LIMIT 1

只能通过将该员工的每条记录与当前销售记录进行比较来回答该订单。

理想情况下,您希望能够从索引中找到适当的员工评级,而不必运行涉及评级表和销售表的日期的计算。

例如,如果您想要“销售前的最新评级”,则可以大大改进查询...

SELECT
   s.name,
   s.country,
   d.name,
   si.item, 
   si.date, 
   (
     SELECT sr.rating 
       FROM staff_ratings sr
      WHERE sr.staff_id = s.id
        AND sr.date <= si.date
   ORDER BY sr.date DESC
      LIMIT 1
   )
    AS rating, 
   st.name, 
   st.owner
FROM store st
LEFT JOIN staff s ON s.store_id = st.id
LFET JOIN departments d ON d.store_id = st.id
LEFT JOIN sold_items si ON si.store_id = st.id

然后,使用staff_ratings(staff_id, date, rating) 的索引,优化器可以非常快速地查找要使用的评级,而无需扫描该员工的每个单一评级。

【讨论】:

【参考方案2】:

为什么是DATEDIFF?像这样的东西会更好吗?如果是这样,给定的索引将使它工作得更快。

WHERE staff_id = s.id
  AND s.date >= s1.date
ORDER BY s.date
LIMIT 1

还有INDEX(staff_id, date)

你需要LEFT JOIN吗?也许是普通的JOIN

d 可能受益于INDEX(store_id, name)

【讨论】:

以上是关于MYSQL 查看查询性能问题的主要内容,如果未能解决你的问题,请参考以下文章

mysql问题排查与性能优化

MySQL性能优化

mysql之性能指标查询

性能测试-MySQL性能查看(转)

MySQL 查询中的性能

MYSQL性能查看(命中率,慢查询)