通过 Sybase ASE 15.5 上的查询优化非常慢的 select 最大组

Optimizing a very slow select max group by query on Sybase ASE 15.5

我在一个有 6000 万行的 table 上有一个非常简单的查询:

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

它 returns 600 万条记录,需要一个多小时才能 运行。我只需要 运行 一次,因为我正在将记录转移到另一个我不断更新的新 table。

我尝试了一些对我不起作用但经常在 Whosebug 上推荐的方法:

  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 实例本身还是特定于查询?

我有哪些选项可以减少查询的 运行ning 时间?

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

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

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

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

这将是一个完整的 table 扫描(有点贵,但用不了一个小时)和对每一行的索引查找(相当便宜)。这种方法的优点是您可以 select 所有您想要的列。缺点是,如果两行具有相同的 id 最大版本,您将在结果集中获得两者。

Edit :尼古拉斯在这里给出了更准确的答案。我对 Sybase 没有特别的经验,但我在 Sql 服务器上的一个非常小的服务器上获得了处理数据音调的经验。从这次经历中,我了解到当您处理大量数据并且您的服务器没有足够的内存来处理这些数据时,您将遇到瓶颈(我想将临时结果写入磁盘)。我认为这是你的情况(6000 万行),但再一次,我不知道 Sybase,它取决于许多因素,如我的 table 的列数和你的服务器的 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 上,我的table 有 2.878.441 行。
Query#1 需要 31.458 秒和 returns 1.200.146 行。
Query#2 需要 41.787 秒和 returns 1.200.146 行。

在 Sql 服务器上,我的table 有 1.600.010 行。
查询#1 耗时 6 秒 returns 537.232 行。
Query#2 需要 10 秒和 returns 537.232 行。

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

在 PostgreSQL 上,我的table 现在有 5.875.134 行。
查询#1 需要 100.915 秒和 returns 2.796.800 行。
查询#2 需要 98.805 秒和 returns 2.796.800 行。

在 Sql 服务器上,我的 table 现在有 11.712.606 行。
查询#1 需要 28 分 28 秒 和 returns 6.262.778 行。
查询#2 需要 2 分 39 秒 和 returns 6.262.778 行。

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

批评 : 我没有更大的 table PostgreSQL 也没有手头的 Sybase 服务器。

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

上使用 PostgreSQL 9.3.5

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

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

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