На выходных был не у компьютера, прошу прощения за паузу.
Вот точные данные по таблицам и выборкам. Построил заново индекс roomID+id, поскольку после предыдущих тестов удалил его было, за ненадобностью (плюс где-то прочитал, что на индексы таблиц InnoDB MySQL автоматически добавляет последним столбцом первичный ключ).
deadka написал:
Покажите show create table messroom; пожалуйста.
mysql> show create table `messroom`\G
*************************** 1. row ***************************
Table: messroom
Create Table: CREATE TABLE `messroom` (
`id` int(11) NOT NULL auto_increment COMMENT 'Порядковый индекс',
`time` timestamp NOT NULL default CURRENT_TIMESTAMP COMMENT 'Время записи',
`roomID` int(11) default NULL COMMENT 'ID комнаты, в которую отправлено сообщение',
`fromNum` int(11) default NULL COMMENT 'ID пользователя, отправившего сообщение',
`tarNum` int(11) default '-1' COMMENT 'ID пользователя, которому отправлено сообщение',
`messNum` int(11) default NULL COMMENT 'Номер сообщения для подтверждения доставки',
`fPrv` tinyint(1) unsigned zerofill default '0' COMMENT 'Флаг приватности',
`text` varchar(1024) collate utf8_unicode_ci default NULL COMMENT 'Текст сообщения',
PRIMARY KEY (`id`),
KEY `roomID` (`roomID`),
KEY `roomID_id` (`roomID`,`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16136954 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AVG_ROW_LENGTH=86
Всё последующее - уже после построения индекса:
deadka написал:
Покажите explain с ним
mysql> explain select * from `messroom` where `roomID` IN (3,7) order by `ID` desc limit 5;
+----+-------------+----------+-------+------------------+--------+---------+------+--------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+------------------+--------+---------+------+--------+-----------------------------+
| 1 | SIMPLE | messroom | range | roomID,roomID_id | roomID | 5 | NULL | 485464 | Using where; Using filesort |
+----+-------------+----------+-------+------------------+--------+---------+------+--------+-----------------------------+
1 row in set (0.00 sec)
mysql> explain select * from `messroom` force index(`roomID_id`) where `roomID` IN (3,7) order by `ID` desc limit 5;
+----+-------------+----------+-------+---------------+-----------+---------+------+--------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+---------------+-----------+---------+------+--------+-----------------------------+
| 1 | SIMPLE | messroom | range | roomID_id | roomID_id | 5 | NULL | 485464 | Using where; Using filesort |
+----+-------------+----------+-------+---------------+-----------+---------+------+--------+-----------------------------+
1 row in set (0.00 sec)
deadka написал:
как насчет скорости выполнения - возрастает?
mysql> select * from `messroom` where `roomID` IN (3,7) order by `ID` desc limit 5;
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| id | time | roomID | fromNum | tarNum | messNum | fPrv | text |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| 15707189 | 2012-01-19 14:06:48 | 3 | 55386 | 31400 | 5 | 0 | #24 |
| 15707188 | 2012-01-19 14:06:45 | 3 | 16056 | -1 | 27 | 0 | смешной дядька однако |
| 15707178 | 2012-01-19 14:06:06 | 3 | 31400 | 55386 | 19 | 0 | Просто он такой же тактикой и ко мне подкатывал:-D |
| 15707145 | 2012-01-19 14:04:23 | 3 | 55386 | 31400 | 2 | 0 | очередная игра. |
| 15707129 | 2012-01-19 14:03:34 | 3 | 31400 | 55386 | 17 | 0 | Да тебе то понятно,а вот за ним смешно наблюдать:) |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
5 rows in set (32.05 sec)
mysql> select * from `messroom` force index(`roomID_id`) where `roomID` IN (3,7) order by `ID` desc limit 5;
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| id | time | roomID | fromNum | tarNum | messNum | fPrv | text |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| 15707189 | 2012-01-19 14:06:48 | 3 | 55386 | 31400 | 5 | 0 | #24 |
| 15707188 | 2012-01-19 14:06:45 | 3 | 16056 | -1 | 27 | 0 | смешной дядька однако |
| 15707178 | 2012-01-19 14:06:06 | 3 | 31400 | 55386 | 19 | 0 | Просто он такой же тактикой и ко мне подкатывал:-D |
| 15707145 | 2012-01-19 14:04:23 | 3 | 55386 | 31400 | 2 | 0 | очередная игра. |
| 15707129 | 2012-01-19 14:03:34 | 3 | 31400 | 55386 | 17 | 0 | Да тебе то понятно,а вот за ним смешно наблюдать:) |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
5 rows in set (11.67 sec)
Но видимо, часть данных просто закешировалась, поскольку все последующие запросы дают идентичное время в диапазоне 11,6..11,9 сек:
mysql> select * from `messroom` where `roomID` IN (3,7) order by `ID` desc limit 5;
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| id | time | roomID | fromNum | tarNum | messNum | fPrv | text |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| 15707189 | 2012-01-19 14:06:48 | 3 | 55386 | 31400 | 5 | 0 | #24 |
| 15707188 | 2012-01-19 14:06:45 | 3 | 16056 | -1 | 27 | 0 | смешной дядька однако |
| 15707178 | 2012-01-19 14:06:06 | 3 | 31400 | 55386 | 19 | 0 | Просто он такой же тактикой и ко мне подкатывал:-D |
| 15707145 | 2012-01-19 14:04:23 | 3 | 55386 | 31400 | 2 | 0 | очередная игра. |
| 15707129 | 2012-01-19 14:03:34 | 3 | 31400 | 55386 | 17 | 0 | Да тебе то понятно,а вот за ним смешно наблюдать:) |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
5 rows in set (11.85 sec)
deadka написал:
Хотя mysql иногда ошибается в анализе - попробуйте выполнить по отдельности два запроса
select * from `messroom` where `roomID`=3 order by `ID` desc limit 5;
select * from `messroom` where `roomID`=7 order by `ID` desc limit 5;
mysql> select * from `messroom` where `roomID`=3 order by `ID` desc limit 5;
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| id | time | roomID | fromNum | tarNum | messNum | fPrv | text |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| 15707189 | 2012-01-19 14:06:48 | 3 | 55386 | 31400 | 5 | 0 | #24 |
| 15707188 | 2012-01-19 14:06:45 | 3 | 16056 | -1 | 27 | 0 | смешной дядька однако |
| 15707178 | 2012-01-19 14:06:06 | 3 | 31400 | 55386 | 19 | 0 | Просто он такой же тактикой и ко мне подкатывал:-D |
| 15707145 | 2012-01-19 14:04:23 | 3 | 55386 | 31400 | 2 | 0 | очередная игра. |
| 15707129 | 2012-01-19 14:03:34 | 3 | 31400 | 55386 | 17 | 0 | Да тебе то понятно,а вот за ним смешно наблюдать:) |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
5 rows in set (0.00 sec)
mysql> select * from `messroom` where `roomID`=7 order by `ID` desc limit 5;
+----------+---------------------+--------+---------+--------+---------+------+------------------------------------------------+
| id | time | roomID | fromNum | tarNum | messNum | fPrv | text |
+----------+---------------------+--------+---------+--------+---------+------+------------------------------------------------+
| 15700246 | 2012-01-18 22:47:08 | 7 | 55993 | 2997 | 10 | 0 | Привет дамы и господа) |
| 15693426 | 2012-01-18 13:16:09 | 7 | 2997 | 21349 | 14 | 0 | Спасибо Полечка)) |
| 15693380 | 2012-01-18 13:10:34 | 7 | 21349 | 2997 | 10 | 0 | С днем рождения!) |
| 15692993 | 2012-01-18 12:42:55 | 7 | 2997 | 35376 | 12 | 0 | Спасибо#2 |
| 15692699 | 2012-01-18 12:15:02 | 7 | 35376 | -1 | 11 | 0 | И не торчи сегодня здесь#2 |
+----------+---------------------+--------+---------+--------+---------+------+------------------------------------------------+
5 rows in set (0.00 sec)
deadka написал:
И покажите explain'ы на них тоже.
mysql> explain select * from `messroom` where `roomID`=3 order by `ID` desc limit 5;
+----+-------------+----------+------+------------------+--------+---------+-------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+------------------+--------+---------+-------+-------+-------------+
| 1 | SIMPLE | messroom | ref | roomID,roomID_id | roomID | 5 | const | 84812 | Using where |
+----+-------------+----------+------+------------------+--------+---------+-------+-------+-------------+
1 row in set (0.00 sec)
mysql> explain select * from `messroom` where `roomID`=7 order by `ID` desc limit 5;
+----+-------------+----------+------+------------------+-----------+---------+-------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+------------------+-----------+---------+-------+--------+-------------+
| 1 | SIMPLE | messroom | ref | roomID,roomID_id | roomID_id | 5 | const | 400652 | Using where |
+----+-------------+----------+------+------------------+-----------+---------+-------+--------+-------------+
1 row in set (0.00 sec)
Почему-то MySQL выбирает разные индексы для этих выборок, хотя предполагаю, из составного всё равно возьмет только первый столбец.
deadka написал:
Есть вероятность, что запрос будет иметь смысл переписать в виде
select * from `messroom` where `roomID`=3 order by `ID` desc limit 5
UNION
select * from `messroom` where `roomID`=7 order by `ID` desc limit 5;
Без скобок работать отказался. Со скобками получаю не то, что хотелось бы:
mysql> (select * from `messroom` where `roomID`=3 order by `ID` desc limit 5)
-> UNION
-> (select * from `messroom` where `roomID`=7 order by `ID` desc limit 5);
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| id | time | roomID | fromNum | tarNum | messNum | fPrv | text |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| 15707189 | 2012-01-19 14:06:48 | 3 | 55386 | 31400 | 5 | 0 | #24 |
| 15707188 | 2012-01-19 14:06:45 | 3 | 16056 | -1 | 27 | 0 | смешной дядька однако |
| 15707178 | 2012-01-19 14:06:06 | 3 | 31400 | 55386 | 19 | 0 | Просто он такой же тактикой и ко мне подкатывал:-D |
| 15707145 | 2012-01-19 14:04:23 | 3 | 55386 | 31400 | 2 | 0 | очередная игра. |
| 15707129 | 2012-01-19 14:03:34 | 3 | 31400 | 55386 | 17 | 0 | Да тебе то понятно,а вот за ним смешно наблюдать:) |
| 15700246 | 2012-01-18 22:47:08 | 7 | 55993 | 2997 | 10 | 0 | Привет дамы и господа) |
| 15693426 | 2012-01-18 13:16:09 | 7 | 2997 | 21349 | 14 | 0 | Спасибо Полечка)) |
| 15693380 | 2012-01-18 13:10:34 | 7 | 21349 | 2997 | 10 | 0 | С днем рождения!) |
| 15692993 | 2012-01-18 12:42:55 | 7 | 2997 | 35376 | 12 | 0 | Спасибо#2 |
| 15692699 | 2012-01-18 12:15:02 | 7 | 35376 | -1 | 11 | 0 | И не торчи сегодня здесь#2 |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
10 rows in set (0.08 sec)
Вынес сортировку за скобки, теперь то, что надо, но снова медленно:
mysql> (select * from `messroom` where `roomID`=3)
-> UNION
-> (select * from `messroom` where `roomID`=7)
-> order by `ID` desc limit 5;
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| id | time | roomID | fromNum | tarNum | messNum | fPrv | text |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| 15707189 | 2012-01-19 14:06:48 | 3 | 55386 | 31400 | 5 | 0 | #24 |
| 15707188 | 2012-01-19 14:06:45 | 3 | 16056 | -1 | 27 | 0 | смешной дядька однако |
| 15707178 | 2012-01-19 14:06:06 | 3 | 31400 | 55386 | 19 | 0 | Просто он такой же тактикой и ко мне подкатывал:-D |
| 15707145 | 2012-01-19 14:04:23 | 3 | 55386 | 31400 | 2 | 0 | очередная игра. |
| 15707129 | 2012-01-19 14:03:34 | 3 | 31400 | 55386 | 17 | 0 | Да тебе то понятно,а вот за ним смешно наблюдать:) |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
5 rows in set (26.16 sec)
Вношу в скобки лимит, чтобы не сортировать всю выборку:
mysql> (select * from `messroom` where `roomID`=3 limit 5)
-> UNION
-> (select * from `messroom` where `roomID`=7 limit 5)
-> order by `ID` desc;
+--------+---------------------+--------+---------+--------+---------+------+--------------------------------------------------------+
| id | time | roomID | fromNum | tarNum | messNum | fPrv | text |
+--------+---------------------+--------+---------+--------+---------+------+--------------------------------------------------------+
| 837377 | 2009-06-27 23:49:06 | 7 | 1 | -1 | 14 | 0 | 6 |
| 837376 | 2009-06-27 23:49:04 | 7 | 1 | -1 | 13 | 0 | 7 |
| 837375 | 2009-06-27 23:49:02 | 7 | 1 | -1 | 12 | 0 | 8 |
| 837372 | 2009-06-27 23:49:00 | 7 | 1 | -1 | 11 | 0 | 9 |
| 837371 | 2009-06-27 23:48:57 | 7 | 1 | -1 | 10 | 0 | сообщение для гаражика 10 |
| 48325 | 2009-03-12 21:05:25 | 3 | 302 | 1 | 4 | 0 | я заместитель) |
| 48322 | 2009-03-12 21:04:56 | 3 | 1 | 302 | 3 | 0 | о! так вы вдвоем тут живете? :) |
| 48320 | 2009-03-12 21:04:37 | 3 | 302 | 1 | 2 | 0 | ))) я за него |
| 48319 | 2009-03-12 21:04:15 | 3 | 1 | -1 | 1 | 0 | вот только Стрелка дома нет :)) |
| 48317 | 2009-03-12 21:03:54 | 3 | 1 | 302 | 0 | 0 | быстрая ты! )) |
+--------+---------------------+--------+---------+--------+---------+------+--------------------------------------------------------+
10 rows in set (0.00 sec)
Для меня неожиданный результат. :( Вношу обратно в скобки и сортировку, и лимит, и добавляю внешнюю сортировку:
mysql> (select * from `messroom` where `roomID`=3 order by `ID` desc limit 5)
-> UNION
-> (select * from `messroom` where `roomID`=7 order by `ID` desc limit 5)
-> order by `ID` desc;
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| id | time | roomID | fromNum | tarNum | messNum | fPrv | text |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
| 15707189 | 2012-01-19 14:06:48 | 3 | 55386 | 31400 | 5 | 0 | #24 |
| 15707188 | 2012-01-19 14:06:45 | 3 | 16056 | -1 | 27 | 0 | смешной дядька однако |
| 15707178 | 2012-01-19 14:06:06 | 3 | 31400 | 55386 | 19 | 0 | Просто он такой же тактикой и ко мне подкатывал:-D |
| 15707145 | 2012-01-19 14:04:23 | 3 | 55386 | 31400 | 2 | 0 | очередная игра. |
| 15707129 | 2012-01-19 14:03:34 | 3 | 31400 | 55386 | 17 | 0 | Да тебе то понятно,а вот за ним смешно наблюдать:) |
| 15700246 | 2012-01-18 22:47:08 | 7 | 55993 | 2997 | 10 | 0 | Привет дамы и господа) |
| 15693426 | 2012-01-18 13:16:09 | 7 | 2997 | 21349 | 14 | 0 | Спасибо Полечка)) |
| 15693380 | 2012-01-18 13:10:34 | 7 | 21349 | 2997 | 10 | 0 | С днем рождения!) |
| 15692993 | 2012-01-18 12:42:55 | 7 | 2997 | 35376 | 12 | 0 | Спасибо#2 |
| 15692699 | 2012-01-18 12:15:02 | 7 | 35376 | -1 | 11 | 0 | И не торчи сегодня здесь#2 |
+----------+---------------------+--------+---------+--------+---------+------+-------------------------------------------------------------------------------------------+
10 rows in set (0.00 sec)
Вот теперь то, что надо! Пробую выборки на других комнатах, добавив общий лимит:
mysql> (select * from `messroom` where `roomID`=1 order by `ID` desc limit 5)
-> UNION
-> (select * from `messroom` where `roomID`=3 order by `ID` desc limit 5)
-> UNION
-> (select * from `messroom` where `roomID`=6 order by `ID` desc limit 5)
-> UNION
-> (select * from `messroom` where `roomID`=7 order by `ID` desc limit 5)
-> order by `ID` desc limit 5;
+----------+---------------------+--------+---------+--------+---------+------+---------------------------------------------------+
| id | time | roomID | fromNum | tarNum | messNum | fPrv | text |
+----------+---------------------+--------+---------+--------+---------+------+---------------------------------------------------+
| 16136953 | 2012-02-23 01:54:36 | 6 | 28006 | 1 | 1 | 0 | Ясно:) я тоже раньше джим, а потом баян. |
| 16136952 | 2012-02-23 01:53:23 | 1 | 50670 | 1 | 32 | 0 | О :)кстати добавлю тя В.К:)ЕСЛИ ТЫ НЕ ПРОТив |
| 16136951 | 2012-02-23 01:52:50 | 1 | 50670 | 58214 | 31 | 0 | С Украины я:) |
| 16136950 | 2012-02-23 01:52:39 | 1 | 50670 | 1 | 30 | 0 | Чао Валентин:)#51:) |
| 16136949 | 2012-02-23 01:52:30 | 1 | 58214 | -1 | 2 | 0 | #60 |
+----------+---------------------+--------+---------+--------+---------+------+---------------------------------------------------+
5 rows in set (0.00 sec)
Всё супер. Explain этого запроса:
mysql> explain (select * from `messroom` where `roomID`=1 order by `ID` desc limit 5) UNION (select * from `messroom` where `roomID`=3 order by `ID` desc limit 5) UNION (select * from `messroom` where `roomID`=6 order by `ID` desc limit 5) UNION (select * from `messroom` where `roomID`=7 order by `ID` desc limit 5) order by `ID` desc limit 5;
+----+--------------+----------------+------+------------------+-----------+---------+-------+---------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+----------------+------+------------------+-----------+---------+-------+---------+----------------+
| 1 | PRIMARY | messroom | ref | roomID,roomID_id | roomID | 5 | const | 5001120 | Using where |
| 2 | UNION | messroom | ref | roomID,roomID_id | roomID | 5 | const | 84812 | Using where |
| 3 | UNION | messroom | ref | roomID,roomID_id | roomID | 5 | const | 1227150 | Using where |
| 4 | UNION | messroom | ref | roomID,roomID_id | roomID_id | 5 | const | 400652 | Using where |
| NULL | UNION RESULT | <union1,2,3,4> | ALL | NULL | NULL | NULL | NULL | NULL | Using filesort |
+----+--------------+----------------+------+------------------+-----------+---------+-------+---------+----------------+
5 rows in set (0.00 sec)
deadka, большое спасибо!
vasya написал:
Ну и вместо * можно выбирать одни id, а потом для полученных N id выбрать остальные значения.
Пока не знаю, как это реализовать, но за совет спасибо. Завтра поищу и попробую оптимизировать таким образом, поскольку количество сообщений в каждом юнионе будет колебаться вплоть до 500, а количество юнионов - до 20, и эти два показателя будут комбинироваться для различных пользователей в совершенно произвольных комбинациях (пользователь просматривает историю для набора своих комнат, задавая её суммарную длину).