Задавайте вопросы, мы ответим
Вы не зашли.
День добрый!
Помогите решить задачу:
Есть таблица статусов сообщений, ежесуточно прядка 2 млн. записей. Формат таблицы следующий:
DROP TABLE IF EXISTS `msg`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `msg` (
`smid` varchar(24) NOT NULL,
`id` int(10) DEFAULT NULL,
`ip_from` varchar(16) NOT NULL DEFAULT '',
`mail_from` varchar(500) DEFAULT '',
`mail_to` varchar(500) DEFAULT '',
`domain` varchar(200) NOT NULL,
`from_domain` varchar(200) DEFAULT NULL,
`ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`chtime` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`server_id` int(4) unsigned NOT NULL,
`status` int(2) unsigned NOT NULL,
`status_info` int(4) unsigned NOT NULL,
`head` text,
`split_smid` varchar(30) DEFAULT NULL,
`msize` int(10) DEFAULT '0',
`filter_id` int(4) DEFAULT '0',
PRIMARY KEY (`smid`),
KEY `ip_from` (`ip_from`),
KEY `k_id` (`id`),
KEY `k_tod` (`mail_to`(15)),
KEY `k_from` (`mail_from`(15)),
KEY `k_domato` (`domain`(15)),
KEY `ks_from` (`smid`(12),`mail_from`(15)),
KEY `kst_from` (`status`,`mail_from`(15)),
KEY `ksts_from` (`status`,`smid`(12),`mail_from`(15)),
KEY `k_fromd` (`from_domain`(15)),
KEY `ks_fromd` (`smid`(12),`from_domain`(15)),
KEY `kst_fromd` (`status`,`from_domain`(15)),
KEY `ksts_fromd` (`status`,`smid`(12),`from_domain`(15)),
KEY `ks_tod` (`smid`(12),`mail_to`(15)),
KEY `kst_tod` (`status`,`mail_to`(15)),
KEY `ksts_tod` (`status`,`smid`(12),`mail_to`(15)),
KEY `k_from_to` (`mail_to`(15),`mail_from`(15)),
KEY `ks_from_to` (`smid`(12),`mail_from`(15),`mail_to`(15)),
KEY `kst_from_to` (`status`,`mail_from`(15),`mail_to`(15)),
KEY `ksts_from_to` (`status`,`smid`(12),`mail_from`(15),`mail_to`(15)),
KEY `k_fromd_to` (`mail_to`(15),`from_domain`(15)),
KEY `ks_fromd_to` (`smid`(12),`from_domain`(15),`mail_to`(15)),
KEY `kst_fromd_to` (`status`,`from_domain`(15),`mail_to`(15)),
KEY `ksts_fromd_to` (`status`,`smid`(12),`from_domain`(15),`mail_to`(15)),
KEY `k_from_tod` (`domain`(15),`mail_from`(15)),
KEY `ks_from_tod` (`smid`(12),`mail_from`(15),`domain`(15)),
KEY `kst_from_tod` (`status`,`mail_from`(15),`domain`(15)),
KEY `ksts_from_tod` (`status`,`smid`(12),`mail_from`(15),`domain`(15)),
KEY `k_fromd_tod` (`domain`(15),`from_domain`(15)),
KEY `ks_fromd_tod` (`smid`(12),`from_domain`(15),`domain`(15)),
KEY `kst_fromd_tod` (`status`,`from_domain`(15),`domain`(15)),
KEY `ksts_fromd_tod` (`status`,`smid`(12),`from_domain`(15),`domain`(15)),
KEY `kictime` (`id`,`ctime`),
KEY `kismid` (`id`,`smid`),
KEY `kistatus` (`id`,`smid`(12),`status`),
KEY `ki_from` (`id`,`mail_from`(15)),
KEY `kis_from` (`id`,`smid`(12),`mail_from`(15)),
KEY `kist_from` (`id`,`status`,`mail_from`(15)),
KEY `kists_from` (`id`,`status`,`smid`(12),`mail_from`(15)),
KEY `ki_fromd` (`id`,`from_domain`(15)),
KEY `kis_fromd` (`id`,`smid`(12),`from_domain`(15)),
KEY `kist_fromd` (`id`,`status`,`from_domain`(15)),
KEY `kists_fromd` (`id`,`status`,`smid`(12),`from_domain`(15)),
KEY `ki_to` (`id`,`mail_to`(15),`domain`(15)),
KEY `kis_to` (`id`,`smid`(12),`mail_to`(15),`domain`(15)),
KEY `kist_to` (`id`,`status`,`mail_to`(15),`domain`(15)),
KEY `kists_to` (`id`,`status`,`smid`(12),`mail_to`(15),`domain`(15))
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
При этом smid - уникальный ключ, содержащий в себе дату.
Помогите найти быстрый способ пролистывания данной таблицы,
Допустима сортировка по полям smid, mail_from, mail_to, domain, from_domain и status
и отбор по ним-же:
У меня получается вот какая беда:
При ограничение запроса по status=7 ( около млн записей )
select count(*) выполняется около 5-15 секунд, даже без сортировки, что крайне неудобно для
просмотра таблицы через сайт (php скрипт для пролистывания)
я сделал это следующим способом:
Ограничил количество просматриваемых записей до 2тыс, но select count(*) - все портит, я не знаю очень быстрого способа получить количество записей по запросу.
А хотелось бы иметь возможность постраничного просмотра всех записей базы.
Существующие:
explain select count(*) from msg where status=7;
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------+---------+-------+--------+-------------+
| 1 | SIMPLE | msg | ref | kst_from,ksts_from,kst_fromd,ksts_fromd,kst_tod,ksts_tod,kst_from_to,ksts_from_to,kst_fromd_to,ksts_fromd_to,kst_from_tod,ksts_from_tod,kst_fromd_tod,ksts_fromd_tod | ksts_from_tod | 4 | const | 526536 | Using index |
+----+-------------+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------+---------+-------+--------+-------------+
select count(*) from msg where status=7;
+----------+
| count(*) |
+----------+
| 2502558 |
+----------+
1 row in set (31.35 sec)
select count(*) from msg;
+----------+
| count(*) |
+----------+
| 2583981 |
+----------+
1 row in set (28.95 sec)
select count(*) from msg where status=5;
+----------+
| count(*) |
+----------+
| 65522 |
+----------+
1 row in set (2.88 sec)
Как ускорить хотя-бы count по большому количеству записей?
Отредактированно Delems (20.04.2011 10:45:36)
Неактивен
Денормализацию не пробовали? Вам же честно надо оббежать дерево в 2кк
листьев, это тяжелая работа.
Неактивен
Согласен работа действительно тяжелая, но я не совсем понимаю как в этом случает можно применить денормализацию, фрмировать отдельную таблицу со счетчиками по каждому возможному запросу? Вариант. Спасибо, подумаю.
Хотя может быть еще есть варианты?
Неактивен
Не по каждому возможному, а по статусу. Если не нужны точные значения —
можно руководствоваться приблизительными оценками (которые можно полу-
чить, например, из EXPLAIN запросов).
Неактивен