Час від часу, читаючи чужий код, бачу що деякі розробники вказують різні параметри в функцію 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) - сказати складно.