Выборка с сортировкой

Модераторы: kdv, CyberMax

Ответить
pticelov
Сообщения: 95
Зарегистрирован: 28 дек 2005, 22:52

Выборка с сортировкой

Сообщение pticelov » 19 дек 2009, 15:46

Есть у меня простая проблема, для которой я нашел только очень кривое решение:

есть таблица, в которой хранятся некоторые данные (на самом деле задача типовая), пусть будет такая:
table operations account integer,tm integer,...
данные по операциям клиентов в системе, клиент идентифицируется полем account, tm - время выполнения операции
созданы индексы

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

create index operations_account on operations(account)
create descending index operations_tm on operations(tm)
иногда мне надо получить список из последний операций клиента, отсортированных по времени, иногда - просто последнюю операцию или ее время

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

select max(tm) from operations where account=?
все это приводит к очевидному сканированию большого индекса и при неудачном раскладе запрос тормозит по полсекунды (запросов таких очень много)
вариант

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

select max(tm+0) from operations where account=?
приводит к тормозам в других случаях (если клиенты, у которых очень много операций, десятки тысяч)

в статистике - тысячи фетчей

Я сделал доп. поле:
acctm bigint
и при внесении данных в таблицу добавляю туда значение
account*1000000+tm
добавли индекс по нему

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

create descending index operations_acctm on operations(acctm)
и все выборки по account= с сортировкой по tm первратил в

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

select * from operations where acctm >= (? * 1000000) and acctm < ((? + 1) * 1000000) order by acctm desc
? - одинаковое значение номера аккаунта
это классно и предсказуемо работает (в статистике - всегда десятки фетчей), однако меня смущает 2 вещи:
1. заведено поле, которое мне нафиг не нужно (чисто функция двух других), однако вычисляемое поле для построения индекса не годится
2. запросы стали выглядеть безобразно

мне всегда казалось, что для таких случаев нужен индекс по двум полям:

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

create descending index operations_account_tm on operations(account,tm)
с запросами вида

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

select * from operations where account=? order by tm desc
и все должно бы работать именно так, как мне хочется, однако для сортировки по tm этот индекс не используется, как бы мне не хотелось (перепробовал все, что в голову пришло)

есть у кого-нибудь мысли по оптимизации этого дела менее кривой, чем сделал я?

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Re: Выборка с сортировкой

Сообщение Dimitry Sibiryakov » 20 дек 2009, 14:12

Почитай это.

pticelov
Сообщения: 95
Зарегистрирован: 28 дек 2005, 22:52

Re: Выборка с сортировкой

Сообщение pticelov » 21 дек 2009, 01:09

Dimitry Sibiryakov писал(а):Почитай это.
Да я там не увидел ничего, что могло бы мне помочь

с нее и начинал

pticelov
Сообщения: 95
Зарегистрирован: 28 дек 2005, 22:52

Re: Выборка с сортировкой

Сообщение pticelov » 21 дек 2009, 01:26

Дошло ... На самом деле надо было слегка напрячь фантазию.

Правильный вариант выглядел так:

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

SELECT first 1 * 
FROM OPERATIONS 
where account=?
order by account desc,tm desc
и firebird прекрасно воспользовался для выборки индексом по двум полям, который был создан в самом начале, выдав ожидаемое небольшое количество фетчей в статистике. Индекс выглядел так:

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

create descending index operations_account_tm on operations(account,tm)
избыточность с добавлением лишнего поля (очевидно фиксированного в данном запросе) в order by мне как-то сразу в голову не пришла, зачем-то ожидал подобного интеллекта от fb

Ответить