Как организовать разбивку результатов запроса по страницам?

Ямерт

The Old One
Как организовать разбивку результатов запроса по страницам?

В MySQL это делается очень просто: LIMIT start, length - в результате имеем нужный отрезок информации.
Как действовать, когда информация находится в базе Oracle? В мануале по Oracle SQL я решения не нашёл.
 

trent

Developer
например так:
select id, name from (select rownum rnum, id, name from (select id, name from table order by name)) where rnum between :fromResult and :toResult

жирным помечен основной запрос
:fromResult и :toResult - забинденные переменные от какой записи выбирать до какой

все переменные надо "тянуть из нутра", на примере это видно...
 

romutis

Guest
У Оракла нет стандартных функций для ограничения кол-ва выводимых результатов, аналогичных MySQL-вскому LIMIT start, length.

Всякие извращения типа "SELECT * FROM (SELECT * FROM TABLE) WHERE rownum<11" - это именно извращения, но никак не решение.

Организовывай постраничный вывод сам - фетчи записи по одной до нужного кол-ва и выводи лишь те, которые имеют номер в цикле со start до start+length.
 

romutis

Guest
trent,
твой пример - яркий пример изврата, основанного на full-scan'е таблицы. Пока таблица маленькая - еще терпимо. А если кол-во записей измеряется миллионами/сотнями миллионов? делать full-scan (считывать все записи из таблицы) для того, чтобы получить несколько записей? Не состаришься ждать результат?
 

Ямерт

The Old One
Ромутис - как тогда ты посоветуешь добиться данной цели?
ADDED: Сорри, не увидел :) Спасибо, идею понял.
 

Crazy

Developer
Можно делать так: первый запрос извлекает все первичные ключи. Затем выбираем нужный кусок и запрашиваем выборку по явно указанным N нужным ключам.
 

romutis

Guest
Crazy,
Извлечение всех первичных ключей - тот же full-scan, те же balls - только в профиль. :(

И как соотносятся нужные primary keys с "нужно выбрать записи с 40-ю по 49-ю с условием WHERE ...." ?
 

Crazy

Developer
По вопросам последовательно:

1. Никто не мешает вынести их в отдельную таблицу. :) Где больше никого нет.

2. Шаг1: находит в последовательности ключей значения с i по i+N. Шаг2: запрсшивает "select ... from ... where key in (Ki...Ki+N)". :)
 

romutis

Guest
Что-то тема начала напоминать конкурс извращенцев... :)

Пользовать конструкцию LIMIT в Оракле можно лишь в PL/SQL, считывая данные в BULK COLLECTION:
Код:
FETCH ... BULK COLLECT INTO ... [LIMIT rows]
Если BULK COLLECTION не пугают - можно ими пользоваться.
 

romutis

Guest
Crazy,

А если запрос идет не по первичному ключу, а по альтернативному индексу, например, битовому индексу? Для значений битового ключа тоже делать отдельную таблицу?

Я все-таки думаю, что простой fetch в цикле с отбрасыванием предыдущих результатов и вытаскиванием только n нужных - будет проще.
 

Crazy

Developer
Автор оригинала: romutis
А если запрос идет не по первичному ключу, а по альтернативному индексу, например, битовому индексу? Для значений битового ключа тоже делать отдельную таблицу?
Ok, показываю на примере. Пусть есть сущность goods, разложенная на две таблицы: goods_head (id) и goods_body(id,title,price). Строим запрос для извлечения всех id товаров дешевле 100:

Код:
select goods_head.id 
  from goods_head, goods_body
  where( goods_head.id = goods_body.id)
    and( goods_body.price < 100 )
Если есть индексы по goods_body.id и goods_body.price, то единственный tablescan который мы теоретически можем получить, есть tablescan по goods_head.
 

romutis

Guest
Crazy,

Ок, стандартный запрос по твоему условию возвращает 50 000 записей, подходящих под условие.
Вернуть нужно записи с 1220 по 1230, отсортированные по убыванию цены.
И, кстати, какая радость в дублировании id? В твоем примере кол-во ID в heads = кол-ву ID в body. И если ассортимент большой - то те же balls - full-scan большой таблицы (которая heads).


А если сущность (сборная) такова? :
Василий|Иванович|Чапаев|М|12.01.1901|г. Чапаевск|ул. Чапаевская|10А|21|232-22-15|командир взвода тяжелых пулеметов|истинный ариец|

Сущностей - 5 млн. Обновляются редко, но селектятся очень часто и по самым разным комбинациям полей/признаков (фамилия, геогр. принадлежность, пол, телефон).
Дублируем, например, телефоны в отдельной таблице и фуллсканим эти несчастные 5 млн. телефонов? Никаких ощутимых бенефитов - 100 пудов.
 

Crazy

Developer
Автор оригинала: romutis
И, кстати, какая радость в дублировании id? В твоем примере кол-во ID в heads = кол-ву ID в body. И если ассортимент большой - то те же balls - full-scan большой таблицы (которая heads).
Радость в том, что подавлябщая часть контента исключена из TableScan'а. Т.е. мы читаем в 10-100 раз меньше информации.

Дублируем, например, телефоны в отдельной таблице и фуллсканим эти несчастные 5 млн. телефонов? Никаких ощутимых бенефитов - 100 пудов.
При чем здесь телефоны? Они у тебя сделаны первичными ключами?
 

romutis

Guest
Автор оригинала: Crazy
Радость в том, что подавлябщая часть контента исключена из TableScan'а. Т.е. мы читаем в 10-100 раз меньше информации.
Слушай, если мы будем делать select только id из большой таблицы - мы считаем ровно такой же объем инфы. Или ты про block_read?



Автор оригинала: Crazy
При чем здесь телефоны? Они у тебя сделаны первичными ключами?
Нет, но, к примеру, 30% запросов составляет поиск персоны/персон по номеру/маске телефона. Что тут делать бум?

И вообще - что делать, если primary key не участвует в выборке или выборка по нему не является оптимально с точки зрения performance (см. вышеприведенный пример про телефоны)?
 

Crazy

Developer
Автор оригинала: romutis
Слушай, если мы будем делать select только id из большой таблицы - мы считаем ровно такой же объем инфы. Или ты про block_read?
Это зависит от конкретной СУБД. В общем случае запись читается с диска целиком -- прочитается не только id, но и все остальные поля. Та или иная СУБД может оптимизировать процесс (вплоть до того, что может не обращаться к таблице, если есть индекс по данному полю).

Нет, но, к примеру, 30% запросов составляет поиск персоны/персон по номеру/маске телефона. Что тут делать бум?
Делать индекс по этому полю -- как всегда.

И вообще - что делать, если primary key не участвует в выборке или выборка по нему не является оптимально с точки зрения performance (см. вышеприведенный пример про телефоны)?
Прости, я не понял ни этой фразы, ни приведенного выше примера.
 

romutis

Guest
Автор оригинала: Crazy
Это зависит от конкретной СУБД.
А я думал что мы в Оракловском форуме находимся и обсуждаем именно Оракл а не "сферических коней в вакууме"... :)


Автор оригинала: Crazy
Делать индекс по этому полю -- как всегда.

Прости, я не понял ни этой фразы, ни приведенного выше примера.
Индекс по полю "телефон", который не является первичным индексом (бо глупо делать из номера телефона первичный признак человека) и не вынесен в отдельную таблицу - не вписывается в написанное тобой решение. Но вписывается в то, что написал я - причем мой вариант будет почти всегда работать быстрее, за счет отсутствия full-сканов и join'ов (для какой бы то ни было таблицы).
 

Crazy

Developer
Автор оригинала: romutis
А я думал что мы в Оракловском форуме находимся и обсуждаем именно Оракл а не "сферических коней в вакууме"... :)
Т.е. ты хочешьс казать, что Oracle умеет при tablescan делать выборочную загрузку указанных полей?

Индекс по полю "телефон", который не является первичным индексом (бо глупо делать из номера телефона первичный признак человека) и не вынесен в отдельную таблицу - не вписывается в написанное тобой решение.
Почему goods_body.price вписывается, в phone -- не вписывается?
 

romutis

Guest
Crazy, для Оракла критичным является кол-во считанных блоков. А что там содержится - одно поле или вся запись целиком - это уже вопрос номер 16. И это отнюдь не является самой критичой проблемой, верь мне. Но здесь мы отклоняемся в админскую область, о которой девелоперам знать не обязательно. :)

Про телефоны: распиши, пожалуйста, вкратце свое видение телефонного справочника с учетом разнообразных выборок разных полей при различных сочетаниях полей, участвующих в выборке. Как для выборке по маске телефонного номера использовать вторую таблицу? Какие это даст бенефиты (учитываем первый абзац этого сообщения)?

P.S. Я даже готов сделать реальные таблицы для такой структуры, набить их всяким <beep> и предоставить тебе результаты EXPLAIN PLAN для разных вариантов выборок.
 

Crazy

Developer
Автор оригинала: romutis
Crazy, для Оракла критичным является кол-во считанных блоков.
Как и в любой СУБД.

А что там содержится - одно поле или вся запись целиком - это уже вопрос номер 16.
В данном случае нас интересует то, как хранятся записи: поля записей последовательно, запись за записью? Или вначале все поля A, потом все поля B и т.п.? :)

Но здесь мы отклоняемся в админскую область, о которой девелоперам знать не обязательно. :)
Лично я с удовольствием послушаю.

Шеф, ты последовательно уводишь обсуждение в сторону от темы. Вернемся к началу:

Чем твой пример с телефонами принциально отличается от моего с товарами?

P.S. Я даже готов сделать реальные таблицы для такой структуры, набить их всяким <beep> и предоставить тебе результаты EXPLAIN PLAN для разных вариантов выборок.
Прекрасно. Пусть у нас будет таблица phones_body, в которой есть целочисленное поле id, являющееся первичным ключом и поле phone типа char(20), по которому построен индекс. И еще пусть там жу будет штук 20 полей foobar1..foobar20 типа char(100) со всяким мусором. И будет у нас таблица phones_head с единственным целочисленным полем id, которое является первичным индексом.

Занесем в таблицу 100,000 пар записей и посмотрим план запроса:

Код:
select phones_head.id 
  from phones_body, phones_head
  where( phones_body.phone > '111111')
    and( phones_body.phone < '22222')
    and( phones_body.id = phones_head.id )
Хочу посмотреть, будет ли в плане table scan по phones_body (и вообще -- будет ли он).

Thanx.
 
Сверху