【问题标题】:MySQL Spring 复杂查询——排序方式与查询效率
【发布时间】:2022-01-11 13:43:24
【问题描述】:

我在 Spring JPA Repository 上运行这个复杂的查询。 我的目标是从站点表中获取所有信息,并按每个站点上的事件严重性对其进行排序。
这是我的查询:

SELECT alls.* FROM sites AS alls JOIN 
( 
    SELECT distinct ets.id FROM 
    ( 
        SELECT s.id, et.`type`, et.severity_level, COUNT(et.`type`) FROM sites AS s  
            JOIN users_sites AS us ON (s.id=us.site_id)  
            JOIN users AS u ON (us.user_id=u.user_id) 
            JOIN areas AS a ON (s.id=a.site_id) 
            JOIN panels AS p ON (a.id=p.area_id) 
            JOIN events AS e ON (p.id=e.panel_id) 
            JOIN event_types AS et ON (e.event_type_id=et.id) 
        WHERE u.user_id="98765432-123a-1a23-123b-11a1111b2cd3"  
        GROUP BY s.id , et.`type`, et.severity_level 
        ORDER BY et.severity_level, COUNT(et.`type`) DESC 
   ) AS ets 
) as etsd ON alls.id = etsd.id

第二个选择(带有“distinct”的那个)返回按严重性正确排序的site_ids。 请注意,每个站点都有不同的 event_types + 严重性,我在答案上使用了分页,所以我需要不同的。

问题是 - 主选择没有保持这个顺序。 有没有办法在一个复杂的查询中保持顺序?

另一个相关问题 - 我的一个想法是提出两个查询:

  1. 将返回订单的“选择不同”查询 --> 保存在“订单列表”列表中
  2. 主“站点”查询(变得非常简单)与“where id in {“order list”}
  3. 按“订单列表”对代码中的第二个查询进行排序。

我每 10 秒使用一次查询,因此它对性能非常敏感。 在这种情况下,什么似乎更快 - 原始复杂查询或那些 2?

任何见解将不胜感激。 Tnx 很多。

【问题讨论】:

  • 您在 ets.id 上的表现与众不同。为什么不重写查询并按 ets.id 分组,那么您根本不需要嵌套查询
  • 希望我理解正确 - 我需要嵌套查询来获得正确的顺序。我得到每个站点中事件的严重性和数量,然后我可以得到正确的顺序。我在 ets 中没有订单信息。
  • 请问什么版本的 MySQL?
  • 然后你可以在那个级别上做一个 group by 而不是 distinct
  • @O.Jones MySQL 5.7 版

标签: mysql query-optimization aggregate-functions


【解决方案1】:

对于我们的过程程序员来说,SQL 的面向集合的声明式语法的一个怪癖:子查询中的 ORDER by 子句不会传递到外部查询,除非有时是偶然的。如果您想在任何查询级别进行排序,则必须在该级别指定它,否则您将获得不可预知的结果。查询优化器通常足够聪明,可以避免浪费排序操作。

您的要求:每个sites.id 值最多给出一个sites 行,按最差事件排序。 Worst:最低的事件严重性,如果有多个事件的严重性最低,则计数最多。

使用这种方法来获得每个 id 的“最差”,而不是 DISTINCT。

      SELECT id, MIN(severity_level) severity_level, MAX(num) num
        FROM (
           /* your inner query */
             ) ets
       GROUP BY id

这会为每个 sites.id 值提供最多一行。那么你的外部查询是

SELECT alls.*
  FROM sites alls
  JOIN (
      SELECT id, MIN(severity_level) severity_level, MAX(num) num
        FROM (
           /* your inner query */
             ) ets
       GROUP BY id
       ) worstevents ON alls.id = worstevents.id
 ORDER BY worstevents.severity_level, worstevents.num DESC, alls.id 

把它们放在一起:

SELECT alls.*
  FROM sites alls
  JOIN (
      SELECT id, MIN(severity_level) severity_level, MAX(num) num
        FROM (
             SELECT s.id, et.severity_level, COUNT(et.`type`) num
               FROM sites AS s  
               JOIN users_sites AS us ON (s.id=us.site_id)  
               JOIN users AS u ON (us.user_id=u.user_id) 
               JOIN areas AS a ON (s.id=a.site_id) 
               JOIN panels AS p ON (a.id=p.area_id) 
               JOIN events AS e ON (p.id=e.panel_id) 
               JOIN event_types AS et ON (e.event_type_id=et.id) 
              WHERE u.user_id="98765432-123a-1a23-123b-11a1111b2cd3"  
              GROUP BY s.id , et.`type`, et.severity_level 
             ) ets
       GROUP BY id
       ) worstevents ON alls.id = worstevents.id
 ORDER BY worstevents.severity_level, worstevents.num DESC, alls.id 

users.user_id 上的索引将有助于提高这些单用户查询的性能。

如果您仍然遇到性能问题,请please read this 并提出另一个问题。

【讨论】:

  • 这很有效,而且信息量很大,非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-14
相关资源
最近更新 更多