SQLinfo.ru - Все о MySQL Webew.ru: теория и практика веб-технологий

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

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

Вы не зашли.

#1 17.03.2012 01:26:28

Lsync
Участник
Откуда: Киев
Зарегистрирован: 17.03.2012
Сообщений: 3

Выборка последних, WHERE IN и ORDER BY DES

Доброго дня.

Подскажите, пожалуйста, можно ли избавиться (и каким способом) от файл-сортировки в такой вот ситуации.

Есть таблица чат-сообщений, с полями id (автоинкремент), roomID (int) и text. Общее количество сообщений в этой таблице - десятки миллионов. Количество комнат (roomId) - десятки. Цель - получить N последних сообщений для K комнат, где N=10..1000, K=1..20. При этом количество сообщений в каждой комнате не обязано быть одинаковым - нужны глобально последние записи.

Пример результата выборки (N=5, комнаты 3 и 7):

|  id  |   time   | roomID | text |
| 0120 | 17:40:00 |      3 |  ... |
| 0136 | 17:40:02 |      7 |  ... |
| 0142 | 17:40:06 |      3 |  ... |
| 0154 | 17:40:08 |      3 |  ... |
| 0168 | 17:40:11 |      3 |  ... |


В примере ID сообщений растет неравномерно, поскольку есть фоновые сообщения в других комнатах.

SQL знаю весьма плохо, поэтому вот такая моя писанина (и результаты её работы) ни капли не радуют:

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 | 5       | NULL | 5410580 | Using where; Using filesort |
+----+-------------+----------+-------+---------------+--------+---------+------+---------+-----------------------------+


Почитал про принципы работы индексов, попробовал добавить индекс roomID+id - никаких изменений, кроме того, что explain показывает, что планирует использовать именно его.

Если нужно - могу привести все данные о таблицах и времени выборок, но что-то мне подсказывает, что существует какое-то типовое решение для подобных случаев. Поиск по форумам пока не помог - не нашел примеров, которые либо адаптировались бы для моих условий, либо которые я хоть как-то способен понять.

Просьба поделиться ссылкой на пример, который подошел бы под мои условия, и/или хотя бы вкратце разъяснить, какова концепция решения.

Спасибо.
Валентин

Неактивен

 

#2 17.03.2012 01:47:19

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2422

Re: Выборка последних, WHERE IN и ORDER BY DES

Здравствуйте.

Lsync написал:

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 | 5       | NULL | 5410580 | Using where; Using filesort |
+----+-------------+----------+-------+---------------+--------+---------+------+---------+-----------------------------+

Покажите show create table messroom; пожалуйста.

Lsync написал:

Почитал про принципы работы индексов, попробовал добавить индекс roomID+id - никаких изменений, кроме того, что explain показывает, что планирует использовать именно его.

Ну вообще на этот запрос идеально подходит именно индекс (roomID, id);
Покажите explain с ним. И как насчет скорости выполнения - возрастает?
Хотя 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;
И покажите explain'ы на них тоже.

Lsync написал:

Если нужно - могу привести все данные о таблицах и времени выборок, но что-то мне подсказывает, что существует какое-то типовое решение для подобных случаев. Поиск по форумам пока не помог - не нашел примеров, которые либо адаптировались бы для моих условий, либо которые я хоть как-то способен понять.

Просьба поделиться ссылкой на пример, который подошел бы под мои условия, и/или хотя бы вкратце разъяснить, какова концепция решения.

Табличку messroom сможете если что выложить на какой-нибудь файлообменник? Чем больше там записей будет тем лучше. Пока не надо - но если что попрошу.

Касательно концепции решения - она крутится вокруг составного индекса на (roomID, id)
Есть вероятность, что запрос будет иметь смысл переписать в виде

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;
 


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#3 17.03.2012 02:02:21

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: Выборка последних, WHERE IN и ORDER BY DES

deadka написал:

Касательно концепции решения - она крутится вокруг составного индекса на (roomID, id)
Есть вероятность, что запрос будет иметь смысл переписать в виде

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;
 

Насколько я понимаю, через union придется переписывать, потому что иначе будет использована только первая часть индекса для условия `roomID` IN (3,7) по типу range и далее файлсорт.
В варианте через union тоже будет файлсорт, то для 10 строк, в то время как в первом случае для всех удовлетворяющих условию `roomID` IN (3,7), т.е. 5410580

Ну и вместо * можно выбирать одни id, а потом для полученных N id выбрать остальные значения.

Неактивен

 

#4 17.03.2012 02:07:38

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2422

Re: Выборка последних, WHERE IN и ORDER BY DES

vasya написал:

Насколько я понимаю, через union придется переписывать, потому что иначе будет использована только первая часть индекса для условия `roomID` IN (3,7) по типу range и далее файлсорт.

То есть MySQL сам не сообразит, что условие IN(3,7) можно хорошо соптимизировать, да? Это ж ведь не range на самом деле.
Есть еще sort_union, я на него натыкался  (подробности здесь: http://sqlinfo.ru/forum/viewtopic.php?id=3884), правда там условие OR состояло из двух полей различных, а не на два значения различных на одно поле.


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#5 17.03.2012 02:35:59

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: Выборка последних, WHERE IN и ORDER BY DES

Насколько я понимаю sort_union применяется когда части индекса относятся к условиям в where

"This access algorithm is employed when the WHERE clause was converted to several range conditions combined by OR"
http://dev.mysql.com/doc/refman/5.5/en/ … union.html

Кроме того, он ведь выбирает все строки по условию и сортирует их? А в данном случае хочется как раз ограничиться выборкой не более N строк каждого типа.

Неактивен

 

#6 17.03.2012 02:43:47

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2422

Re: Выборка последних, WHERE IN и ORDER BY DES

Ну если не более N строк каждого типа, тогда union. Ну или просто двумя запросами - ничем не хуже по большому счёту. C составным индексом, указанным выше должно хорошо получиться. Подождём пока отпишет топикстартер smile.


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#7 20.03.2012 02:07:49

Lsync
Участник
Откуда: Киев
Зарегистрирован: 17.03.2012
Сообщений: 3

Re: Выборка последних, WHERE IN и ORDER BY DES

На выходных был не у компьютера, прошу прощения за паузу.

Вот точные данные по таблицам и выборкам. Построил заново индекс 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, и эти два показателя будут комбинироваться для различных пользователей в совершенно произвольных комбинациях (пользователь просматривает историю для набора своих комнат, задавая её суммарную длину).

Неактивен

 

#8 20.03.2012 02:36:02

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: Выборка последних, WHERE IN и ORDER BY DES

Lsync написал:

(плюс где-то прочитал, что на индексы таблиц InnoDB MySQL автоматически добавляет последним столбцом первичный ключ).

Это не так. Скорее вы читали, что вторичные ключи в innodb содержат указатель на первичный ключ, или вы читали явную дезинформацию.

Lsync написал:

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)

А кто может объяснить такое странное поведение explain. С одной стороны из key_len мы видим, что используется только первая часть индекса, с другой в extra нет using filesort (который там появится, если мы будем сортировать по другому полю)

Lsync написал:

Пока не знаю, как это реализовать, но за совет спасибо.

select `нужные вам поля` from `messroom` m join (ваш текущий запрос с union-ами, где вместо * указано одно поле id) t on m.id=t.id;
(Да и вообще * никогда писать не стоит).

Неактивен

 

Board footer

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