【问题标题】:SQL Query optimization -performance issuesSQL 查询优化 - 性能问题
【发布时间】:2019-01-22 14:18:50
【问题描述】:

我有以下要优化的 SQL 查询:

select table1.tiers as col1, table1.id_item as col2 
from items table1 
where (table1.tiers is not null) 
  and table1.tiers<>''
  and table1.id_item = (select max(table2.id_item)
                        from items table2
                        where table1.tiers=table2.tiers) 
  and table1.n_version_item=(select max(table2.n_version_item) 
                             from items table2 
                             where table2.id_item=table1.id_item)

我试过这个:

select table1.tiers as col1, table1.id_item as col2 
from items table1 
where (table1.tiers is not null) 
  and table1.tiers<> '' 
  and CONCAT(table1.id_item,table1.n_version_item) =  (select CONCAT(max(table2.id_item),max(table2.n_version_item)) 
                                                       from items table2
                                                       where table2.id_item=table1.id_item 
                                                         and table1.tiers=table2.tiers)

但我没有得到相同的结果。原始的第一个查询返回的行数少于修改后的行数。请注意,表项有一个主键(id、version),并且对于每一对,都会影响一个层。

【问题讨论】:

  • 不要在查询中重复使用同一个表别名 (table1)。
  • where (id_item, n_version_item) = (select max(t2.id_item), max(t2.n_version_item) from ...)
  • 我知道 SQL 只是一种查询语言。第一个查询是由休眠生成的。而且我在日志文件中注意到它需要太长时间。这就是为什么我想以另一种方式重写它以解决性能问题谢谢
  • 我正在使用 MySQL
  • @user3474488 它的一些数据不应该导致性能问题。您可以创建索引,因为在您的查询中您没有使用 PK

标签: mysql sql query-performance


【解决方案1】:

当使用函数时,它会阻止索引被使用,所以CONCAT(table1.id_item,table1.n_version_item) 不会读取索引,除非它是基于函数的索引。但是,正如 cmets 中提到的a_horse_with_no_name,您可以使用以下内容:

select itm.tiers as col1, itm.id_item as col2 
from items itm
where itm.tiers is not null 
  and itm.tiers<>''
  and (itm.id_item , itm.n_version_item)= (select 
 max(item_sub.id_item),max(item_sub.n_version_item)
                        from items item_sub
                        where itm.tiers=item_sub.tiers) 

然后您必须检查查询的查询计划正在使用什么索引(您可以使用列tiersid_itemn_version_item 上的其他索引开始索引)

【讨论】:

    【解决方案2】:

    我想你想要:

    select i.tiers as col1, i.id_item as col2 
    from items i 
    where i.tiers is not null and  -- redundant, but I'm leaving it in
          i.tiers <> '' 
          (id_item, n_version_item) = (select i2.id_item, max(i2.n_version_item)
                                       from items i2
                                       where i2.tiers = i.tiers
                                       order by i2.id_item desc, i2.n_version_item desc
                                       limit 1
                                      );
    

    对于这个版本,您需要items(tiers, id_item, n_version_item) 上的索引。

    【讨论】:

      【解决方案3】:

      如果您在“函数”(CONCATDATE 等)内隐藏列,则无法使用索引来提高性能。这将排除您的第二个版本的考虑。

      与此相关的是“行构造函数”的使用(参见 a_horse_with_no_name 的评论)。它们历来优化不佳;避免他们。我指的是WHERE (a,b) IN ( (1,2), ...) 或其他变体。

      现在,让我们剖析一下

        and table1.id_item = (select max(table2.id_item)
                          from items table2
                          where table1.tiers=table2.tiers) 
      

      table2 按此顺序需要 INDEX(tiers, id_item)。这样,子查询非常快。其他子查询需要INDEX(id_item, n_version_item) 其余部分:

        and table1.id_item = <<value>>
      

      现在让我们看看整体

      where (table1.tiers is not null) 
        and  table1.tiers<>''
        and  table1.id_item = <<value>>
        and  table1.n_version_item = <<value>>
      

      = 易于优化;其他人不是。所以让我们构建

      INDEX(id_item, n_version_item,  -- in either order
            tiers)    -- last
      

      通过使用我指定的顺序,您可以避免还需要上面提到的INDEX(id_item, n_version_item)

      (如果您提供SHOW CREATE TABLE 会有所帮助;我需要知道 PK 是什么,以及其他一些事情。)

      作为奖励,这些索引将是“覆盖索引”。

      作为最后一点(小调):

      where (table1.tiers is not null) 
        and  table1.tiers<>''
      

      最好只选择 one 编码(NULL 与空字符串)到您所指示的任何内容。

      【讨论】:

        猜你喜欢
        • 2013-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多