Индексирование с помощью GROUP BY, ORDER BY и GROUP_CONCAT - PullRequest
2 голосов
/ 12 сентября 2011

решено СМОТРЕТЬ НИЖЕ

Я пытаюсь использовать и GROUP BY, и ORDER BY в своем запросе, где я получаю данные, отсортированные по сложности.Я должен использовать GROUP BY из-за GROUP CONCAT, поскольку некоторые таблицы, такие как 'lookup_peripheral', связывают несколько значений с одним и тем же ключом (content_id).Я понимаю, почему MYSQL не может использовать индекс при выполнении этой задачи, поскольку операторы GROUP BY и ORDER BY не разделяют одно и то же поле.Тем не менее, я ищу альтернативные решения, которые не потребуют дня для получения результатов.

Если я опущу предложение GROUP BY или ORDER BY, тогда база данных использует индекс, но в результатах отсутствуют все периферийные устройства или они не отсортированы по сложности.

Я использую таблицу 'lookup_difficulty' в FROM, поэтому я могу использовать этот индекс при упорядочении результатов.Таблицы lookup_xxxxx хранят каждое допустимое значение, а затем другие таблицы, такие как peripheral, связывают отправку со значением через content_id.Все ссылки на представление content_id.Таблица content содержит важную информацию, такую ​​как идентификатор участника, имя и т. Д.

Я прошу прощения, если мой пост недостаточно ясен.

mysql> describe peripheral;
+------------------+----------+------+-----+---------+-------+
| Field            | Type     | Null | Key | Default | Extra |
+------------------+----------+------+-----+---------+-------+
| peripheral_id    | int(2)   | NO   | PRI | NULL    |       |
| peripheral       | char(30) | NO   |     | NULL    |       |
| peripheral_total | int(5)   | NO   |     | NULL    |       |
+------------------+----------+------+-----+---------+-------+

mysql> select * from peripheral;
+---------------+-----------------+------------------+
| peripheral_id | peripheral      | peripheral_total |
+---------------+-----------------+------------------+
|             1 | periph 1        |                0 |
|             2 | periph 2        |                1 |
|             3 | periph 3        |                3 |
+---------------+-----------------+------------------+

:

mysql> describe lookup_peripheral;
+---------------+---------+------+------+---------+-------+
| Field         | Type    | Null | Key  | Default | Extra |
+---------------+---------+------+------+---------+-------+
| content_id    | int(10) | NO   | INDEX| NULL    |       |
| peripheral_id | int(2)  | NO   |      | NULL    |       |
+---------------+---------+------+------+---------+-------+  


mysql> mysql> select * from lookup_peripheral;
+------------+---------------+
| content_id | peripheral_id |
+------------+---------------+
|         74 |             2 |
|         74 |             5 |
|         75 |             2 |
|         75 |             5 |
|         76 |             3 |
|         76 |             4 |
+------------+---------------+

Ниже не используется индекс для lookup_difficulty, а скорее сортировка таблицы и временная таблица.

SELECT group_concat(DISTINCT peripheral.peripheral) as peripheral, content.member, .....
FROM (lookup_difficulty)
LEFT OUTER JOIN lookup_peripheral ON lookup_difficulty.content_id = lookup_peripheral.content_id
LEFT OUTER JOIN peripheral ON peripheral.peripheral_id = lookup_peripheral.peripheral_id
.....
LEFT OUTER JOIN programmer ON programmer.programmer_id = lookup_programmer.programmer_id
LEFT OUTER JOIN lookup_programming_language ON lookup_difficulty.content_id = lookup_programming_language.content_id

GROUP BY lookup_difficulty.content_id
ORDER BY lookup_dfficulty.difficulty_id
LIMIT 30    

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


РЕДАКТИРОВАТЬ: ОТВЕТИТЬ НИЖЕ:

Разобрался.Я сделал то, что подозревал, что должен был сделать, что было добавить подзапрос.Так как MYSQL может использовать только один индекс на таблицу, я не смог собрать вместе GROUP BY и SORT BY для моей конкретной настройки.Вместо этого я добавил еще один запрос, который будет использовать другой индекс в другой таблице для группировки периферийных устройств.Вот что я добавил в операторе SELECT выше:

(SELECT group_concat(DISTINCT peripheral.peripheral) as peripheral
FROM lookup_peripheral
LEFT OUTER JOIN peripheral ON peripheral.peripheral_id = lookup_peripheral.peripheral_id
WHERE lookup_difficulty.content_id = lookup_peripheral.content_id
GROUP BY lookup_peripheral.content_id
LIMIT 1) as peripheral

Я использовал LEFT OUTER, так как некоторые записи не имеют периферийных устройств.Общее время запроса теперь составляет 0,02 с на процессоре 400 МГц с 128 МБ ОЗУ 100 Гц для базы данных по 40 КБ для большинства таблиц.

EXPLAIN теперь дает мне USING INDEX для таблицы lookup_difficulty.Я добавил это, чтобы добиться этого:

ALTER TABLE `pictuts`.`lookup_difficulty` DROP PRIMARY KEY ,
ADD PRIMARY KEY ( `difficulty_id` , `content_id` ) 

Edit 2 Я заметил, что при больших смещениях с использованием нумерации страниц страница будет загружаться значительно медленнее.Возможно, вы испытали это и на других сайтах.К счастью, есть способ избежать этого, на что указывает Петр Зайцев .Вот мой обновленный фрагмент кода для достижения тех же временных интервалов для смещений 30K или 0:

FROM 
SELECT lookup_difficulty.content_id, lookup_difficulty.difficulty_id
FROM lookup_difficulty
LIMIT '.$offset.', '.$per_page.'
) ld

Теперь просто добавьте ld.whatever к каждому JOIN изготовленному, и вот оно!Мой запрос теперь выглядит как полный беспорядок, но по крайней мере он оптимизирован.Я не думаю, что кто-нибудь зайдет так далеко, читая это ...

1 Ответ

2 голосов
/ 12 октября 2011

Введите ответ Джастина, чтобы этот вопрос не попал в список без ответа:

Разобрался. Я сделал то, что, как я подозревал, я должен был сделать, чтобы добавить подзапрос. Поскольку MYSQL может использовать только один индекс на таблицу, я не смог объединить GROUP BY и SORT BY для моей конкретной настройки. Вместо этого я добавил еще один запрос, который будет использовать другой индекс в другой таблице для группировки периферийных устройств. Вот что я добавил в операторе SELECT выше:

(SELECT group_concat(DISTINCT p.peripheral) as peripheral
FROM lookup_peripheral lp
LEFT JOIN peripheral p ON p.peripheral_id = lp.peripheral_id
WHERE ld.content_id = lp.content_id
GROUP BY lp.content_id
LIMIT 1) as peripheral

Я использовал LEFT OUTER, так как некоторые записи не имеют периферийных устройств. Общее время запроса теперь составляет 0,02 с на процессоре 400 МГц с 128 МБ ОЗУ 100 Гц для базы данных из 40 КБ для большинства таблиц.

EXPLAIN теперь дает мне ИНДЕКС ИСПОЛЬЗОВАНИЯ для таблицы lookup_difficulty. Я добавил это для достижения этого:

ALTER TABLE pictuts.lookup_difficulty DROP PRIMARY KEY ,
ADD PRIMARY KEY ( difficulty_id , content_id ) 

Редактировать 2 Я заметил, что при больших смещениях при использовании пагинации страница будет загружаться значительно медленнее. Возможно, вы испытали это и на других сайтах. К счастью, есть способ избежать этого, как отметил Петр Зайцев. Вот мой обновленный фрагмент кода для достижения того же времени для смещений 30K или 0:

FROM 
SELECT ld.content_id, ld.difficulty_id
FROM lookup_difficulty ld
LIMIT '.$per_page.' OFFSET '.$offset.' 
) ld

Теперь просто добавьте ld. Независимо от того, что было сделано в каждом СОЕДИНЕНИИ, и вот оно у вас! Мой запрос теперь выглядит как полный беспорядок, но по крайней мере он оптимизирован. Я не думаю, что кто-нибудь зайдет так далеко, прочитав это ...

...