Скорость работы COUNT(*)

sokol

Zavolga.Net
Скорость работы COUNT(*)

В таблице ~18000 записей.
Нужен постраничный вывод, но большую часть времени в запросе занимает тот самый COUNT(*) который считает общее количество записей.

Как оптимизировать эту операцию? Или здесь уже ничего не поделаешь?

Есть вариант перекидывать часть записей в архивную таблицу, чтобы в активной таблице было порядка 1000 записей.

И еще один вопрос по этой же теме:
Почему LIMIT 30, 30 отрабатывает быстрее чем LIMIT 3000, 30

Судя по EXPLAIN mysql просамтривает боьшее количество записей при LIMIT 3000, 30. Возможно ли это оптимизировать?
 

Фанат

oncle terrible
Команда форума
нет, невозможно.
хотя можно, наверное, извратиться, сортируя в обратном порядке и обратно сортируя в скрипте. но оно тебе надо?
как часто пользователи переходят на трехсотую страницу?
часть времени в запросе занимает тот самый COUNT(*)
шо, таки большую, чем LIMIT 3000, 30?
ну так сделай уже индекс!
 

rudik

Developer
По поводу COUNT я особо не понял вопрос, но может тебе поможет SELECT SQL_CALC_FOUND_ROWS ... и SELECT FOUNDED_ROWS() .
 

sokol

Zavolga.Net
Фанат WHERE может быть совсем пустой, только LIMIT и все... Где и зачем тут индекс? На нужных полях по которым может быть объединение индексы стоять.
Кстати если в WHERE ставишь хотя бы id > 0, то ускорение в запросе порядка 30%.
 

sokol

Zavolga.Net
Фанат
На зрение не жалуюсь. Цифры сравнивать тоже умею:)
Я не считал, просто смотрю чисто визульно в консольном менеджере время выполнения.

rudik хороший вариант, решил использовать именно его.
Только (need MySQL >= 4)
 

Фанат

oncle terrible
Команда форума
Я не считал, просто смотрю чисто визульно
ню-ню.
на будущее.
с субъективными ощущениями впредь обращайся к психиатру или священнику, а не на форум.
 

man2d

Guest
Кстати если в WHERE ставишь хотя бы id > 0, то ускорение в запросе порядка 30%.
А если, скажем, в таблице поле id установлено как unsigned/unsigned zerofill?
 

Фанат

oncle terrible
Команда форума
man2d
ты кого спрашиваешь? этого субъективного фантазёра?
он давно ушел.
спрашивать у него ничего не надо.
Все, что он тут понаписал - это плоды разглядывания результатов работы своих шаловливых ручек. подозреваю - с большого бодуна.

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

Vlad DraKula

Guest
sokol
что у тебя с базой не так я такие запросы к таблице из 4000000 записей писал и все работало быстро (рорядка 0,01-0,0001с )(время выполнения всего скрипта)(на локальной машине АМД 1800+ХР 512памяти)

sokol
то что на выборку:
LIMIT 3000, 30
надо больше времени чем на:
LIMIT 30, 30
ни как не проаптимизируешь.

зато можно просто уменишить выборку каколибо оптимизицией.

ты выбираешь по индексам или просто по полям?
у тебя только необходимые поля проиндексированы?
 

lucas

Guest
Если не ошибаюсь, при использовании COUNT(*) и отсутствии WHERE, информация берется непосредственно из описания таблицы, так что слухи о диких тормозах явно преувеличены.
 

lucas

Guest
Если не ошибаюсь, при использовании COUNT(*) и присутствии WHERE, информация берется непосредственно из описания индекса по столбцу из условия, так что слухи о диких тормозах явно преувеличены. :)
 

sokol

Zavolga.Net
lucas
Не ошибаешся. Но если есть хотя бы один LEFT JOIN это правило не работает.

Объединение данной таблицы (~18000 записей) с таблицей в которой порядка 500 записей по [первичный ключу<->индекс] и вычисление COUNT(*) занимает у меня 1.7 - 2 сек.

Фанат
Специально для тебя, из истории:

Толстой (не Лев, если не изменяет память Николай) каждые выходные приглашал друзей для прогулок по саду. Они говорили о политике, науке, литературе и.т.д Так вот когда он слышал, что кто-нибудь из друзей говорил о другом человеке плохо, неважно пусть даже тот о ком говорили был последней тварью, он никогда больше не приглашал этого человека к себе в гости и вычеркивал его из списка знакомых.
 

Falc

Новичок
sokol
Скорость работы COUNT в основном зависит от кол-ва пересчитываемых записей ( естествено если все условия и связи идут по индексам ). Так что может просто попробовать уменьшить кол-во выбираемой информации.

>>Не ошибаешся. Но если есть хотя бы один LEFT JOIN это правило не работает.

>>Объединение данной таблицы (~18000 записей) с таблицей в которой порядка 500 записей по [первичный ключу<->индекс] и вычисление COUNT(*) занимает у меня 1.7 - 2 сек.

Если ты подсчитываешь кол-во записей в таблице то зачем тебе лефт джоин?


P.S. если ты сюда напишешь сам запрос и его EXPLAIN, то тебе быстро его с оптимизируют :)
 

Фанат

oncle terrible
Команда форума
хе-хе, наш сокол прилетел.
правда, начал путаться в показаниях :)
sokol
30.05.04 16:22
Фанат WHERE может быть совсем пустой. Где и зачем тут индекс?
sokol
10.06.04 03:29
Но если есть хотя бы один LEFT JOIN это правило не работает.
Чувак, ты определись, а? Если у тебя вхере пустой, то ты гонишь. Если не пустой, то сделай индкексы и не парь людям мозги.
Я смотрю, ты чисто разговор поддержать пришел?
ему говорят - сделай индекс, он отвечает, что у него вхере пустой. ему говорят, что он тогда гонит, он отвечает, что вхере есть.
Определись, короче.
Толстой (не Лев, если не изменяет память Николай)
Я считаю - правильно поступал старик.
Я бы тоже так делал.
А ты к чему это? Кто здесь о ком говорит плохо?
Да, и кто такой этот Николай Толстой? Чем знаменит сей достойный муж?
 

sokol

Zavolga.Net
Фанат
WHERE пустой, но объединение из трех таблиц... поля по которым объединятся таблицы проиндексированны.
Не я конечно понимаю, что можно переписать JOIN,ы с использованием только WHERE, но результат немного не тот т.к. нужен LEFT JOIN.

Так что показания мои правильные WHERE пустой, есть только объединение.
Тему можно было закрывать после ответа rudik

>Да, и кто такой этот Николай Толстой? Чем знаменит сей достойный муж?

Он тоже писатель и тоже известный, но жил чуток попозже чем Лев Толстой
 

Фанат

oncle terrible
Команда форума
послушай, ума палата.
внимательно.
про WHERE Первый заговорил ТЫ
тебе сказали - тормозит? используй индексы.
ОТКУДА мне знать, что у тебя там в запросе on или having?
если ты ни буквы из своего хитрого запроса ен привел?
Если ты счел себя гуру, и вывалил нам только результаты, не приведя НИКАКИХ обстоятельств тестов, в первую очередь - самого запроса?
Скажи, ты до сих пор считаешь, что правильно задал вопрос, а виноват только злобный Фанат?

Я тебе скажу, кто виноват.
во-первых, ты не задал вопрос по-человечески.
Во-вторых, понял ответ в силу своих мизерных знаний, считая что индексы используются только во where
но опять же, счел свои заключения истиной в последней инстанции, и ДАЖЕ не переспросил!

Кстати, ты ваообще, понимаешь, о чем я говорю?
все понял? Как-то я сомневаюсь...
Скажи, а ты всерьез до сих пор считаешь, что индексы используются ТОЛЬКО, если есть where?

Тему можно было закрывать после ответа rudik
Ты.
Хочешь сказать.
что без лимита у тебя работает долго, а с лимитом - быстро?
и опять, как всегда - БЕЗ точных цифр и запросов?
Все-таки, я считаю, что ты на форум просто так язык почесать пришел. Начесался, я надеюсь?
В следующий раз, если зачешется - будь добр, приводи реальную информацию, а не свои фантазии.
Он тоже писатель и тоже известный, но жил чуток попозже чем Лев Толстой
и что же написал сей известный писатель?
 

sokol

Zavolga.Net
Фанат да вопрос был задан неправильно.
Ты где нубудь видел, чтобы я написал, что индексы используются только в WHERE? По моему я этого нигде не писал, это уже плод твоих фантазий.

>Скажи, а ты всерьез до сих пор считаешь, что индексы используются ТОЛЬКО, если есть where?

Не считал никогда, я незнаю почему ты так подумал.
ОК счаз приведу реальные запросы и цифры!

-~{}~ 10.06.04 15:59:

PHP:
SELECT SQL_CALC_FOUND_ROWS elogic_news.*,
CONCAT(LEFT(elogic_news.description, 100), '...') AS short_desc,
elogic_users.id AS user_id, elogic_users.login, elogic_users.nick,
elogic_users.name, elogic_status.color,
(
CASE
    WHEN '7' = '2' OR '0' THEN elogic_news.access
    WHEN elogic_news.owner = '7' THEN elogic_news.access
    WHEN BIT_OR(elogic_access_list.access) THEN BIT_OR(elogic_access_list.access)
    WHEN COUNT(elogic_usrtogroup.user_id) > 0 THEN IF (elogic_news.access & 1, (elogic_news.access >> 4) | 1, elogic_news.access >> 4) ELSE IF (elogic_news.access & 1, (elogic_news.access >> 8) | 1 , elogic_news.access >> 8)
END
) AS record_access
FROM elogic_news
LEFT JOIN elogic_users ON elogic_news.owner = elogic_users.id
LEFT JOIN elogic_status ON elogic_news.status = elogic_status.id
LEFT JOIN elogic_access_list ON (elogic_news.id = elogic_access_list.record_id AND elogic_access_list.tbl = 'elogic_news' AND (elogic_access_list.group_id IN ('7') OR elogic_access_list.user_id = '7'))
LEFT JOIN elogic_usrtogroup ON (elogic_news.owner = elogic_usrtogroup.user_id AND elogic_usrtogroup.group_id IN ('7'))
GROUP BY elogic_news.id
HAVING (record_access & (1 << 1)) != 0
ORDER BY elogic_news.tstamp DESC
LIMIT 7000, 20;
время выполнения 0.65 - 0.7 сек
и не зависит от наличия или отсутствия
SQL_CALC_FOUND_ROWS

PHP:
SELECT FOUND_ROWS() AS citem;
время выполнения всегда 0.01 сек

PHP:
SELECT COUNT(*) FROM elogic_news
время выполнения 0.03 сек, случай простейший согласись.

Если
PHP:
SELECT COUNT(*)
FROM elogic_news
LEFT JOIN elogic_status ON elogic_news.status = elogic_status.id
WHERE elogic_status.is_active
время выполнения 0.05 сек.

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

Потому я и решил использовать метод rudik,а

Да признаюсь, в прошлый раз при подсчете COUNT(*) я пихал все выражение FROM в запрос, а все оно там нахрен не нужно. Потому и получил такое огромное время выполнения. Был неправ, исправлюсь.

-~{}~ 10.06.04 16:05:

Да забыл
Apache/1.3.29 (Win32) PHP/4.3.6
MySQL 4.0.17-nt
CPU: AMD Duron 800Mhz / 256 Mb RAM
 
Сверху