LINUX.ORG.RU

sql извраты - количество записей и paging


0

0

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

      select * from (
        select a_page.*, ROWNUM rnum
          from ( $statement$ ) a_page
          where ROWNUM <= #endRow#
        )
        where rnum  >= #startRow#

(это ibatis) где $statement$ - собстно запрос, и все это для вывода результатов постранично. Но возникает задача как получить общее кол-во страниц (или хотябы записей)?

В качестве временного решение второй запрос

select count(1) from ( $statement$ )
результаты которго сохраняются в сессии (вебприложения), но этот путь не кошерен, есть ли альтернатива?

★★☆

> этот путь не кошерен

Если RDBMS скомпилировать с libastral.so, то она сможет узнавать о том, сколько всего строк удовлетворяет твоему запросу без извлечения всех строк из базы.

anonymous
()

если ты об оракле - вприииинципе, нормально.

только тебе придётся вложенность делать +1 для случая order by
или пользоваться вариантом
select *
from (
  select ...,row_number() over (order by ...) as rn
  from ...
  where ...
)
where rn>:offset and rn<:offset+:size


и кстати, не забывай про :\w+

vahvarh ★★★
()
Ответ на: комментарий от vahvarh

Такой финт ушами должен быть повторяем на других субд (db2 firebird), причем одним запросом иначе когда придется переносить столкнемся с трудностями.

wfrr ★★☆
() автор топика
Ответ на: комментарий от vahvarh

мне кстати нужно не просто постранично вывести (что я нашел как делается у тома кайта) а получить кол-во страниц .

wfrr ★★☆
() автор топика
Ответ на: комментарий от vahvarh

Как отвечает на вопрос " как получить общее кол-во страниц"?

anonymous
()

> Есть некий запрос с order by и т.п. его строит хитрый алгоритм, я беру эту строку и заворачиваю в :

Кстати, чем тебе limit и count не угодили?

> В качестве временного решение второй запрос <div class="code">select count(1) from ( $statement$ )</div> результаты которго сохраняются в сессии (вебприложения), но этот путь не кошерен, есть ли альтернатива?


Если с логикой запроса не разбираться, то нет.

gaa ★★
()
Ответ на: комментарий от gaa

>Кстати, чем тебе limit и count не угодили?

В энтрепрайзном оракле нетути.

>Если с логикой запроса не разбираться, то нет.


Там логика элементраная - пачка полей - фром 1_таблица и куча джойнов потому where и order by

wfrr ★★☆
() автор топика
Ответ на: комментарий от wfrr

>> Если с логикой запроса не разбираться, то нет.

> Там логика элементраная - пачка полей - фром 1_таблица и куча джойнов потому where и order by


Ну так разберись тогда, сколько запрос вернёт, раз там элементарно :)

gaa ★★
()
Ответ на: комментарий от gaa

ну дык, как разобратсья ? Как варинат было встраивание select ... , count(1) over() countofrows from .... во унутренний запрос, тогда просто у выбранных записей будет поле countofrows имеющее значение равное кол-ву записей выданных внутренним запросом, однако как это повлиеят на производительность.

wfrr ★★☆
() автор топика
Ответ на: комментарий от wfrr

Как ни крути, а без libastral.so строки считать придётся все. Если ты хочешь универсальности. Если ты можешь пожертвовать универсальностью или функционалом в угоду производительности - придётся тебе тут расписывать свою задачу подробно и выслушивать множество откликов про шревты..

Навскидку варианты решения:
0. Забить на производительность и тупо селектить count() по тому же условию. По вкусу добавить процессоров, поставить более производительный дисковый массив, добить памяти.
1. Отказаться от пейджинга. Вот зачем тебе нужен пейджинг? Тому, кто кто-то ищет последовательно перебирая страницы - какая разница сколько там миллионов страниц ты ему можешь предложить, он всё равно умрёт раньше, чем просмотрит их все. А если речь о трёх-четырёх страницах - я не понимаю почему у тебя вообще вопрос встал.
2. Частично отказаться от пейджинга - как это сделано у гугла или ебая.
3. Если набор условий для поиска конечен - создать таблицу с записями для каждой комбинации и держать в ней счётчики. При каждой вставке записи в основную таблицу инкрементировать счётчики с удовлетворяющими условиями, при удалении - декрементировать. Раз в сутки проверять соответствие счётчиков для выявления багов.

anonymous
()
Ответ на: комментарий от wfrr

> ну дык, как разобратсья ? Как варинат было встраивание select ... , count(1) over() countofrows from .... во унутренний запрос, тогда просто у выбранных записей будет поле countofrows имеющее значение равное кол-ву записей выданных внутренним запросом, однако как это повлиеят на производительность.

ну вот если у тебя в запросе стоит что-то вроде

select t.a, sum(t.b) from table t group by t.c

то количеством будет

select count(distinct t.c) from table t

Ну и т.д.

gaa ★★
()
Ответ на: комментарий от wfrr

> В энтрепрайзном оракле нетути.

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

Casus ★★★★★
()
Ответ на: комментарий от Casus

Нет, это безумие - кешировать результаты запроса для каждой сессии. Oracle кеширует блоки данных и индексы. Если кроме count() он будет тянуть ещё и данные, которые ему потребуются в другом запросе, то возможно, некоторые блоки останутся в кеше ко времени второго запроса и будут использованы. Только тогда ему придётся тащить все записи, удовлетворяющие условию там, где, возможно, в этом нет необходимости, если поля, использованные в условии, проиндексированы и эти записи всё равно не поместятся в памяти.

Кстати, Oracle ещё кеширует результат парсинга запроса что бы минимизировать использование CPU на на такие затратные операции, но и этот кешинг идёт коту под хвост, поскольку сам запрос у него непостоянен ибо "его строит хитрый алгоритм" - т.е. парсинги ему тоже обеспечены.

anonymous
()
Ответ на: комментарий от gaa

нет, там еще where который отсекает часть записи попадаются джойны из-за которых записи дублируются. Кое-кто советовал мне не ипстись а взять тупо рекордсет и выковырять из него нужное колво записей. (на java) однако я потестил оба результата с пейджингом на стороне вебприложения весьма тормозно получается. Да и plsql в режиме разбора запроса (f5) утверждает что запрос с count(1) over() весит даже меньше чем без пайджинга вообще.

wfrr ★★☆
() автор топика
Ответ на: комментарий от wfrr

> нет, там еще where который отсекает часть записи попадаются джойны из-за которых записи дублируются.

Ну и это учти, делов-то. В любом случае придётся поскрипеть мозгами. Ну или писать тормозно, но просто: "select count(*) ..."

gaa ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.