Страница 1 из 1

FB2 Оптимизация сортировки

Добавлено: 24 май 2006, 10:24
Sikambr
Имеется таблица:

Код: Выделить всё

create TABLE Docs (
  Id        INTEGER  not NULL PRIMARY KEY,
  Doc_Kind  SMALLINT not NULL REFERENCES Doc_Kinds(Id),
  Client_Id INTEGER  not NULL REFERENCES Clients(Id),
  Doc_Year  SMALLINT not NULL,
  Doc_No    INTEGER  not NULL,
  ...
Для получания списка документов, использую такой запрос:

Код: Выделить всё

select * from Docs
  where (Doc_Kind = :Doc_Kind) and (Client_Id = :Client_Id)
  order by Doc_Year desc, Doc_No desc

PLAN SORT ((DOCS INDEX (RDB$FOREIGN79, RDB$FOREIGN78)))
Т.е. используется два форин-индекса.
После создания индекса:

Код: Выделить всё

create desc index Idx_Docs_No on Docs(Doc_Year, Doc_No)
план уже такой

Код: Выделить всё

PLAN (DOCS ORDER IDX_DOCS_NO INDEX (RDB$FOREIGN79, RDB$FOREIGN78))
Хотелось спросить общественность, как оптимальней использовать индексы при сортировки и использования условий?
Насколько я понимаю, использование одного составного индекса лучше, чем трех одиночек.
Что скажите?

Добавлено: 24 май 2006, 10:31
Dimitry Sibiryakov
Для сортировки индекс лучше вообще не использовать если только у тебя не мега-выборки.
У составного индекса практически нет преимуществ перед одиночными.

Добавлено: 24 май 2006, 12:05
Sikambr
Dimitry Sibiryakov писал(а):У составного индекса практически нет преимуществ перед одиночными.
Для FB не знаю, а для Interbase 7, если оптимизатор использует два одиночных индекса, то время выполения запроса заметно больше, чем использование (после создания) одного составного индекса.
Это для было замечено на таблице с количеством записей более 1 млн.

Добавлено: 24 май 2006, 12:35
dimitr
1) индекс для сортировки (т.е. ORDER-план) стоит использовать *только* для максимально быстрого получения первых записей. Например, отобразить первую страницу грида. Если же требуется максимально быстро отфетчить все записи, то ORDER практически всегда проигрывает SORT-плану.

2) композит всегда будет эффективнее, чем несколько односегментных индексов. Но набор односегментых гибче, т.к. позволяет качественно оптимизировать практически любой запрос, в то время как в случае с композитами надо думать про порядок столбцов.

3) после создания композита IDX_DOCS_NO план стал совсем плохой, т.к. разные индексы используются для сортировки и для фильтрации. Добиться использования только индекса IDX_DOCS_NO в этом случае не удастся.

Добавлено: 24 май 2006, 13:39
Sikambr
dimitr писал(а):1) индекс для сортировки (т.е. ORDER-план) стоит использовать *только* для максимально быстрого получения первых записей. Например, отобразить первую страницу грида. Если же требуется максимально быстро отфетчить все записи, то ORDER практически всегда проигрывает SORT-плану.
Вот этого я и хочу.
После дропанья индекса Idx_Doc_No и создания другого

Код: Выделить всё

create desc index Idx_Docs_No_2 on Docs(Doc_Kind, Client_Id, Doc_Year, Doc_No)
Получаем следущее:
a)

Код: Выделить всё

select * from Docs
where (Doc_Kind = :Doc_Kind) and (Client_Id = :Client_Id)
order by Doc_Year desc, Doc_No desc

PLAN SORT ((DOCS INDEX (IDX_DOCS_NO_2)))
b)

Код: Выделить всё

select * from Docs
where (Doc_Kind = :Doc_Kind) and (Client_Id = :Client_Id)
order by Doc_Kind desc, Client_Id desc, Doc_Year desc, Doc_No desc

PLAN (DOCS ORDER IDX_DOCS_NO_2 INDEX (IDX_DOCS_NO_2))
Для варианта (1) план (b) оптимальный?

Добавлено: 24 май 2006, 14:39
kdv
дропать исходный индекс необязательно.
Для варианта (1) план (b) оптимальный?
да. чую, туговато у тебя с пониманием, что такое индекс, в смысле, как он устроен.

Добавлено: 24 май 2006, 15:33
Sikambr
kdv писал(а):дропать исходный индекс необязательно.
Если Idx_Doc_No не дропать, то он будет участвовать в запросе (a).
Вообщем, вопрос не в этом.
kdv писал(а):да. чую, туговато у тебя с пониманием, что такое индекс, в смысле, как он устроен.
Не спорю, как устроен индекс и что такое б-деревья я знаю только по наслышке.
Но меня интересует, что оптимальнее, запрос (а) или запрос (b). Т.е. я не совсем догоняю, если план:

Код: Выделить всё

PLAN (DOCS ORDER IDX_DOCS_NO_2 INDEX (IDX_DOCS_NO_2))
Сколько проходов будет:
1. в одном проходе будет и сортировка и отсеивание;
2. вначале сортируется, а затем отсеивается (или наоборот), т.е. два прохода.
Вот в этом хочу разобраться.

PS В запросе (a) я ошибся с планом. Прошу прощения, исправил.

Добавлено: 25 май 2006, 15:21
Sikambr
После ряда экспериментов, решил, что оптимальней (по времени) и гибче будет следущее:

Код: Выделить всё

create desc index Idx_Docs_No on Docs(Doc_Year, Doc_No);

select * from Docs 
  where (Doc_Kind = :Doc_Kind) and (Client_Id = :Client_Id) 
  order by Doc_Year desc, Doc_No desc;

PLAN (DOCS ORDER IDX_DOCS_NO INDEX (RDB$FOREIGN79, RDB$FOREIGN78));
Даже использование 3-х индексов, по времени дает выигрыш в 3 раза, чем отказ от построения индекса Idx_Docs_No, т.е. безиндексная сортировка.
Построение индекса по 4-м полям

Код: Выделить всё

create desc index Idx_Docs_No_2 on Docs(Doc_Kind, Client_Id, Doc_Year, Doc_No) ;

select * from Docs
  where (Doc_Kind = :Doc_Kind) and (Client_Id = :Client_Id) 
  order by Doc_Kind desc, Client_Id desc, Doc_Year desc, Doc_No desc;

PLAN (DOCS ORDER IDX_DOCS_NO_2 INDEX (IDX_DOCS_NO_2))
не дает выигрыша по времени.

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

Добавлено: 25 май 2006, 15:48
kdv
Может кто-нибудь прояснит, сколько делается проходов?
www.ibase.ru/devinfo/dataaccesspaths.htm

Добавлено: 26 май 2006, 08:36
Sikambr
kdv писал(а):
Может кто-нибудь прояснит, сколько делается проходов?
www.ibase.ru/devinfo/dataaccesspaths.htm
Спасибо за поучительную статью.