Нужно ли Firebird переиндексацию вручную? - PullRequest
13 голосов
/ 19 мая 2009

Я использую встроенный Firebird и 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

Я полагаю, это нормально при использовании встроенного ПО, но действительно ли это необходимо при использовании сервера? Есть ли способ настроить сервер так, чтобы он делал это автоматически при необходимости или периодически?

Ответы [ 3 ]

20 голосов
/ 19 мая 2009

Во-первых, позвольте мне отметить, что я не эксперт по Firebird, поэтому я отвечаю на основе того, как работает SQL Server.

В этом случае ответом будет как да, так и нет.

Индексы, конечно, обновляются на SQL Server, в том смысле, что если вы вставите новую строку, все индексы для этой таблицы будут содержать эту строку, поэтому она будет найдена. В общем, вам не нужно постоянно переиндексировать таблицы, чтобы эта часть работала. Это часть «нет».

Проблема, однако, не в индексе, а в статистике. Вы говорите, что вам нужно переиндексировать таблицы, но затем вы показываете код, который манипулирует статистикой, и именно поэтому я отвечаю.

Короткий ответ: статистика постепенно выходит из-под контроля с течением времени. Они могут не ухудшиться до такой степени, что они непригодны для использования, но они будут ухудшаться по сравнению с идеальным уровнем, на котором они находятся, когда вы их пересматриваете / пересчитываете. Это часть "да".

Основная проблема со устаревшей статистикой заключается в том, что, если распределение ключей в индексах кардинально меняется, статистика может не сразу это исправить, и поэтому оптимизатор запросов выберет неправильные индексы, основанные на старых устаревших , статистические данные у него на руках.

Например, допустим, у одного из ваших индексов есть статистика, которая говорит о том, что ключи объединены в одном конце пространства значений (например, int-column с множеством нулей и единиц). Затем вы вставляете много-много строк со значениями, в которых этот индекс содержит значения, разбросанные по всему спектру.

Если вы сейчас выполняете запрос, использующий объединение из другой таблицы, для столбца с низкой селективностью (также с множеством нулей и единиц) к таблице с этим вашим индексом, оптимизатор запросов может сделать вывод, что этот индекс хорош , поскольку он извлекает много строк, которые будут использоваться одновременно (они находятся на одной странице данных).

Однако, поскольку данные изменились, они будут перескакивать по всему индексу, чтобы найти соответствующие фрагменты, и, следовательно, не будут такими хорошими.

После пересчета статистики оптимизатор запросов может увидеть, что этот индекс не оптимален для этого запроса, и вместо этого выбрать другой индекс, который более подходит.

Обычно вам необходимо периодически пересчитывать статистику, если ваши данные постоянно меняются. Если ваши данные редко изменяются, вам, вероятно, не нужно делать это очень часто, но я все равно добавил бы работу по обслуживанию с некоторой регулярностью, которая делает это.

Что касается того, можно ли попросить Firebird сделать это самостоятельно, опять же, я на тонком льду, но я подозреваю, что есть. В SQL Server вы можете настроить задачи обслуживания, которые выполняют это, по расписанию, и, по крайней мере, вы должны иметь возможность запустить пакетный файл из планировщика Windows, чтобы сделать что-то подобное.

7 голосов
/ 19 мая 2009

Это не переиндексирует, оно пересчитывает веса для индексов, которые используются оптимизатором для выбора наиболее оптимального индекса. Вам не нужно этого делать, если размер индекса не сильно меняется. Если вы создаете индекс до того, как добавляете данные, вам необходимо выполнить перерасчет.

Встроенный сервер и сервер должны иметь одинаковую функциональность, кроме модели процесса.

2 голосов
/ 10 июня 2015

Я хотел обновить этот ответ для более новой 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;
...