【问题标题】:Optimizing a very slow select max group by query on Sybase ASE 15.5在 Sybase ASE 15.5 上通过查询优化非常慢的 select max group
【发布时间】:2017-02-10 19:18:25
【问题描述】:

我对一个有 6000 万行的表有一个非常简单的查询:

select id, max(version) from mytable group by id

它返回 600 万条记录,运行时间超过一小时。我只需要运行一次,因为我正在将记录转移到另一个我不断更新的新表中。

我尝试了一些对我不起作用但在 stackoverflow 上经常被建议的方法:

  1. select top 1 / order by desc 的内部查询:Sybase ASE 不支持它
  2. left outer join where a.version < b.version and b.version is null:一个多小时后中断查询,只找到十万条记录

我了解 Sybase 必须进行全面扫描。

为什么全扫描会这么慢?

缓慢是由于 Sybase ASE 实例本身还是特定于查询?

有哪些方法可以减少查询的运行时间?

【问题讨论】:

    标签: sql database performance query-optimization sap-ase


    【解决方案1】:

    我对 Sybase 优化不是很熟悉。但是,您的查询确实很慢。这里有两个想法。

    首先,在mytable(id, version desc) 上添加一个索引。至少,这是一个查询的覆盖索引,这意味着所有使用的列都在索引中。 Sybase 可能足够聪明,可以消除group by

    另一个选项使用相同的索引,但具有相关的子查询:

    select t.id
    from mytable t
    where t.version = (select max(t2.version)
                       from mytable t2
                       where t2.id = t.id
                      );
    

    这将是一个全表扫描(有点贵,但不是一个小时的价值)和每行的索引查找(相当便宜)。这种方法的优点是您可以选择所需的所有列。缺点是如果两行对于一个 id 具有相同的最大版本,您将在结果集中得到两者。

    【讨论】:

    • 感谢您的回答。我忘了提到这个表上已经有一个聚集索引,删除它不是一个选项。此外,索引创建和更新统计信息不会少于一小时。
    • @Nicolas 。 . .我没有提到任何关于聚集索引或删除任何现有索引的内容。
    • "add an index on mytable(id, version desc)" 你说的是非聚集索引吗?
    • @Nicolas 。 . .是的。
    【解决方案2】:

    编辑:这里 Nicolas 给出了更准确的答案。我对 Sybase 没有特别的经验,但我获得了在 Sql Server 上使用一个非常小的服务器处理大量数据的经验。从这次经验中,我了解到,当您处理大量数据并且您的服务器没有足够的内存来处理大量数据时,您会遇到瓶颈(我想将临时结果写入盘)。我认为这是您的情况(6000 万行),但我不知道 Sybase,这取决于许多因素,例如 mytable 拥有的列数和服务器拥有的 RAM 数量等......

    这里是我刚刚做的一个小经验的结果:

    我在 Sql-Server 和 PostgreSQL 上运行这两个查询。

    查询 1:

    SELECT id, max(version)
    FROM mytable
    GROUP BY id
    

    查询 2:

    SELECT id, version
    FROM
    (
        SELECT id, version, ROW_NUMBER() OVER (PARTITION BY id ORDER BY version DESC) as RN
        FROM mytable
    ) q
    WHERE q.rn = 1
    

    在 PostgreSQL 上,mytable 有 2.878.441 行。
    Query#1 耗时 31.458 秒并返回 1.200.146 行。
    Query#2 耗时 41.787 秒并返回 1.200.146 行。

    在 Sql Server 上,mytable 有 1.600.010 行。
    Query#1 需要 6 秒并返回 537.232 行。
    Query#2 需要 10 秒并返回 537.232 行。

    到目前为止,您的查询总是更快。所以我尝试了更大的桌子。

    在 PostgreSQL 上,mytable 现在有 5.875.134 行。
    查询#1 需要 100.915 秒并返回 2.796.800 行。
    Query#2 耗时 98.805 秒并返回 2.796.800 行。

    在 Sql Server 上,mytable 现在有 11.712.606 行。
    查询 #1 需要 28 分 28 秒并返回 6.262.778 行。
    查询#2 需要 2 分 39 秒 并返回 6.262.778 行。

    现在我们可以做一个假设。在第一部分关于这次经历。两台服务器有足够的内存来处理数据,因此 Group By 更快。这个实验的第二部分可能会证明太多的数据会破坏 group by 的性能。为了防止瓶颈 ROW_NUMBER() 似乎可以解决问题。

    批评:我在 PostgreSQL 上没有更大的表,也没有 Sybase 服务器。

    对于这个实验,我在 x86_64 和 SQL Server 2012 - 11.0-2100.60 (X64) 上使用 PostgreSQL 9.3.5

    也许 Nicolas 这个实验会对你有所帮助。

    【讨论】:

    • 我也很好奇。恕我直言,PARTITION BYGROUP BY 的工作量几乎相同,但使用MAX 它可以在使用ROW_NUMBER() 流式传输数据并将所有结果转储到一个临时表意味着它也需要在整个操作中将每个值都保存在“内存”中。
    • 明天我会做一些基准测试,我会更新我太快的答案。
    • 我刚刚测试了您的查询,但不支持。关键字“OVER”附近的语法不正确。
    • 我的错... Row_number 仅存在于特定版本的 Sybase(显然是 IQ)上。我有几个问题: - 为什么您的查询持续不到一个小时很重要?对于 6000 万行,这还不错。 - mytable 中有多少列? - 您能否编辑您的帖子并向我们提供您的聚集索引的详细信息以及其他索引(如果存在)?
    • 其实没那么重要,单发还是可以的。我只是假设我可以做得更好,我也想知道这背后的数据库是否有问题。
    【解决方案3】:

    函数 max() 不帮助优化器使用索引。 也许您应该在 max(version) 上创建一个基于函数的索引:
    http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc32300.1550/html/sqlug/CHDDHJIB.htm

    【讨论】:

    • 我不知道这个功能。我应该在 id,max(version) 上创建索引还是只在 max(version) 上创建索引?
    • 我刚刚测试过,索引中不允许使用聚合函数。它仅适用于非聚合函数,如 lower 或 upper。
    【解决方案4】:

    最后,(id, version desc) 上的非聚集索引成功了,而无需对查询进行任何更改。索引创建也需要一小时,查询会在几秒钟内响应。但我想它仍然比拥有另一个可能导致数据完整性问题的表更好。

    【讨论】:

      猜你喜欢
      • 2014-06-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多