【问题标题】:slow sql script optimization慢sql脚本优化
【发布时间】:2013-08-21 18:11:53
【问题描述】:

我有一个类似的查询:

select row_number() over(order by m_time desc) as row, m.m_id, m_time, m_log_id
    (case when exists(select 1 from t_approved_phonenumber where phone_number = m.c_phone_number) then 1 else 0 end) as approved, 
    (case when exists(select 1 from t_log log where log.c_id < m.m_log_id and log.phone_number = m.phone_number) then 'N' else 'Y' end) as is_first_time
from t_message m

所有表 t_approved_phonenumber、t_message 和 t_log 都有很多记录。并且所有的 ID 都是主键,phone_number 列有索引。有时我的查询很慢。有什么办法可以加快速度吗?

谢谢,

【问题讨论】:

  • 您忘记提及运行此查询的 SQL 产品。另外,在询问优化时,请考虑添加当前版本查询的查询计划。

标签: sql optimization case exists


【解决方案1】:

也许在t_log 上使用第一列phone_number 和第二列c_id 创建一个索引,这样第二个存在就可以使用这个索引并且-依赖于DBMS-甚至可能不必访问表@987654324 @ 本身。声明索引唯一会促进优化器的使用 - 当然,只有当它真的唯一时,您才能这样做。

当然,如果到目前为止还没有 m_time 索引,这可能会对row_number() 有所帮助。

【讨论】:

    【解决方案2】:

    尝试用普通的“左连接”子查询替换相关子查询,因为它们通常表现更好。常规子查询只运行一次,与针对每一行运行的相关子查询相反。它也更灵活 - 如果需要,您可以向子查询添加更多数据。 您的查询应如下所示(可能出现错误 - 目前没有 Management Studio):

    select 
        row_number() over(order by m_time desc) as row
        ,m.m_id
        ,m_time
        ,m_log_id
        ,coalesce(approved, 0) as approved
        ,coalesce(is_first_time, 'Y') as is_first_time
    from 
        t_message m
        left join (select phone_number, 1 as [approved] from t_approved_phonenumber group by phone_number) as a
        on a.phone_number = m.c_phone_number
        left join (select phone_number, min(c_id) as c_id, 'N' as is_first_time from t_log group by phone_number) log
        on log.c_id < m.m_log_id and log.phone_number = m.phone_number
    

    【讨论】:

      【解决方案3】:

      根据我的经验,joins 比谓词中的 select 要好得多。 试试这个查询。

      我假设对于每个 t_message,t_message 中的每个 Phone_Number 至少有一个调用,所以我在第二个 JOIN 中使用 INNER JOIN 而不是左连接。

      select row_number() over(order by m_time desc) as row, 
          m.m_id, 
          m_time, 
          m_log_id,
          (case WHEN approved.phone_number IS NULL then 0 else 1 end) as approved, 
          (case when First_c_id < m.m_log_id then 'N' else 'Y' end) as is_first_time
      from t_message  m
      LEFT JOIN t_approved_phonenumber approved ON m.c_phone_number = approved.phone_number 
      INNER JOIN (SELECT phone_number, MIN(c_id)  AS First_c_id 
                 FROM t_log 
                 GROUP BY phone_number) FirstLog ON FirstLog.PhoneNumber = m.phone_number
      

      无论如何,@FrankPl 建议的索引可以帮助获得更多的性能,

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-17
        • 1970-01-01
        • 1970-01-01
        • 2017-11-16
        • 2018-10-10
        • 2020-04-12
        • 1970-01-01
        相关资源
        最近更新 更多