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

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

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

есть таблица, в которой хранятся некоторые данные (на самом деле задача типовая), пусть будет такая:
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 этот индекс не используется, как бы мне не хотелось (перепробовал все, что в голову пришло)

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

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

Добавлено: 20 дек 2009, 14:12
Dimitry Sibiryakov
Почитай это.

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

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

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

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

Добавлено: 21 дек 2009, 01:26
pticelov
Дошло ... На самом деле надо было слегка напрячь фантазию.

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

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

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