MySQL утверждает, что я могу использовать столбцы в SELECT, которых нет в GROUP BY, но я не могу с одинаковой производительностью - PullRequest
0 голосов
/ 19 ноября 2010

Документы MySQL сообщают в разделе 11.5.3 , что, несмотря на то, что может сказать стандарт SQL, очень просто использовать столбцы в предложении SELECT, которых нет в предложении GROUP BY, так долгопоскольку они функционально зависят от сгруппированного ключа.

MySQL расширяет использование GROUP BY, так что вы можете использовать неагрегированные столбцы или вычисления в списке выбора, которые не отображаются в предложении GROUP BY.Вы можете использовать эту функцию для повышения производительности, избегая ненужной сортировки и группировки столбцов.Например, вам не нужно группировать данные по customer.name в следующем запросе:

SELECT order.custid, customer.name,
MAX(payments)   FROM order,customer  
WHERE order.custid = customer.custid  
GROUP BY order.custid;

В стандартном SQL вам потребуется добавить customer.name в предложение GROUP BY.В MySQL имя избыточно.

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

EXPLAIN SELECT o.id FROM objects o GROUP BY o.id;
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
|  1 | SIMPLE      | o     | range | NULL          | PRIMARY | 3       | NULL | 5262 | Using index for group-by |
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+

(я понимаю, что этот запрос довольно глупый; это просто самая простая версияболее сложный запрос, имеющий ту же проблему.) При выборе только группы первичного ключа, сгруппированной по I, MySQL использует индекс первичного ключа.Однако, когда я включаю другие столбцы, MySQL этого не делает.

EXPLAIN SELECT o.id, o.name FROM objects o GROUP BY o.id;
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
|  1 | SIMPLE      | o     | ALL  | NULL          | NULL | NULL    | NULL | 5261 | Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+

Это использование файловой сортировки вместо индекса действительно отбрасывает меня назад.В настоящее время я хочу выбрать * из этой таблицы, поэтому хотел бы избежать необходимости повторять все столбцы в группе и индексировать их.Есть ли способ заставить MySQL использовать индекс первичного ключа, как я ожидаю?

Ответы [ 3 ]

0 голосов
/ 19 ноября 2010

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

То, что я сделает , будет выглядеть примерно так:

SELECT o1.* FROM objects o1 WHERE o1.id IN (SELECT o2.id FROM objects o2 WHERE mycondition GROUP BY o2.id)

Однако, в зависимости от того, как он получает EXPLAIN ed, оптимизатор MySQL рассматривает подзапрос как зависимый, который всегда является действительно очень неприятным убийцей производительности. Я думаю, что это ошибка в оптимизаторе запросов, вызванная тем, что это одна и та же таблица, хотя она и псевдоним. Таким образом, я буду использовать один запрос для извлечения идентификаторов и помещать их IN во второй запрос, который извлекает o.*. Это дает разумную производительность, и не является слишком болезненным.

Этот вопрос все еще открыт для ответов с более чистыми решениями, которые также работают, если не лучше :)

0 голосов
/ 20 ноября 2010

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

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

Что касается оптимизации, то если в вашем реальном запросе нет накопительных функций (SUM, COUNT и т. д.), как в вашем примеремы должны увидеть значительное улучшение, просто сделав:

SELECT DISTINCT o.id, o.name FROM objects o

Однако, если это верно только для вашего простого примера и ваш запрос действительно требует GROUP BY, тогда ваша следующая лучшая ставка - увеличить tmp_table_size иmax_heap_table_size переменные для одновременного размещения большего количества строк в памяти.

0 голосов
/ 19 ноября 2010

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

...