我对一个有6000万行的表有一个非常简单的查询:
select id, max(version) from mytable group by id
它返回600万条记录,运行时间超过一小时。我只需要运行一次因为我将记录转移到另一个我不断更新的新表中。
我尝试了一些对我不起作用但却经常在stackoverflow上建议的事情:
select top 1 / order by desc
的内部查询:Sybase ASE left outer join where a.version < b.version and b.version is null
:我在一个多小时后打断了查询,发现只有十万条记录我知道Sybase必须进行全面扫描。
为什么全扫描速度太慢?
由于Sybase ASE实例本身还是特定于查询而导致的缓慢?
我有哪些选项可以减少查询的运行时间?
答案 0 :(得分: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,您将获得结果集。
答案 1 :(得分:0)
编辑:尼古拉斯在这里提供更准确的答案。我没有使用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行 查询#1需要31.458秒并返回1.200.146行 查询#2需要41.787秒并返回1.200.146行。
在Sql Server上,mytable有1.600.010行 查询#1需要6秒,返回537.232行 查询#2需要10秒并返回537.232行。
到目前为止,您的查询总是更快。所以我尝试了更大的桌子。
在PostgreSQL上,mytable现在有5.875.134行 查询#1需要100.915秒并返回2.796.800行 查询#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上使用PostgreSQL 9.3.5 - 11.0-2100.60(X64)
也许尼古拉斯这个实验会帮助你。
答案 2 :(得分:0)
函数max()无助于优化器使用索引。
也许你应该在max(version)上创建一个基于函数的索引:
http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc32300.1550/html/sqlug/CHDDHJIB.htm
答案 3 :(得分:0)
所以最后,非聚集索引(id,版本desc)完成了这一操作,而无需对查询进行任何更改。索引创建也需要一个小时,查询会在几秒钟内响应。但我想这仍然比另一个可能导致数据完整性问题的表更好。