MySQL, GROUP BY - невероятные тормоза

12
elitedesign
На сайте с 25.10.2012
Offline
69
3299

Всем привет. Возможно переработал, мозг не находит готового решения сходу.

SELECT `browser`,`stream_id`,`source_id`,`service_id`,`user_id`

FROM clients_log

WHERE `user_id`!='0'

GROUP BY `browser`

ORDER BY NULL

В таблице несколько миллионов записей. Результат выдает за 200 с чем то секунд.

- поле user_id - int(10)

- поле browser - VARCHAR(50),

- сделан индекс по полю user_id

Как максимально возможно это ускорить?

Заранее спасибо за Ваше время.

S
На сайте с 23.05.2004
Offline
315
#1

Создать индекс из browser + user_id

Как вариант иметь поле browser_crc (INT) и там хранить crc число от поля browser . Тогда идекс по browser_crc + user_id по идее будет быстрее, так как это числа.

---------- Добавлено 07.08.2017 в 15:49 ----------

P.S. "ORDER BY NULL" - это что такое вообще ?

Это просто подпись.
elitedesign
На сайте с 25.10.2012
Offline
69
#2
Stek:
Создать индекс из browser + user_id

Как вариант иметь поле browser_crc (INT) и там хранить crc число от поля browser . Тогда идекс по browser_crc + user_id по идее будет быстрее, так как это числа.

---------- Добавлено 07.08.2017 в 15:49 ----------

P.S. "ORDER BY NULL" - это что такое вообще ?

Спасибо за ответ.

1. ORDER BY NULL - отмена сортировки. Заметил что иногда из за этого есть прирост в скорости.

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

M
На сайте с 04.12.2013
Offline
223
#3

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

Отмена сортировки – убрать конструкцию ORDER BY. Вы зачем вообще группировку используете? Она нужна для т.н. агрегатных ф-ций. Если вы просто хотите распределить выборку по группам, используйте сортировку по соотв. полю: ORDER BY `browser`.

Домены и скрипт для коротких ссылок: https://u75.ru/domains-for-shortcuts
elitedesign
На сайте с 25.10.2012
Offline
69
#4

Stek, miketomlin, спасибо за содействие.

Вопрос: мне стоит добавить browser в существующий составной индекс где уже используется user_id или лучше создать новый индекс на browser и user_id?

M
На сайте с 04.12.2013
Offline
223
#5

На уточняющие вопросы принято отвечать.

Для обычной сортировки можно включить browser в существующий индекс, только соблюдайте «смежность» и нужный порядок следования составных частей в индексе (сначала из WHERE, потом из ORDER BY).

edogs software
На сайте с 15.12.2005
Offline
775
#6
elitedesign:
Всем привет. Возможно переработал, мозг не находит готового решения сходу.

SELECT `browser`,`stream_id`,`source_id`,`service_id`,`user_id`
FROM clients_log
WHERE `user_id`!='0'
GROUP BY `browser`
ORDER BY NULL

В таблице несколько миллионов записей. Результат выдает за 200 с чем то секунд.
- поле user_id - int(10)
- поле browser - VARCHAR(50),
- сделан индекс по полю user_id

Как максимально возможно это ускорить?

Заранее спасибо за Ваше время.

1) Попробуйте запрос вида

SELECT distinct(`browser`),`stream_id`,`source_id`,`service_id`,`user_id`

FROM clients_log

WHERE `user_id`!='0'

2) В любом случае уберите order by null

3) Убедитесь что mysql хотя бы 5.6 версии, а в идеале 5.7. В 5.6 пофиксили много багов с оптимизацией запросов, в 5.7 еще дочистили.

4) Добавьте индекс на browser, user_id или user_id, browser

5) Подумайте о перестройке структуры БД.

При нескольких миллионах записей хранить browser varchar(50) несколько бессмысленно, тем более varchar(50) может обрезать юзер-агента при такой короткой длине. Вынесите browser в отдельную таблицу, оставьте референс в виде browser_id int.

пысы: мы бы начали с пункта 5.

Разработка крупных и средних проектов. Можно с криптой. Разумные цены. Хорошее качество. Адекватный подход. Продаем lenovo legion в спб, дешевле магазинов, новые, запечатанные. Есть разные. skype: edogssoft
mendel
На сайте с 06.03.2008
Offline
232
#7

Я так понимаю нужен distinct, и соответственно напрашивается индекс на все вот эти вот поля:

`browser`,`stream_id`,`source_id`,`service_id`,`user_id`

По логике наверное первым указывать юзера?

Ну и в целом конечно edogs правильно написал и по юзерагенту и по остальному.

Шутку любишь над Фомой, так люби и над собой. (с) народ. Бесплатные списки читабельных(!) свободных доменов (http://burzhu.net/showthread.php?t=2976) (5L.com) Сайты, All inclusive. 5* (/ru/forum/962215)
Aisamiery
На сайте с 12.04.2015
Offline
319
#8

А я бы прежде чем начать гадать по гуще, попробовал бы запустить с explain

Разработка проектов на Symfony, Laravel, 1C-Bitrix, UMI.CMS, OctoberCMS
M
На сайте с 04.12.2013
Offline
223
#9

Так практический опыт, которым тут делятся, обычно на этом и основан. Или тут собрались одни теоретики?

Хотя лично мне даже назначение запроса не до конца понятно (ТСу влом ответить, зачем это нужно), поэтому отчасти приходится гадать.

dma84
На сайте с 21.04.2009
Offline
168
#10
edogs:

2) В любом случае уберите order by null

Ещё один. Вы знаете, для чего это нужно? Специально для вас:

By default, MySQL sorts all GROUP BY col1, col2, ... queries as if you specified ORDER BY col1, col2, ... in the query as well. If you include an explicit ORDER BY clause that contains the same column list, MySQL optimizes it away without any speed penalty, although the sorting still occurs.

If a query includes GROUP BY but you want to avoid the overhead of sorting the result, you can suppress sorting by specifying ORDER BY NULL.

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

В этой таблице сделайте уникальный ключ по USER_AGENT, а можете и по browser_crc (INT), как выше предлагали, только смысла в этом не вижу.

Запрос:


SELECT
`b`.`browser`,
`l`.`stream_id`,
`l`.`source_id`,
`l`.`service_id`,
`l`.`user_id`
FROM `clients_log` AS `l`
JOIN `browsers` AS `b` ON (`b`.`id` = `l`.`browser_id`)
WHERE
`l`.`user_id` <> 0
GROUP BY `l`.`browser_id`
ORDER BY NULL

Это если необходимо выбрать USER_AGENT из базы, а если нет, то вообще без JOIN'ов обойдётесь, тупо по `browser_Id` группировать. Структуру таблиц сами додумаете, не маленькие.

И ещё, запрос без лимитов на таком количестве данных - слабоумие и отвага?

12

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий