помогите оптимизировать ЗАПРОС

elven

Новичок
помогите оптимизировать ЗАПРОС

есть таблица

PHP:
CREATE TABLE `stat` (
  `id` int(11) NOT NULL auto_increment,
  `t_id` int(11) NOT NULL default '0',
  `edate` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`id`),
  KEY `t_id` (`t_id`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;
содержащая 6899027 записей

можно ли как нибудь оптимизировать слеюущий запрос?
PHP:
 SELECT t_id, count(t_id) AS count
FROM stat 
GROUP BY t_id                          
ORDER BY count DESC 
LIMIT 5
он у меня выполняет за 9 секунд

P.S. MySQL 4.1.11
 

elven

Новичок
1 SIMPLE stat index NULL t_id 4 NULL 6899542 Using index; Using temporary; Using filesort

-~{}~ 19.11.07 01:32:

Id - 1
select_type - SIMPLE
table – stat
type – index
possible_keys - NULL
key - t_id
key_len – 4
ref – NULL
rows – 6899542
EXTRA - Using index; Using temporary; Using filesort
 

Mr_Max

Первый класс. Зимние каникулы ^_^
Команда форума
можно ли как нибудь оптимизировать слеюущий запрос?
Такой запрос я бы вынимал из таблицы (2) с уже просумированными данными.

При запросах к таблице 1 (когда счётчик увеличивается) сумировал - бы и данные в таблице (2)

+ синхронизировал, например, по крону данные в таблице 1 с данными в таблице 2.
 

phprus

Moderator
Команда форума
Не заметил, что сортировка идет по вычисляемому полю и кроме того в запросе нет блока where. В данном случае запрос вроде-бы ускорить нельзя.

А почему бы тебе не сделать отдельную таблицу в которой хранить t_id и соответствующее ему количество записей из твоей таблицы stat? В новую таблицу обновления можно вносить автоматически при помощи использования триггера в таблице stat.
 

Mr_Max

Первый класс. Зимние каникулы ^_^
Команда форума
Using index; Using temporary; Using filesort
Можно попробовать без сортировки по count (если данных не много). И потом отсортировать средствами ПХП.
Без сортировки, если не ошибаюсь, будет
не
Using index; Using temporary; Using filesort
A
Using index;
Опять-же если данных не много.
 

elven

Новичок
данная таблица, была сделана для статистики - по сути это лог просмотров определенных данных из другой таблицы - t_iв

мне также необходимо потом считать количество записей t_id за разные периоды по датам (другим запросом)

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


дело в том что таблица stat постоянно обновляется
и мне нужен текущий результат (не буду же я запускать крон ежесекундно чтобы синхронизировать данные)
 

elven

Новичок
вообще то первоначально запрос был сложнее
просто я чтобы упростить решил разбить

$sql="SELECT s.t_id, t.header, count( s.t_id ) AS count, t.code
FROM stat s
LEFT JOIN topics t ON (s.t_id = t.id )
WHERE s.edate > FROM_UNIXTIME($date)
GROUP BY s.t_id
ORDER BY count DESC

-~{}~ 19.11.07 01:48:

дата у меня идет с точностью до секунды

-~{}~ 19.11.07 01:49:

если поле `edate` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP

то разве можно ее проиндексировать?
 

Mr_Max

Первый класс. Зимние каникулы ^_^
Команда форума
и мне нужен текущий результат (не буду же я запускать крон ежесекундно чтобы синхронизировать данные)
Зачем? Чем не устраивает результат 5-минутной давности?
 

phprus

Moderator
Команда форума
elven
вообще то первоначально запрос был сложнее
просто я чтобы упростить решил разбить
А на самом деле ты только усложнил задачу.

Добавь индекс на поле stat.edate и сделай explain реального запроса.

-~{}~ 18.11.07 21:51:

elven
то разве можно ее проиндексировать?
А кто запретил?
 

elven

Новичок
это новостной портал - если ты видишь на главной странице рейтинг самых читаемых новостей, потом заходишь, а там количество просмотров отличается, то это мне кажется несерьезно

-~{}~ 19.11.07 01:58:

запРОС

SELECT s.t_id, t.header, count( s.t_id ) AS count, t.code
FROM stat s
LEFT JOIN topics t ON ( s.t_id = t.id )
WHERE s.edate > FROM_UNIXTIME( 1195398000 )
GROUP BY s.t_id
ORDER BY count DESC
LIMIT 5

ГДЕ 1195398000 - ЭТО 0 ЧАСОВ 0 МИНУТ ДАННОГО ДНЯ

то ЭКСПЛЕЙН ПИШЕТ

1 SIMPLE s ALL NULL NULL NULL NULL 6900155 Using where; Using temporary; Using filesort
1 SIMPLE t eq_ref PRIMARY PRIMARY 4 1sn.s.t_id 1

-~{}~ 19.11.07 01:59:

выполняет за 10.2668 сек

-~{}~ 19.11.07 02:01:

может сделать так:
записывать дату не через CURRENT_TIMESTAMP а просто писать дату без часов, минут и секунд и сделать edate index?

как думаете это поможет?
 

Mr_Max

Первый класс. Зимние каникулы ^_^
Команда форума
elven
мне кажется несерьезно
Более несерьезно будет, если сервак "загнётся" от запросов нахлынувшых посетителей.
Тем более такой информации, что не несет смысловой нагрузки - каике-то счетчики.
Человек на Ваш новострой сайт приход в первую очередь за новостями. Не правда ли?.

Советую перечитать топик с самого начала
Данные нужно обновлять в 2-х таблицах.
1 - в Вашей для статистики
2 - в таблице с уже пощитанным count из 1-й таблицы. При нормально построенном движне данный будут совпадать.
Но я бы "сихронизировал" эти таблицы периодически.

то разве можно ее проиндексировать?
Что мешает попробовать?
Что мешает сделать explain до и после?
 

Mr_Max

Первый класс. Зимние каникулы ^_^
Команда форума
просто писать дату без часов
Да, если этого достаточно.

Откажитесь от
WHERE s.edate > FROM_UNIXTIME( 1195398000 )
подавайте на вход дату в нужном формате.

-~{}~ 18.11.07 19:08:

Почему?

mysql> select benchmark(1000000, FROM_UNIXTIME( 1195398000 ));
+-------------------------------------------------+
| benchmark(1000000, FROM_UNIXTIME( 1195398000 )) |
+-------------------------------------------------+
| 0 |
+-------------------------------------------------+
1 row in set (1.64 sec)
 

elven

Новичок
или сделать отдельный скрипт с этим запросом, результат записывать в отдельную таблицу (из 5 записей), обновление этой таблицы делать через определенные промежутки времени (крон или еще что нибудь)

-~{}~ 19.11.07 02:13:

спасибо за помощь
попробую:
1) изменить формат времени
2) проиндексировать поле с датой
3) создать отдельную таблицу для результатов

-~{}~ 19.11.07 02:20:

вопрос напоследок:

что я должен указать в WHERE чтобы обрабатывались данные только за сегодяншний день?

-~{}~ 19.11.07 02:24:

поменял формат, проиндексировал

запрос

SELECT s.t_id, t.header, count( s.t_id ) AS count, t.code
FROM stat2 s
LEFT JOIN topics t ON ( s.t_id = t.id )
WHERE s.edate = '2007-11-19'
GROUP BY s.t_id
ORDER BY count DESC
LIMIT 5

занял 0.1103 сек

:)) спасибо огромное вам за помощь
 

algo

To the stars!
Сделай триггер, который будет обновлять таблицу статистики.
 

phprus

Moderator
Команда форума
Gas
algo, не первый кто не посмотрел на версию MySQL. Я тоже посоветовал триггером воспользоваться, но несколько раньше. :)
 

algo

To the stars!
Да, иногда самое важное пишут последним в Пы Эс.

Запрос из топика оптимизировать нельзя. Индекс по id уже есть, больше ниче не пригодится тут.
 
Сверху