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

как лучше реализовать агрегатный first / last

Добавлено: 25 окт 2007, 19:31
rilu
Проблема в общем классическая, но хорошего решения до сих пор не нашёл. Есть три связанных таблицы, из которых нужно выбрать на каждый день последнюю (в смысле соответствующую наибольшему времени в рамках текущего дня) цену по каждой группе товара. Приблизительно так

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

select cast(pr."prt_date" as DATE) as "prt_date", p."pst_puid", max(p."pst_cost")
  from PRICE_RELATIONS pr
  inner join PRICES pp on (pr."prt_price" = pp."prc_id") 
  inner join POSITIONS p on (p."pst_price" = pp."prc_id") 
  where (pr."prt_date" >= :"fdate") and (pr."prt_date" <= :"todate")
  group by cast(pr."prt_date" as DATE), p."pst_puid"
тока есессно этот запрос выбирает максимальную цену вместо последней. добавить к нему ордер и агрегатный first и всё было бы готово. а так перебрасываем это дело во вьюшник и получаем

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

  select cast(v."prt_date" as DATE) as "prt_date", p."pst_puid", 
      ( select first 1 v2."pst_cost"
          from VW_GROUPED_POSITIONS v2
          where (cast(v."prt_date" as DATE) = cast(v2."prt_date" as DATE))
            and (v."pst_puid" = v2."pst_puid")
          order by v2."prt_date" desc
      )
    from VW_GROUPED_POSITIONS v
    where (v."prt_date" >= :"fdate") and (v."prt_date" <= :"todate")
    group by cast(v."prt_date" as DATE), v."pst_puid";
т.е. в принципе результат получили. но для для второго запроса кол-во обращений прилично выросло, с десятков до тысяч на тестовой выборке. учитывая что этот запрос крутиться в цикле то радости совсем мало. насколько я понимаю кроме такого варианта остаётся тока хп. но я сильно сомневаюсь что хп отработает быстрее. всё таки через индексы оптимизация запроса своё даст, а там в лоб циклом всё перебирать и джойнить результат дальше... на форуме чёт ничего такого не нашёл, кроме http://forum.ibase.ru/phpBB2/viewtopic.php?t=2164 но и там как-то не много чего полезного оказалось...
в общем, буду благодарен за советы или идеи
з.ы. fb2, индексы по всем используемым полям
з.ы.ы. я плохо искал или я реально один с такой проблемой? если не один тогда почему first/last не были реализованы? а если один, тогда я не понимаю как можно переделать архитектуру базы, чтобы решить эту задачу без лишнего гемора...
В общем, заранее спасибо...

Добавлено: 25 окт 2007, 21:20
WildSery
1. Неясно, зачем тебе идентификаторы в кавычках. ИМХО только жисть себе усложняешь. А уж имена параметров в кавычках...
2. Про соединение двух вьюх ты круто ошибаешься, кажись не будут там индексы использоваться.
3. Не совсем понятна структура.
Почему дата в PRICE_RELATIONS? Один прайс может быть прицеплён более одного раза? А в один и тот же день?

Добавлено: 26 окт 2007, 16:20
rilu
1. да както сложилась традиция такая :) а переделывать/перепривыкать смысла счас нет.
2. ошибаюсь в чём?? я ж вроде про них ничиво и не говорил )) я только привёл как я решил задачу на сейчас, в смысле что второй запрос формирует нужную выборку. тока медленно, многовато там чтений выходит. кстати ib expert показывает одинаковый план что для первого что для второго. а количество чтений на два порядка больше.
3. price_relations содержит скажем так ключевые даты, это кусок для оптимизации. и для каждой из таких дат указывается какие прайсы актуальны на этот момент. так что там только два поля - ссылка на прайс и дата. а так у прайса своя жёсткая дата, которая и является первичной. в общем джойн relations и prices даёт что-то вроде
21/01 прайс_1
21/01 прайс_2
21/01 прайс_3
24/01 прайс_1
24/01 прайс_2_новый
24/01 прайс_3
etc
ну и дальше джойним с позициями. в частном случае имеем что в один календарный день может попасть несколько таких дат и нужно выбрать данные соответствующие прайсу с большим временем. ну или в общем случае последний в заданном интервале дат.

Добавлено: 02 ноя 2007, 15:58
rilu
так что, никто не посоветует как оптимизировать эту операцию??

Добавлено: 02 ноя 2007, 17:47
Slavik
Во-первых, я бы не отметал с ходу вариант с хранимой процедурой. Самые медленные операции - дисковые, а правильно написанная хранимая процедура нормально использует индексы и может существенно уменьшить кол-во повторно считываемых данных. Надо тестировать и сравнивать, а не сомневаться на пустом месте.

Во-вторых, безалаберное использование то просто pr."prt_date", то cast(pr."prt_date" as DATE) осложняет жизнь оптимизатору и затрудняет нормальное использование индексов. А уж повторный cast(v."prt_date" as DATE) - вообще лишний и даже вредный.

В-третьих, в данном случае вполне возможно обойтись одним сложным запросом, если уж очень надо.

В-четвертых, приведи уж структуру этих трёх таблиц с описанием. Гадать неохота, а необходимость в таблице PRICE_RELATIONS сомнительна, ведь дату-время начала действия прайса можно хранить прямо в прайсе.

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

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