Оптимизировать запрос для web_count

Dl

Новичок
Оптимизировать запрос для web_count

Добрый день!

Опишу суть проблемы:
В компании на сайте настроена статистика посещений web_count.
С недавнего времени количество записей в одной таблице (counts_table_session) перевалило за 900000 и один запрос стал сильно нагружать сервер. Время выполнения доходило до 67 секунд.

Запись из slow_qury.log:
# Query_time: 67 Lock_time: 0 Rows_sent: 1 Rows_examined: 911125
SELECT count(distinct(statid)) FROM counts_table_session;

Структура таблицы:
CREATE TABLE `counts_table_session` (
`id` int(10) NOT NULL auto_increment,
`statid` int(10) NOT NULL default '0',
`time` int(11) NOT NULL default '0',
`page` varchar(50) default NULL,
PRIMARY KEY (`id`),
KEY `statid` (`statid`),
KEY `time` (`time`),
KEY `page` (`page`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

Если выполнить этот запрос выполнить в командной строке MySQL на сервере:
mysql> select count(distinct(statid)) from counts_table_session;
+----------------------------+
| count(distinct(statid)) |
+----------------------------+
| 37704 |
+----------------------------+
1 row in set (1.31 sec)

Я попытался его немного оптимизировать, получилось:
mysql> select count(*) from (select distinct `statid` from `counts_table_session`) as `sessions`;
+-----------+
| count(*) |
+-----------+
| 37704 |
+-----------+
1 row in set (0.58 sec)

Изменил его и в скрипте, но в slow_qury.log он все равно пишется:
# Query_time: 11 Lock_time: 0 Rows_sent: 1 Rows_examined: 0
SELECT COUNT(*) FROM (SELECT DISTINCT `statid` FROM `counts_table_session`) AS `sessions`;

В my.ini
set-variable=long_query_time=1

PHP Version 5.1.6, Apache 2.0 Handler, MySQL 5.0.22.

Вопрос: можно ли запрос ещё оптимизировать или искать косяк в коде?
 

Dl

Новичок
Попробовал

select count(*) from (select `statid` from `counts_table_session` group by `statid`) as `sessions`;

select count(`statid`) from (select `statid` from `counts_table_session` group by `statid`) as `sessions`;

время такое же.
 

Mr_Max

Первый класс. Зимние каникулы ^_^
Команда форума
Dl
1. Попробуйте обойтись без волженного запроса. Сделав 2 запроса.
не поможет - выносите "подсчитанные" данные в отдельную таблицу.
 

Dl

Новичок
Mr_Max
Скорее всего, так и придется сделать.
Либо уговорить начальство поставить другой счетчик :)
 

zerkms

TDD infected
Команда форума
Код:
mysql> SELECT COUNT(DISTINCT `path_id`) FROM `cms_stat_hits`;
+---------------------------+
| COUNT(DISTINCT `path_id`) |
+---------------------------+
|                     50574 |
+---------------------------+
1 row in set (0.16 sec)
100k записей, поле индексированное, тачка не серверная
 

Dl

Новичок
Код:
mysql> select count(distinct(`statid`)) from `counts_table_session`;
+---------------------------+
| count(distinct(`statid`)) |
+---------------------------+
|                      2511 |
+---------------------------+
1 row in set (0.14 sec)
На локальной машине, 100К записей, поле индексированное.

Проблема именно на серваке, и именно в скрипте...

Строчки из кода:
PHP:
$result=$this->exec("SELECT COUNT(*) FROM (SELECT DISTINCT `statid` FROM `counts_table_session`) AS `sessions`;" );
list($sess_all)=$result->fetch_row();

//Объявление exec
function exec($query) {

	 if (!$result=@mysql_query($query, $this->connection)) {
//		 $this->write_log("Ошибка запроса к базе!", __line__, __file__, "");
		 return false;
	 }
	 $return=new ___result___($result);
	 return $return;
}
 

Gas

может по одной?
Dl
Идёт полный скан по индексу, скорее всего далеко не все индексные блоки в памяти - идёт чтение с диска. При 900K записей и нагруженном сервере 11 сек вполне могут быть. Так-что дело скорее всего не в скрипте.
p.s. не ожидал что вариант с подзапросом действительно почти в 2 раза быстрее, тестил на таблице с 1.3M записей.
 

Dl

Новичок
Gas, еще имеет место дефрагментация таблицы, но не более 10Кб (при размере таблицы 58Мб). Попробую её оптимизировать.

Но все равно, в первом посте я написал как раз про отличие времени выполнения запроса из командной строки и при вызове скрипта через браузер...
Эта разница может зависеть от других сервисов, выполняющихся на сервере (синхронизация таблиц с другими серверами, бекапы, другие сервисы, юзающие MySQL)?
 

Gas

может по одной?
Уверен что разница в скорости между консольным и php клиентами несущественна. Скорость одного итого же запроса может зависеть от кучи факторов - запустился дамп, залочил таблицу и запрос висит.
 

Dl

Новичок
Пока от админов добился невнятного "MySQL плохо работает с таблицами ~1000К записей"...
 

Gas

может по одной?
:) ну хорошо не сказали что Mysql не работает с более чем 1M записей.

А чего у от админов то хотел? Имхо, запрос оптимизировать уже некуда. Если не устраивает скорость - меняй логику получения этого значения.
 

Dl

Новичок
В понедельник попробую разделить запросы по совету Mr_Max
 

Dl

Новичок
Вобщем, вышестоящие решили пока вобще отключить этот счетчик, так что тему можно закрыть.
Спасибо всем за помощь!
 
Сверху