SQLinfo.ru - Все о MySQL

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

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

Вы не зашли.

#1 14.02.2009 22:02:28

Proger
Активист
Откуда: Санкт-Петербург
Зарегистрирован: 04.09.2008
Сообщений: 172

Не цепляет примари индекс при конструкции IN

Есть запрос:

SELECT *
FROM `infosystem`
WHERE `uid`
IN ( 2, 4, 5, 6, 7, 16, 18, 20, 24, 26, 32, 33, 34, 37, 38, 39, 42, 44, 45, 66, 67, 68, 71, 73, 1001, 1002, 1005 )
ORDER BY `time` DESC


Структура таблицы:
CREATE TABLE `infosystem` (
  `uid` int(8) NOT NULL,
  `type` varchar(20) NOT NULL,
  `what` varchar(20) NOT NULL,
  `where` int(8) NOT NULL,
  `info` varchar(500) NOT NULL,
  `time` datetime NOT NULL,
  KEY `uid` (`uid`),
  KEY `uid_2` (`uid`,`time`)
) ENGINE=InnoDB DEFAULT CHARSET=cp1251;



Запрос падает в slow-query-log.
Explain:
id     select_type     table     type     possible_keys     key     key_len     ref     rows     Extra
1     SIMPLE     infosystem     ALL     uid,uid_2     NULL     NULL     NULL     154     Using where, Usind filesort

Собственно почему не цепляет индекс? Как бороться? Ибо условий IN может быть до 500 где-то...

Отредактированно Proger (14.02.2009 22:22:00)

Неактивен

 

#2 14.02.2009 23:13:21

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: Не цепляет примари индекс при конструкции IN

Попробуйте FORCE INDEX. Оптимизатор считает, что один раз пройти всю таблицу проще, чем 500 раз пройти по индексу, и, возможно, это правда.

Неактивен

 

#3 14.02.2009 23:32:33

Proger
Активист
Откуда: Санкт-Петербург
Зарегистрирован: 04.09.2008
Сообщений: 172

Re: Не цепляет примари индекс при конструкции IN

гм... Индекс подцепил но все равно using_filesort. Размер таблицы переменно от 100 до 100000 записей. Возможно следует изменить алгоритм сам вот только как...
Кто быстрее не понять особо, но в slow-query падает же sad( попробую поставить на время FORCE_INDEX может не будет падать...

UID = это ID друзей данного пользователя и я вывожу информацию о том что они за последнее время сделали. Иного алгоритма пока не придумал, попробую пообсуждать.

Отредактированно Proger (14.02.2009 23:32:58)

Неактивен

 

#4 14.02.2009 23:37:24

coin
Гуру
Зарегистрирован: 15.07.2008
Сообщений: 66

Re: Не цепляет примари индекс при конструкции IN

Proger написал:

но все равно using_filesort

Потому что сортируете по полю `TIME`, которое не входит в левый префикс ни одного из ключей.

Отредактированно coin (14.02.2009 23:37:53)

Неактивен

 

#5 15.02.2009 00:03:54

Proger
Активист
Откуда: Санкт-Петербург
Зарегистрирован: 04.09.2008
Сообщений: 172

Re: Не цепляет примари индекс при конструкции IN

ммм. Что за левый префикс, можно тогда "правильный индекс" в студию. Что-то я не допонял...

Неактивен

 

#6 15.02.2009 00:17:58

coin
Гуру
Зарегистрирован: 15.07.2008
Сообщений: 66

Re: Не цепляет примари индекс при конструкции IN

Индексы сортируются примерно так:

Код:

`uid`   `TIME`
0    2009-02-14 23:59:47
0    2009-02-14 23:59:47
0    2009-02-15 00:06:47
1    2009-02-14 23:58:47
1    2009-02-15 00:01:47
1    2009-02-15 00:07:47
2    2009-02-15 00:07:47
3    2009-02-15 00:08:47
4    2009-02-15 00:05:47
4    2009-02-15 00:07:47
5    2009-02-15 00:06:47
6    2009-02-15 00:00:47
6    2009-02-15 00:01:47
6    2009-02-15 00:05:47
7    2009-02-15 00:01:47

Т.е. происходит общая сортировка по первому полю и у групп с равными `uid` записи отсортированы по второму полю `TIME`. А вы хотите от такого индекса общую сортировку по второму полю.
С этим индексом можно работать только по левому префиксу полей:
1) либо `uid`
2) либо `uid`,`TIME`

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

Неактивен

 

#7 15.02.2009 00:20:51

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: Не цепляет примари индекс при конструкции IN

Если запрос был бы ... WHERE uid=10 ORDER BY time
то составной индекс сработал бы. Однако это возможно только если все операции, кроме последней - точное равенство (а не >,<, IN)

Неактивен

 

#8 15.02.2009 00:24:16

coin
Гуру
Зарегистрирован: 15.07.2008
Сообщений: 66

Re: Не цепляет примари индекс при конструкции IN

Я бы создал индекс `TIME`,`uid` и использовал бы запросы вроде:

SELECT *
FROM `infosystem` USE INDEX (`имя индекса`)
WHERE
`TIME` BETWEEN CURRENT_DATE-INTERVAL 5 DAY AND CURRENT_DATE-INTERVAL 4 DAY
AND
`uid` IN ( 2, 4, 5, 6, 7, 16, 18, 20, 24, 26, 32, 33, 34, 37, 38, 39, 42, 44, 45, 66, 67, 68, 71, 73, 1001, 1002, 1005 )
ORDER BY `TIME`

Т.е. что то вроде постраничной навигации по суткам.

Неактивен

 

#9 15.02.2009 00:51:08

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: Не цепляет примари индекс при конструкции IN

coin, вторая часть индекса использоваться в Вашем случае все равно не будет

Неактивен

 

#10 15.02.2009 00:54:50

Proger
Активист
Откуда: Санкт-Петербург
Зарегистрирован: 04.09.2008
Сообщений: 172

Re: Не цепляет примари индекс при конструкции IN

coin, сделал так (индекс не подрубился). Навигация по дням мне тут не пригодится. Но в другом месте уже пригодилась - спасибо.
Вот только не понимаю чего делать ибо индексы не работаюсь, а какой тогда алгоритм выбирать фигзнает sad((

Пользователь делает что-то, например пишет другому комментарий на запись в блоге и это добавляется в таблицу infosystem и как бы тут же любой друг этого пользователя может это увидеть (на странице "новости друзей") и пройти почитать его комментарий и ту запись в блоге которую он комментировал. Как тут иначе то сделать? Создавать по записи на каждого друга? А если друзей 1000 ? ммм... я погряз в глубоких раздумьях...

Отредактированно Proger (15.02.2009 00:58:29)

Неактивен

 

#11 15.02.2009 00:54:50

coin
Гуру
Зарегистрирован: 15.07.2008
Сообщений: 66

Re: Не цепляет примари индекс при конструкции IN

rgbeast, для сортировки не будет (и не надо), а для выборки помоему должна, почему нет?

Отредактированно coin (15.02.2009 00:55:14)

Неактивен

 

#12 15.02.2009 01:07:58

Proger
Активист
Откуда: Санкт-Петербург
Зарегистрирован: 04.09.2008
Сообщений: 172

Re: Не цепляет примари индекс при конструкции IN

КСТАТИ! Я тут подумал. А если сортировать на стороне php? То есть только выборку по UID IN() сделать, а отсортировать уже в php?

Ну да... наверное это самый оптимальный вариант. Только не FORCE INDEX, а USE чтобы оптимизатор сам там подумал что быстрее. Использовать кучу проходов по индексу или по таблице.

Отредактированно Proger (15.02.2009 01:21:10)

Неактивен

 

#13 15.02.2009 01:16:12

coin
Гуру
Зарегистрирован: 15.07.2008
Сообщений: 66

Re: Не цепляет примари индекс при конструкции IN

Т.е. выборка вообще ничем не ограничивается? Если есть 1000 записей - все выводить?
/ Не думаю что у PHP сортировка 2мерного ассоциативного массива выйдет быстрее )

Неактивен

 

#14 15.02.2009 01:19:51

Proger
Активист
Откуда: Санкт-Петербург
Зарегистрирован: 04.09.2008
Сообщений: 172

Re: Не цепляет примари индекс при конструкции IN

дык данные об активности людей автоматом чистятся. И выводится за последние несколько дней примерно.
Притом данные ещё проходят парсер. Который например группирует одинаковые события. Например человек загрузил 100 фотографий мне что о каждой фотке отдельный раз информацию вывести? Нет я просто беру и пишу юзер "загрузили фото (N штук)".

Тут вопрос даже не в скорости, а в том чтобы запрос не падал в slow-query-log ибо мешает следить за другими неполадками.

Также подумываю сделать кеширование материала, чтобы генерировать всю информацию и парсить её в том числе один раз, а не при каждом просмотре.

Неактивен

 

#15 16.02.2009 17:45:55

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

Re: Не цепляет примари индекс при конструкции IN

Извините, немножко вклинюсь.

1. На таблице InnoDB нет явного primary key - это плохо.
2. Второй индекс полностью включает в себя первый. Первый индекс можно смело снести.

Без первичного ключа данные лежат тостаточно хаотично (и уж точно не в порядке id).
Когда оптимизатор пытается решить, что лучше - выбрать 30 строк из 150 по хаотичным
данным или прочитать все и отсортировать - он предпочитает второе. Оно, разумеется, быстрее.

Неактивен

 

#16 17.02.2009 19:45:15

Magz
Гуру
Откуда: Москва
Зарегистрирован: 18.09.2007
Сообщений: 112

Re: Не цепляет примари индекс при конструкции IN

Вообще, операция IN сама по себе долгая. Как я понимаю, набор значений, которые подставляются в IN получаются на основе каких-то запросов? Не получится ли сделать примерно так:

Код:

SELECT field
FROM (SELECT значения_которые_в_IN FROM tables WHERE условия_использующие_индексы) t1
JOIN infosystem ON infosystem.uid = t1.данные

ИМХО, в этом случае индексы должны будут использоваться гораздо эффективнее. По крайней мере, у меня скорость подобного запроса на 2 000 000 строчках выросла с 4-5 минут до 5-7 секунд. Правда, это было на оракле, но не думаю, что в данном случае будет разница.

Неактивен

 

#17 24.02.2009 08:44:41

Proger
Активист
Откуда: Санкт-Петербург
Зарегистрирован: 04.09.2008
Сообщений: 172

Re: Не цепляет примари индекс при конструкции IN

paulus - примари индекс нарисовал, индекс первый потёр, а какие ещё варианты? То что предложил Magz?

Magz - верно, я выбираю сначала список друзей, потом генерирую запрос. И уже сейчас понял что это неверное вообще бить на запросы было. хм...

ЗЫ в slow query log кстати падали абсолютно все запросы почему-то. Но данный запрос всё равно не верен - факт.

Отредактированно Proger (24.02.2009 08:46:09)

Неактивен

 

#18 24.02.2009 15:31:03

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

Re: Не цепляет примари индекс при конструкции IN

Ну в slow log он падает потому что у Вас или очень-очень медленный сервер, или таки включена запись
запросов без индексов. Для маленьких табличек - это нормально.

Неактивен

 

#19 24.02.2009 19:14:13

Proger
Активист
Откуда: Санкт-Петербург
Зарегистрирован: 04.09.2008
Сообщений: 172

Re: Не цепляет примари индекс при конструкции IN

Странно в slow-query падало всё подряд (вырубил просто slow-query ибо падали запросы даже системные самого мускуля к базе mysql и information_schema). Однако EXPLAIN плохой только на нескольких запросах...

Сервер нормальный, загрузка в среднем не более 10% процессора. И оперативка на одну пятую только занята во время основных нагрузок на сервер.

ADD: да была включена запись запросов без индексов.

Отредактированно Proger (24.02.2009 19:17:26)

Неактивен

 

#20 25.02.2009 18:48:26

EugeneTM
Гуру
Зарегистрирован: 11.04.2008
Сообщений: 89

Re: Не цепляет примари индекс при конструкции IN

Magz написал:

Вообще, операция IN сама по себе долгая.

Операция IN нормальная, быстрая.
Прекрасно понимает индексы.

Проблемы возникают если источник IN не константа - подзапрос.
Оптимизатор MySQL криво их отрабатывает, может выполнить его далеко не один раз.
http://sqlinfo.ru/forum/viewtopic.php?id=559

Я эту проблему для себя решил
Подобные конструкции заворачиваю в ХП.
Разбиваю на два запроса.

Сначала выполняю подзапрос, результат загоняю в строку через GROUP_CONCAT.
SELECT GROUP_CONCAT(bla) FROM blabla WHERE id = 1 INTO blablabla;

Затем собираю строку основного запроса
@qry = CONCAT("SELECT id FROM test WHERE test.bla IN (" , blablabla, ")";

Дальше через PREPARE его выполняю
http://sqlinfo.ru/forum/viewtopic.php?id=363

В результате жестко выполняю подзапрос ОДИН раз и не имею проблем с оптимизатором.

Неактивен

 

#21 26.02.2009 11:23:35

Magz
Гуру
Откуда: Москва
Зарегистрирован: 18.09.2007
Сообщений: 112

Re: Не цепляет примари индекс при конструкции IN

EugeneTM написал:

Magz написал:

Вообще, операция IN сама по себе долгая.

Операция IN нормальная, быстрая.
Прекрасно понимает индексы.

Я имел ввиду, что поиск каждого значения из IN происходит по полной таблице. Да, индекс, конечно, используется, но запорс, где в IN стоит два значения практически равен двум отдельным запросом. Вернее, сопоставим с выполнением двух отдельных запросов с равенством. И чем больше значений в IN, тем тяжелее получается запрос. Естественно, это заметно на больших объемах данных.

Код:

SELECT * FROM Table WHERE f IN (1,2)
// Сопоставим с 
SELECT * FROM Table WHERE f =1 UNION SELECT * FROM Table WHERE f =2

Возможно, я не прав, к этому выводу я пришел самостоятельно после большого числа экспериментов.

Отредактированно Magz (26.02.2009 11:25:29)

Неактивен

 

#22 26.02.2009 12:53:46

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

Re: Не цепляет примари индекс при конструкции IN

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

Неактивен

 

#23 26.02.2009 13:01:08

Magz
Гуру
Откуда: Москва
Зарегистрирован: 18.09.2007
Сообщений: 112

Re: Не цепляет примари индекс при конструкции IN

Ну, я написал просто, как иллюстрацию своих слов. Естественно, оптимизатор работает не так smile Главное, что сопоставимо.

Неактивен

 

#24 26.02.2009 23:14:13

EugeneTM
Гуру
Зарегистрирован: 11.04.2008
Сообщений: 89

Re: Не цепляет примари индекс при конструкции IN

Magz написал:

EugeneTM написал:

Magz написал:

Вообще, операция IN сама по себе долгая.

Операция IN нормальная, быстрая.
Прекрасно понимает индексы.

Я имел ввиду, что поиск каждого значения из IN происходит по полной таблице. Да, индекс, конечно, используется, но запорс, где в IN стоит два значения практически равен двум отдельным запросом. Вернее, сопоставим с выполнением двух отдельных запросов с равенством. И чем больше значений в IN, тем тяжелее получается запрос. Естественно, это заметно на больших объемах данных.

Код:

SELECT * FROM Table WHERE f IN (1,2)
// Сопоставим с 
SELECT * FROM Table WHERE f =1 UNION SELECT * FROM Table WHERE f =2

Возможно, я не прав, к этому выводу я пришел самостоятельно после большого числа экспериментов.

Не прав
Explain посмотри, по сути то же самое что и WHERE id = const

PS.
В него вообще почаще заглядывать нужно, он может фингню делать, но как правило не врет.
В смысле что пишет, то и делает
smile

Неактивен

 

Board footer

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