【问题标题】:Does Firebird need manual reindexing?Firebird 需要手动重新索引吗?
【发布时间】:2010-10-27 07:15:45
【问题描述】:

我同时使用 Firebird Embedded 和 Firebird Server,有时我需要使用如下过程重新索引表:

CREATE PROCEDURE MAINTENANCE_SELECTIVITY 
ASDECLARE VARIABLE S VARCHAR(200);
BEGIN
FOR select RDB$INDEX_NAME FROM RDB$INDICES INTO :S DO
BEGIN
S = 'SET statistics INDEX ' || s || ';';
EXECUTE STATEMENT :s;
END
SUSPEND;
END

我想这在使用嵌入式时是正常的,但真的需要使用服务器吗?有没有办法将服务器配置为在需要时自动执行或定期执行?

【问题讨论】:

  • 只是一个注释。在这个过程中,SUSPEND 是不必要的。
  • 谢谢!我想我是从某个地方复制的。
  • 实际上,您并没有重新索引,而只是重新计算索引统计信息。在大表上重新索引可能非常慢。计算统计数据总是很快的。

标签: firebird


【解决方案1】:

首先,我要指出我不是 Firebird 专家,所以我根据 SQL Server 的工作原理来回答。

在这种情况下,答案是肯定的,也不是。

索引当然会在 SQL Server 上更新,因为如果您插入新行,该表的所有索引都将包含该行,因此会找到该行。因此,基本上,您不需要为该部分工作重新索引表。那是“不”的部分。

然而,问题不在于索引,而在于统计信息。你说你需要重新索引表,但是你展示了操纵统计数据的代码,这就是我要回答的原因。

简短的回答是,随着时间的推移,统计数据会慢慢失控。它们可能不会恶化到无法使用的程度,但是当您重新创建/重新计算它们时,它们会从它们所处的完美水平下降。那是“是”的部分。

过时统计信息的主要问题是,如果索引中键的分布发生剧烈变化,则统计信息可能无法立即获取,因此查询优化器将根据旧的、过时的索引选择错误的索引,手头有统计数据。

例如,假设您的一个索引的统计数据表明键在值空间的一端聚集在一起(例如,具有大量 0 和 1 的 int-column)。然后插入大量行,其值使该索引包含分布在整个范围内的值。

如果您现在执行一个查询,该查询使用来自另一个表的连接,在一个具有低选择性(也有很多 0 和 1)的列上针对您的这个索引的表,查询优化器可能会推断出这个索引是好的,因为它会获取许多将同时使用的行(它们在同一个数据页上)。

但是,由于数据发生了变化,它会跳过索引来查找相关部分,因此毕竟不是那么好。

在重新计算统计信息后,查询优化器可能会发现该索引对于该查询来说是次优的,并选择另一个更适合的索引。

基本上,如果您的数据不断变化,您需要定期重新计算统计信息。如果您的数据很少更改,您可能不需要经常更改,但我仍然会添加一个定期执行此操作的维护作业。

至于是否可以让 Firebird 自己做,我又如履薄冰,但我怀疑有。在 SQL Server 中,您可以按计划设置执行此操作的维护作业,至少您应该能够从 Windows 计划程序启动批处理文件来执行类似的操作。

【讨论】:

  • 没错,我想说的是,当引入大量数据时,实际重新计算统计数据可能是关键,我担心的是 Firebird 不会自动重新计算它们,并且没有 (很明显)用 SQL Server 之类的工作来完成它。
  • 那么我猜一个批处理文件调用正确的命令行工具并执行你需要的 SQL 语句或存储过程是你唯一的选择,除非你有冒险精神,并且可以自己制作一个工具:)
  • 这个 youtube 视频提到了创建自动重新索引 firebird 索引的程序youtube.com/…
【解决方案2】:

这不会重新索引,它会重新计算索引的权重,优化器使用这些权重来选择最佳索引。除非索引大小发生很大变化,否则您不需要这样做。如果在添加数据之前创建索引,则需要重新计算。

嵌入式和服务器除了流程模型外应该具有完全相同的功能。

【讨论】:

  • 你是对的。但无论如何,它确实对性能产生了巨大的影响。那么,您的意思是它们都不会自动执行此操作?
  • 索引在数据修改时更新,但权重不更新。所以如果数据变化很大,需要手动重新计算。
【解决方案3】:

我想为较新的 firebird 更新此答案。这是更新的 dsql。

SET TERM ^ ;
CREATE OR ALTER PROCEDURE NEW_PROCEDURE 
AS
DECLARE VARIABLE S VARCHAR(300);
begin
  FOR select  'SET statistics INDEX ' || RDB$INDEX_NAME || ';' 
  FROM RDB$INDICES 
  WHERE RDB$INDEX_NAME <> 'PRIMARY' INTO :S 
  DO BEGIN
     EXECUTE STATEMENT :s;
  END
end^
SET TERM ; ^

GRANT EXECUTE ON PROCEDURE NEW_PROCEDURE TO SYSDBA;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-06
    • 2017-04-04
    • 2013-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-24
    相关资源
    最近更新 更多