2012-03-16 3 views
2

Запрос:Оптимизация порядка запросов по результатам с помощью filesort;

SELECT 
     r.reply_id, 
     r.msg_id, 
     r.uid, 
     r.body, 
     r.date, 
     u.username as username, 
     u.profile_picture as profile_picture 
    FROM 
     pm_replies as r 
     LEFT JOIN users as u 
      ON u.uid = r.uid 
    WHERE 
     r.msg_id = '784351921943772258' 

    ORDER BY r.date DESC 

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

этот запрос принимает на 0,33 возвращенных товаров и подсчета ...


EXPLAIN:

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE r ALL  index1 NULL NULL NULL 540  Using where; Using filesort 
1 SIMPLE u eq_ref uid  uid  8 site.r.uid 1 

SHOW CREATE pm_replies

CREATE TABLE `pm_replies` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`reply_id` bigint(20) NOT NULL, 
`msg_id` bigint(20) NOT NULL, 
`uid` bigint(20) NOT NULL, 
`body` text COLLATE utf8_unicode_ci NOT NULL, 
`date` datetime NOT NULL, 
PRIMARY KEY (`id`), 
KEY `index1` (`msg_id`,`date`,`uid`) 
) ENGINE=MyISAM AUTO_INCREMENT=541 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

SHOW CREATE пользователи

CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT, 
`uid` bigint(20) NOT NULL, 
`username` varchar(20) COLLATE utf8_unicode_ci NOT NULL, 
`email` text CHARACTER SET latin1 NOT NULL, 
`password` text CHARACTER SET latin1 NOT NULL, 
`profile_picture` text COLLATE utf8_unicode_ci NOT NULL, 
`date_registered` datetime NOT NULL, 
PRIMARY KEY (`id`), 
UNIQUE KEY `uid` (`uid`), 
UNIQUE KEY `username` (`username`) 
) ENGINE=MyISAM AUTO_INCREMENT=2004 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 
+0

Можете ли вы добавить вывод 'SHOW CREATE TABLE pm_replies',' SHOW CREATE TABLE users', 'EXPLAIN SELECT <весь ваш выбор здесь>'? Кроме этого, вероятным индексом будет 'r.msg_id, r.uid', и вы захотите' u.uid' иметь индекс тоже (лучший уникальный). – Konerak

+0

@Konerak обновленный вопрос – fxuser

+0

Вы указали u.uid, r.uid, r.msg_id и r.date? EDIT: Я вижу ... Попробуйте индексировать дату в pm_replies –

ответ

0

Пожалуйста, попробуйте следующее:

SELECT 
     r.reply_id, 
     r.msg_id, 
     r.uid, 
     r.body, 
     r.date, 
     u.username as username, 
     u.profile_picture as profile_picture 
    FROM 
     pm_replies as r 
     LEFT JOIN users as u 
      ON (u.uid = r.uid AND r.msg_id = '784351921943772258') 
    ORDER BY r.date DESC 

в моем случае это поможет.

+0

такой же время загрузки. – fxuser

+1

Это функционально отличается и, скорее всего, неверно. OP берет определенный набор строк из 'pm_replies', на основе' msg_id', а затем слева соединяет их с 'users'. * (Возможно, всего одна строка.) * Вы берете *** все *** строки из 'pm_replies', но присоединяете их только к' users' для определенного 'msg_id', все остальные все еще проходят, но как NULL. Это не ответ. – MatBailie

+0

Вы указали поля r.msg_id и r.date? – Mirodil

5

Для запроса, как это, лучшие показатели, казалось бы, ...

pm_replies: (msg_id, date, uid) 
users:  (uid) 

Важным является один pm_replies. Вы используете его для фильтрации ваших данных (сначала столбец фильтра), затем заказывайте свои данные (второй столбец заказа).

Было бы иначе, если вы удалили фильтр. Тогда вам просто нужно указать (date, uid).

Последнее поле в индексе просто делает его более дружественным к соединению, важной частью на самом деле является индекс на users.

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


EDIT

Не то, что мой Рекомендованное индекс pm_replies один индекс охватывает три поля, а не только три индекса. Это гарантирует, что все записи в индексе предварительно отсортированы по этим столбцам. Это похоже на сортировку данных в Excel на три столбца.

Имея три отдельных индекса, как данные Excel на трех вкладках. Каждый сортируется по другим полям.

Только с одним индексом в трех полях вы получаете такое поведение ...
- Вы можете выбрать один «кучу» записей с тем же MSG_ID
- Вся эта «связка» рядом друг с другом, без пробелов и т.д.
- Весь этот «букет» сортируются в хронологическом порядке для того MSG_ID
- для любых строк с той же датой, они отсортированы по user_id

(Опять user_id часть действительно очень незначительные.) дата

+1

+1, дата - вот ключ, который я думаю. – davidethell

+0

, так что вы говорите, чтобы создать 1 индекс с 3 столбцами, если это так, похоже, не помогает. – fxuser

+0

updated EXPLAIN и SHOW CREATE TABLE для ответов – fxuser

0

Добавить в свой ключ iNDEX1 так что MSG_ID и дата как в индекс.

+0

все еще ничего не меняется – fxuser

0

Что Dems is saying должен быть правильным, но есть одна дополнительная деталь, если вы используете InnoDB: возможно, вы платите цену secondary indexes on clustered tables - по существу, доступ к ряду через вторичный индекс требует дополнительного поиска корыта первичного, т.е. индекс кластеризации. Этот «двойной поиск» может сделать индекс менее привлекательным для оптимизатора запросов.

Чтобы облегчить эту проблему, попробуйте covering в всех поля в вашем отборном заявлении с индексом:

pm_replies: (msg_id, date, uid, reply_id, body, date) 
users:  (uid, username, profile_picture) 
+0

все мои таблицы - myisam, я изменился на innodb, чтобы проверить комментарий dems. – fxuser

+0

@fxuser Еще одна вещь: вы пробовали использовать индекс 'pm_replies: (msg_id, uid)', так как это LEFT join, а 'users' - это« внешняя »таблица. Кроме того, вы пытались удалить LEFT, просто чтобы узнать, что произойдет? –

+0

@fxuser Или даже 'pm_replies: (uid, msg_id)'? –

0

Оказывается, оптимизатор пытается заставить индекс по идентификатору, чтобы сделать присоединиться к пользователю Таблица. Поскольку вы выполняете левое соединение (что не имеет смысла, поскольку я ожидаю, что каждая запись будет иметь идентификатор пользователя, таким образом, нормальный INNER JOIN), я оставлю это влево.

Итак, я бы попробовал следующее. Запрос только ответы, основанные на ID MESSAGE и порядке по дате по убыванию по заслугам, затем налево присоединиться, такие как

SELECT 
     r.reply_id, 
     r.msg_id, 
     r.uid, 
     r.body, 
     r.date, 
     u.username as username, 
     u.profile_picture as profile_picture 
    FROM 
     (select R2.* 
      from pm_replies R2 
      where r2.msg_id = '784351921943772258') r 
     LEFT JOIN users as u 
      ON u.uid = r.uid 
    ORDER BY 
     r.date DESC 

Кроме того, так как у меня нет MySQL легко доступны, и не может помните, если порядок в разрешении разрешен в подзапросе, если это так, вы можете оптимизировать внутренний прекурсор (используя псевдоним «R2») и поместить здесь заказ, поэтому он использует индекс (msgid, date) и возвращает только этот набор ... THEN присоединяется к пользовательской таблице на идентификаторе, который не требуется индексу в этой точке из набора результатов SOURCE, а только индекс в таблице пользователя, чтобы найти совпадение.

+0

это займет еще больше времени, и добавление 1 индекса на 2 столбца (msg_id, date) тоже не будет работать. – fxuser

+0

@fxuser, извините, что это не сработало, но вам всегда нужно попробовать альтернативы от того, что может думать двигатель. Это был простой тест, и он работал быстрее или нет. Один из многих подходов к поиску улучшений производительности. – DRapp

Смежные вопросы