За последние 24 часа нас посетили 54479 программистов и 1780 роботов. Сейчас ищут 895 программистов ...

пагинация

Тема в разделе "Прочие вопросы по PHP", создана пользователем engager, 23 ноя 2010.

  1. engager

    engager Активный пользователь

    С нами с:
    21 янв 2009
    Сообщения:
    1.106
    Симпатии:
    1
    всем салют.
    озадачился вот какой проблемой, как бы пооптимальнее сделать пагинацию?
    проблема в чем? для пагинации нужно знать количество выводимых на странице айтемов (это не проблема есессно) и количество записей в таблице (это проблема).
    мне видится два способа:
    1. за один селект получаем все записи, тем самым узнаем количество записей - это плюс, но минус очевиден - объем возвращаемых данных и лишнее время на фетч (хотя, подозреваю, можно сделать какой-то seek).
    2. два запроса к базе. первый - select count(*)... получаем количество записей, второй select ... limit page_num * page_size, page_size. собственно, все, что являлось в предыдущем подходе плюсом становиться минусом и наоборот.

    вопрос: есть ли какой-нибудь третий способ?
     
  2. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    Первый способ допустим только если база маленькая, и по каким либо причинам неразумно/трудно/лень/итд использовать второй способ. (я использую на своей гостевухе, БД у меня в файле, по этому в 10000 раз проще реализовать чем второй способ)

    Второй способ идеален для работы с СУБД.
     
  3. kotyara

    kotyara Активный пользователь

    С нами с:
    17 фев 2010
    Сообщения:
    163
    Симпатии:
    0
    если таблица к которой идет обращение не слишком большая, запрос хорошо оптимизирован и нет существенной разницы во времени исполнения между запросом затрагивающий все строки и лимитированным то имеет смысл одним запросом вытягивать все значения. mysql_num_rows() этой функцией получить общее количество записей, ограничить вывод строк в рнр цикле. если же количество возвращаемых строк достаточно велико, или запрос сложен и есть существенная разница, вытянуть 10 строк или же 10000, то в этом случае конечно двумя запросами будет рациональней. Третьего способа не встречал, но вполне возможно он есть.
     
  4. engager

    engager Активный пользователь

    С нами с:
    21 янв 2009
    Сообщения:
    1.106
    Симпатии:
    1
    ну вот для мускуля, к примеру, можно такой сделать трик:

    [sql]select
    mysc.*, isch.table_rows
    from
    my_schema.my_table mysc
    join
    information_schema.tables isch
    on
    isch.table_schema='my_schema' and isch.table_name='my_table'
    limit 20, 10;
    [/sql]

    здесь мы приджоинили столбец с количеством строк таблицы. способ может и не самый красивый, но оптимальнее первых двух.
    в других субд также существует подобие information_schema, хотя меня конкретно интересует мускуль.
    что скажете?
     
  5. kotyara

    kotyara Активный пользователь

    С нами с:
    17 фев 2010
    Сообщения:
    163
    Симпатии:
    0
    с тем же успехом можно создать вьюху с подсчетом кол-ва строк внутри рабочей БД и использовать ее, мне кажется так будет быстрей работать, хотя могу заблуждаться - эксперимент не ставил
     
  6. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    COUNT - нормально. Если слишком большая таблица, число строк можно хранить в другой таблице.
     
  7. runner

    runner Активный пользователь

    С нами с:
    16 апр 2010
    Сообщения:
    343
    Симпатии:
    1
    Адрес:
    Ташкент
    Тема уже поднималась. Если вкратце, то есть два варианта
    вариант 1- если не используется group by и distinct, то лучше использовать два запроса
    первый запрос на выборку записей с использованием limit, а второй тот же запрос только вместо полей вывода подсчет числа записей

    запрос на выборку
    $query="select name, code from users where code>100 limit 0,10";

    запрос на получение числа записей
    $query="select count(*) from users where code>100";

    вариант 2- если используется group by или distinct, то использовать запрос со словом SQL_CALC_FOUND_ROWS для выборки самих записей с использованием limit, а число записей получать используя функцию FOUND_ROWS()

    на выборку
    $query="select name, code from users where code>100 group by user_group limit 0,10";

    на получение числа записей
    $query="select FOUND_ROWS()";
     
  8. engager

    engager Активный пользователь

    С нами с:
    21 янв 2009
    Сообщения:
    1.106
    Симпатии:
    1
    runner
    1. искал, не нашел похожих тем.
    2. SQL_CALC_FOUND_ROWS - я так понимаю, вернет количество строк датасета, а он ведь лимитрован выражением limit - отсюда мы не узнаем количество строк всей таблицы.

    [vs]
    число строк и так хранится в другой таблице (information_schema.tables). другое дело, что count не просто всех записей таблицы нужно знать, а кол-во отфильтрованных записей (напр. результаты поиска).

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

    runner Активный пользователь

    С нами с:
    16 апр 2010
    Сообщения:
    343
    Симпатии:
    1
    Адрес:
    Ташкент
    1) я не совсем точно выразился - там было обсуждение, что быстрее первый или второй способ получения общего количества записей: с count(*) или используя SQL_CALC_FOUND_ROWS. В обоих случаях нужно выполнять два запроса

    2) общее число записей, удовлетворяющих запросу получается выполнением второго запроса
    $query="select FOUND_ROWS()";
    причем сразу после выполнения первого с SQL_CALC_FOUND_ROWS

    В мануале в вольном переводе это звучит так
    Запрос на выборку записей может включать LIMIT для ограничения возвращаемых сервером записей. В некоторых случаях желательно знать, сколько записей будет возвращено без использования LIMIT, но без повторного исполнения запроса. Для получения этого числа включите SQL_CALC_FOUND_ROWS и затем вызовите FOUND_ROWS():

    mysql> SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name
    -> WHERE id > 100 LIMIT 10;
    mysql> SELECT FOUND_ROWS();

    Второй SELECT вернет количество записей, которое вернул бы первый SELECT если бы был написан без LIMIT
     
  10. engager

    engager Активный пользователь

    С нами с:
    21 янв 2009
    Сообщения:
    1.106
    Симпатии:
    1
    runner
    мм, лана, попробуем.
    тханкс)
     
  11. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    SQL_CALC_FOUND_ROWS - зло, гугл.
    делать count()