SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 20.04.2011 10:31:40

Delems
Участник
Зарегистрирован: 20.04.2011
Сообщений: 2

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

День добрый!


Помогите решить задачу:

Есть таблица статусов сообщений, ежесуточно прядка 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 20.04.2011 21:53:23

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Пролистывание таблицы с большим количеством записей.

Денормализацию не пробовали? Вам же честно надо оббежать дерево в 2кк
листьев, это тяжелая работа.

Неактивен

 

#3 21.04.2011 00:02:22

Delems
Участник
Зарегистрирован: 20.04.2011
Сообщений: 2

Re: Пролистывание таблицы с большим количеством записей.

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

Неактивен

 

#4 21.04.2011 16:26:16

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Пролистывание таблицы с большим количеством записей.

Не по каждому возможному, а по статусу. Если не нужны точные значения —
можно руководствоваться приблизительными оценками (которые можно полу-
чить, например, из EXPLAIN запросов).

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson