Правильний count () в mysql - записки шукачів

Час від часу, читаючи чужий код, бачу що деякі розробники вказують різні параметри в функцію COUNT () для отримання колічетсво рядків.
Наприклад: count (*), count (id) (де id - це primary key). count (0).
Виникає питання: "Який count () правильний? А які лже-count-и? "
За основу "правильності" взяв швидкість виконання запиту.
Виконав 3 запити:


У всіх трьох отримав час виконання 0.03 - 0.04 сек. і, як не дивно, один і той же результат - число 47915774.

Знайшов в документації таке:

Варто відмітити, що за браком інших, тести я робив на MyISAM-таблиці.

По суті нічого дивного тут немає, тому йдемо далі.
Є в моїй табличці індексне поле
`C_time` datetime NOT NULL default '0000-00-00 00:00:00'

Виконую ці ж 3 запити але з обмеженням на c_time:

У перших двох випадках отримую час виконання запиту 2.84 - 3.15 сек, а в третьому 27.46 - 28.34 (.) Сек.

Звертаюся до святая святих всіх MySQL-гуру - EXPLAIN запитом і дізнаюся, що в останньому випадку в поле Extra "світиться" значення "Using where", в той час як в перших двох запитах Extra показує "Using where; Using index".

На цій трагічній ноті мої тести закінчилися.
Цікаво ще взгянуть на подібні результати в запитах, в яких WHERE виконується по неключових полю, а також на НЕ MyISAM-таблицях.

P.S. До речі, сам, з якихось невідомих мені причин, користуюся count (*).

19 Responses to "Правильний count () в MySQL"

Зауваж, що якщо використовуєш індекс при отриманні кількості рядків запитом
SELECT COUNT ( `id`) as cnt FROM` users` USE INDEX (as_id) WHERE `siteuser` = 1 '. AND `active` = 1 ':
то час виконання менше ніж у count (*) і count (0), тобто при використанні індексів краще використовувати 'id'
у мене Ідекс as_id дорівнює зв'язці стовпців id, siteuser і active.

Ідекс as_id дорівнює зв'язці стовпців id, siteuser і active.

А навіщо id туди Сува?
Підозрюю що id у тебе primary key, який по суті є і індексом.

да, але вибірка - то робиться не тільки в прімарі, але і в siteuser і active

але вибірка - то робиться не тільки в прімарі, але і в siteuser і active

А якщо у тебе будуть робитися вибірки по всім комбінаціям з 5ти полів - ти будеш 120 індексів з усіма комбінаціями полів створювати?

Що заважає MySQL використовувати 2 індексу?
Перший - primary key (id), другий key (siteuser, active)
Або навіть 3: primary key (id), другий key (siteuser), key (active)?

Сенсу додавати id в складовою індекс просто немає: якщо буде вказано id, то MySQL скористається primary key і на інші індекси навіть дивитися не буде.
У разі якщо в запиті id не вказано то твій складовою індекс теж буде як мертвому припарка, тому що індексу по парі (siteuser, active) у тебе немає, є тільки по трійці (id, siteuser, active).

Питання хороший що йому заважає, тому що він не використовує їх.
А зробивши складовою індекс і вказавши використовувати його я домігся зміни швидкості запиту з 8-ми секунд до 0,7 сек.
Є їжа для мізків.

Чому MySQL не використовує індекс - це окрема тема, і до функції COUNT не відноситься.
Цілком можливо що оціночна кількість рядків в результаті становило більше 15-20% від загальної кількості - в такому випадку оптимізатор вважає що краще провести fullscan таблиці ніж використовувати індекси. Але до іноді жаль він помиляється.

P.S. Сподіваюся питання чому не варто додавати primary key в складовою індекс вже не варто?

спасибі вам, дуже допоміг пост.
я надів на осудність внутренего оптимізатора mysql.
небагато в шоці, вік живи вік учись. - |

EXPLAIN SELECT SQL_NO_CACHE count (0)
FROM `news`
WHERE `type` = 2

id | select_type | table | type | possible_keys | key | key_len | ref | rows | extrara
1 | SIMPLE | news | ref | type | type | 4 | const | 8623 | Using where; Using index

а при count (id) маємо тільки Using where великі лаги.

Скільки рядків всього в таблиці?
Скільки з них підпадає під умову `type` = 2?
Який тип має поле type?
По ньому побудований індекс?

Є підозра що при count (0) оптимізатор вирішує що вигідніше буде виконати fullscan все таблиці замість використання індексу (таке буває коли очікувана кількість записів перевищує 20-25% від загального).
Чому в даному випадку так само не відбувається при count (id) - сказати складно.