Как посчитать и ограничить запись в одном запросе в MYSQL? - PullRequest
16 голосов
/ 29 апреля 2009

Я ищу записи в таблице следующим образом:

SELECT Id, Name FROM my_table WHERE Name LIKE '%prashant%' LIMIT 0, 10;

Теперь я добавляю LIMIT для поддержания моего пейджинга. Но когда пользователь ищет слово «prashant», то у меня всего 124 записи «prashant». Но как ограничение, примененное к запросу, он выбирает только 10 записей в моем PHP-скрипте, и когда я считаю переменную mysql в PHP-коде, он возвращает общее количество найденных записей: 10.

Так что в основном я хочу посчитать и ограничить использование одного запроса, сделав некоторую модификацию в вышеупомянутом запросе, я хочу общее количество записей (124). Я не хочу запускать отдельный запрос count (*) для подсчета общего результата, найденного запросом.

Спасибо.

Ответы [ 5 ]

17 голосов
/ 29 апреля 2009
SELECT SQL_CALC_FOUND_ROWS
  Id, Name
FROM my_table
WHERE
  Name LIKE '%prashant%'
LIMIT 0, 10;

# Find total rows
SELECT FOUND_ROWS();

подробнее

9 голосов
/ 29 апреля 2009

MySQL поддерживает это, используя SQL_CALC_FOUND_ROWS, как упомянуто Ionut. Однако оказывается, что во многих случаях на самом деле быстрее сделать это старомодным способом, используя два оператора, где одно из них является обычным count(). Это, однако, требует, чтобы подсчет можно было выполнить с помощью сканирования индекса, что не будет иметь место для этого самого запроса, но я решил упомянуть об этом в любом случае.

6 голосов
/ 06 августа 2012

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

У меня была похожая проблема, и я не хотел создавать 2 запроса. Поэтому я создал дополнительный столбец для общего числа и переместил предложения LIMIT и OFFSET в конце:

SELECT SQL_CALC_FOUND_ROWS * FROM (
    SELECT `id`, `name`
    FROM `my_table`
    WHERE `name` LIKE '%prashant%'
) res,
(SELECT /*CEIL(FOUND_ROWS()/10) AS 'pages',*/ FOUND_ROWS() AS 'total') tot
LIMIT 0, 10

Итак, результат примерно такой:

| id  |      name      | total |
+-----+----------------+-------+
|  1  | Jason Prashant |  124  |
|  2  | Bob Prashant   |  124  |
|  3  | Sam Prashant   |  124  |
|  4  | etc. prashant  |  124  |

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

2 голосов
/ 07 февраля 2011

В случае огромных таблиц и выбора нескольких полей (не только Id, Name, как в вашем примере), я бы рекомендовал использовать 2 запроса. Сначала выберите count (0) со всеми этими предложениями WHERE, а затем постройте нумерацию страниц, выберите данные и т. Д. Например, на некоторых популярных веб-сайтах электронной коммерции он будет работать намного быстрее.

0 голосов
/ 13 декабря 2017

Не используйте SQL_CALC_FOUND_ROWS и FOUND_ROWS ()

  1. есть сообщения об ошибках
    здесь: https://bugs.mysql.com/bug.php?id=18454
    и здесь: https://bugs.mysql.com/bug.php?id=19553

  2. в то время как для небольших таблиц BENCHMARK больше зависит от других вещей, и время, которое ваш SELECT займет, будет примерно таким же, как COUNT (0) - SQL_CALC_FOUND_ROWS по-прежнему накладывает ограничения на оптимизацию базы данных LIMIT и ORDER BY, поэтому если зависеть от них не использовать SQL_CALC_FOUND_ROWS

  3. для больших таблиц разница BENCHMARK становится огромной, когда COUNT (0) может занять 0,003 секунды, тогда как SQL_CALC_FOUND_ROWS теперь может занимать 20 секунд

По всем метрикам COUNT (0) - лучший выбор

COUNT (0) SYNTAX:

(SELECT COUNT(0) FROM tableNames WHERE condition) AS alias
// alias is optional but needed if you need to use the result later

Итак, ваш общий запрос будет выглядеть так

(SELECT COUNT(0) FROM my_table WHERE name LIKE '%prashant%') AS countResults;

SELECT Id, Name FROM my_table WHERE Name LIKE '%prashant%' LIMIT 0, 10;

А потом просто вызывайте countResults, где бы вам ни понадобилось ...

Еще одним преимуществом использования COUNT (0) является то, что вы можете использовать его для поиска в той же таблице, что и здесь, или вы можете использовать его для поиска в другой таблице ...

Так, например, если у каждого найденного человека есть 3, 2, 1, 5 разных заданий соответственно ... вы можете просто добавить

(SELECT COUNT(0) FROM my_jobs_table WHERE name = name_row_in_jobs_table) AS jobs

внутри вашего оригинального SELECT вот так

SELECT Id, Name (SELECT COUNT(0) FROM my_jobs_table WHERE name = name_row_in_jobs_table) AS jobs FROM my_table WHERE Name LIKE '%prashant%' LIMIT 0, 10;

Даю вам:

--------------------
| id | Name | jobs |
--------------------
| 1  | Alice| 3    |
--------------------
| 2  | John | 2    |
--------------------
| 3  | Bob  | 1    |
--------------------
| 4  | Jill | 5    |
--------------------

Таким образом, показывая имя [3] (т. Е. Боба), вы также можете показать, что у Боба есть 1 задание, вызвав задание [3] ...

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