Как можно узнать количество рядов, которые вернул SELECT-запрос?

Ямерт

The Old One
Как можно узнать количество рядов, которые вернул SELECT-запрос?

Вопрос, наверное, глупый, но я никак не могу это дело красиво решить.

Стандартной OCI8 функции нет.
Поэтому я придумал следующее:

function rowcount()
{
$myarray = array();
return OCIFetchStatement ($statement, $myarray);
}

Кол-во рядов функция, конечно, возвращает, но из результата больше ничего нельзя вытащить - выдаётся ошибка OCIFetch: ORA-01002: fetch out of sequence.

Неужели надо вычислять кол-во рядов единственно через запрос?
Или указатель на текущий ряд в курсоре можно вернуть к первому ряду?
 

trent

Developer
Re: Как можно узнать количество рядов, которые вернул SELECT-запрос?

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

trent

Developer
я считаю количество рядов из выборки вот так, если не нужен постраничный вывод
$numRow = 0;
while(OCIFetch($stmt))
{
$numRow++;
}
 

ruslan

Guest
to trent
А что используешь для постраничного вывода, если не секрет??? Я единственное, что смог придумать - тройной вложенный запрос (чтобы получать данные как привык в mysql'е с limit-ом). Может что-то оптимальней подскажешь?

P.S. мне кажется, что если мне надо получить записи, например с 1000 по 1020 (из 2000-3000 записей всего), фетчить их по одной не очень оптимально (в смысле быстро и по идее должно сильно напрягать Оракл, если таких запросов много будет). Я прав? Как с этим лучше работать?
 

trent

Developer
есть еще вариант
select * from table where rownum <= 5
minus
select * from table where rownum <= 0

что-то типа лимита в mysql, но
во-первых, еще не тестил что быстрее, три вложенных запроса или этот
во-вторых в этом запросе так и не смог сделать сортировку и как мне кажется ее нельзя делать
 

ruslan

Guest
Я пользуюсь вот этим:
PHP:
//$query - исходный запрос
$adv_query = 'select * from (select first.*, rownum as linenum from  ('.$query.') first ) where linenum>'.intval($start).' and linenum<='.intval($finish);
Вроде сортировку позволяет делать, но вот по скорости не знаю... Если будешь сравнивать выложи результаты плз., интересно посмотреть, а самому времени проверять пока нет.
 

romutis

Guest
Автор оригинала: ruslan
Я пользуюсь вот этим:
PHP:
//$query - исходный запрос
$adv_query = 'select * from (select first.*, rownum as linenum from  ('.$query.') first ) where linenum>'.intval($start).' and linenum<='.intval($finish);
На больших таблицах - смерть (от старости того, кто запустил). :)

Для примера запустил такой селект на таблице в 120 млн записей - кранты, невзирая на очень мощный сервер (вернее, выполнялось на Real Application Cluster 9.0.1.3 - 2 IBM T1 c 6-ю процами, 32GB памяти каждый и общим дисковым array в 1.5 Терабайта - кластер настроен так, что любой селект автоматически дробится на 32 подселекта и обсчитывается обоими серверами). Долго... В любом случае как минимум один фуллскан таблицы.

Для маленьких таблиц - работает хорошо, но "you never know" - большая это таблица или нет.
 

ruslan

Guest
Спасибо!
А маленькая таблица - это сколько (5000-10000 записей или меньше)? Т.е. где его можно более-менее безболезненно использовать?

P.S. может у кого-нибудь есть варианты, как запрос с ограничением сделать оптимальней??? Поделитесь :) !!!
 

romutis

Guest
ruslan:

тестируй сам - замеряй время по select count(*) from table и потом делай селект такого плана:
SELECT * FROM table WHERE rowid in (
SELECT rowid FROM table WHERE rownum <51
MINUS
SELECT rowid FROM table WHERE rownum < 41
);

Если больших торомозов на твоей конфигурации не обнаружится - можно и пользовать.

P.S. Есть еще варианты использовать DBMS_ROWID package - но там код получается не менее извратный и не факт, что быстрее.
 
Сверху