LINUX.ORG.RU

Как ускорить тяжелые запросы в MySQL?

 


1

1

Можно ли ускорить тяжелые запросы в MySQL?

Сделал лог долгих запросов, там полно такого:

# Time: 200201 17:47:26
# User@Host: root[root] @ localhost [127.0.0.1]
# Thread_id: 71841 Schema: tgadmin_test QC_hit: No
# Query_time: 72.940765 Lock_time: 0.000165 Rows_sent: 51075 Rows_examined: 51075
# Rows_affected: 0 Bytes_sent: 28192695
SET timestamp=1580575646;
SELECT * FROM tgmanager_delayedtasks WHERE completed = 0 AND dt < '2020-02-01 17:46:13.893177';


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

P.S. Почему-то разметка при редактировании только User line break. Поле неактивное. Не выходит добавить ни лоркод ни маркдаун

★★★★★

Последнее исправление: Qwentor (всего исправлений: 5)

Запрос возвращает десятки тысяч строк, и , к сожалению, все поля нужны

И ты все эти десятки тысяч строк, со всеми полями отдаёшь клиенту? Если нет, то можно попытаться вытащить часть обработки в базу.

x3al ★★★★★
()

Запрос возвращает десятки тысяч строк

Видимо ничего не поделаешь. Ну разве что секционирование что-то даст. Но это вряд ли, исходя из того, что большая часть данных должна попасть в выборку. Если именно время транзакции надо сократить - можно по частям таскать(КО)

dt < '2020-02-01 17:46:13.893177'

Странно выглядит, кстати. Снизу ограничения нет?

DllMain
()
Ответ на: комментарий от x3al

И ты все эти десятки тысяч строк, со всеми полями отдаёшь клиенту?

Да

Если нет, то можно попытаться вытащить часть обработки в базу.

Не получится. Там обработка - это сравнение данных с данными из другого источника. Второй источник - mongodb. Хз, если с этим ничего сделать нельзя, может стоит переписать логику приложения и оба источника засунуть в монгу.

Qwentor ★★★★★
() автор топика
Ответ на: комментарий от DllMain

Странно выглядит, кстати. Снизу ограничения нет?

Нет, нужно вытащить все незавершенные до определенного времени

Qwentor ★★★★★
() автор топика
Ответ на: комментарий от Qwentor

может стоит переписать логику приложения и оба источника засунуть в монгу

Да. Либо оба источника засунуть в mysql.

Кроме этого остаётся разве что кэширование (если старые данные не сильно часто меняются), но это уже костыли.

x3al ★★★★★
()
Ответ на: комментарий от Qwentor

Кстати, необязательно данные перемещать в монгу, можно просто их копировать. В монгу (либо в третью базу данных из mysql и mongodb). Суть — тебе нужна база, в которой все данные, а есть ли они ещё где-то — не так важно.

Можно чем-нибудь https://debezium.io/blog/2018/08/30/streaming-mysql-data-changes-into-kinesis/ таким стримить изменения, если менять приложение слишком дорого.

x3al ★★★★★
()
Ответ на: комментарий от Qwentor

Там обработка - это сравнение данных с данными из другого источника

Я конечно не знаю всей кухни, но звучит так, что по частям таскать всё же получится

DllMain
()
Ответ на: комментарий от x3al

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

rikimaru
()
Последнее исправление: rikimaru (всего исправлений: 1)
Ответ на: комментарий от DllMain

Разбил на кучу запросов по 1000 штук - вроде исчезли предупреждения, буду смотреть дальше

Qwentor ★★★★★
() автор топика

Звёздочку заменить на список нужных полей или уменьшить число полей или явный список, на парсинг даты тратится время - максимально упростить, привести к числам

anonymous
()

Я так и не понял. Скажи, а какую проблему ты тут видишь, что ты пытаешься тут победить или решить?

anonymous
()
Ответ на: комментарий от DllMain

Дурень, это не имеет никакого смысла. В чем идея этого действия? Где его рациональная часть?

Кроме того, почему бы не попытаться ускорить запрос?

anonymous
()
Ответ на: комментарий от anonymous

не имеет никакого смысла

А, ну да. Тестов, конечно же, не приведёшь?

почему бы не попытаться ускорить запрос?

Если бы всё было так просто. Кстати, как ты его ускорять предлагаешь? Чёт у меня стойкое ощущение, что вот это тоже ты писал

Звёздочку заменить на список нужных полей или уменьшить число полей или явный список, на парсинг даты тратится время - максимально упростить, привести к числам

DllMain
()
Ответ на: комментарий от DllMain

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

Qwentor ★★★★★
() автор топика
  1. create index on (dt,completed)

  2. 50k+ никогда не будет «достаточно быстро», как было сказано выше, таскать нужно по частям. А вот как таскать по частям - зависит от логики

anonymous
()

Поставь один индекс на две таблицы. dt,completed - именно в таком порядке.

А с completed индекс убери, т.к. если у тебя там значения могут быть только 0 и 1, то кардинальность слишком низкая, и он там не нужен.

unicorne
()
Ответ на: комментарий от Qwentor

Ты индекс неправильно сделал. Надо было сразу на два поля, а не два отдельных на одно.

Я бы сделал на completed,dt, но ниже почему то советуют в обратном порядке. Можно просто создать оба и сравнить скорость.

KivApple ★★★★★
()
Ответ на: комментарий от KivApple

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

Qwentor ★★★★★
() автор топика
Ответ на: комментарий от DllMain

Что мне сливаться? Ты дурак? О чем тут можно в треде говорить с дебилами которые в упор не видят, что он строит два индекса один из которых не используется вместо составного в правильном порядке. Дальше тему индексов я развивать не буду, так это очевидно уже сильно за гранью понимания.

Слились вы - дурачки, когда вам предложили объяснить, какая идея лежит в основе дробления этой выборки по частям.

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

anonymous
()
Ответ на: комментарий от anonymous

Знал, что тебя затриггерит

Дальше тему индексов я развивать не буду

Ты её и так не развил. Где бенчи с разными схемами индексирования?

DllMain
()
Ответ на: комментарий от DllMain

Ламер, какие «бенчи», с каким схемами индексирования? Ты же вообще не понимаешь о чем говоришь.

ОПу, которого данные, создать нужно сначала один, сравнить, потом другой и сравнить. Либо использовать хинты если они есть в mysql. А вообще тут нужен частичный по complete составной индекc.

Но в целом я думаю, что ОП идиот и решает проблему которой, нет способом который ничего не решает. Он зачем-то включил slow_log (с клиента он замерить не может или работает в слепую), увидел там этот запрос и захотел (судя по его доводам и подходу) «чтобы в slow_log его не было этой строчки». Ну так выключи slow_log и не будет там этих строк. Де факто его беспокоят именно сообщения в логе, так как другого объяснения, чем он реально озабочен он дать не может.

И тут полудурки с лора подсказывают, как «удалить» эти строчки из slow_log «хитрым» путем: выгружать данные отдельными запросами (блоками).

Ну то есть они конечно тудмают, что они эксперты и решают какую-то задачу, а на самом деле они просто «обманули» slow log, threshold которого сами и же выставили. Идиоты, я иного слова не нахожу.

Мало того, что это вообще непонятно какую задачу решает (ах да - «чтобы не было этих противных строк в slow_log»), так оно еще и замедляет работу в реальности, то есть вместо ускорения - замедление. Отличный результат. В-третьих, оно усложняет то, что усложнять просто не нужно и нельзя (ах да, у быдла же кривизна и бессмысленная усложненность на пустом месте - это мера крутизны и успешности).

В-четвертых, разделить на блоки это простым способом в общем случае нельзя. LIMIT/OFFSET работать не будет, так как таблица двигается. Можно брать N после некоторого PK, но вероятно PK там нет. Можно брать N после некоторой даты, но чтобы отрезать эти куски (а следующий кусок запрашивать с макс даты прошлого куска), нужно иметь упорядоченный полный набор, то есть его придется всё равно опять весь построить. Это все в данном случае неэффективно, глупо, бессмысленно и ненужно.

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

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

anonymous
()
Ответ на: комментарий от anonymous

Ламер, какие «бенчи», с каким схемами индексирования?

Похоже у нас появился царь реляционок ). Всю твою простыню не читал, вопрос тот же: где бэнчи?

DllMain
()
Ответ на: комментарий от anonymous

Ах, да, чтобы его посортировать (а иначе на куски ты его делить не сможешь) нужна еще и память.

anonymous
()
Ответ на: комментарий от DllMain

вопрос тот же: где бэнчи?

Ты настолько даун, что чтобы отличить одиночный индекс от составного тебе нужны некие «бенчи»?

Или чтобы понять, что сумма этих запросов выгружающих блоки будет съедать больше ресурсов чем построение одного результата? Тебе нужны «бенчи».

Или ты не понимаешь, что если ты поделил запрос на части, то ты не сделал его быстрее, а просто спрятал (от кого??) из slow log? Ну то есть нельзя 4 уменьшить превратив его в 2 + 2 (и еще +1).

Тогда тут тебе, быдлятина, не «бенчи» нужны, а работа дворником.

anonymous
()
Ответ на: комментарий от anonymous

чтобы не было этих противных строк в slow_log не только Включал errors.log - у меня там куча строк вида:

2020-02-01 22:40:06 193 [Warning] Aborted connection 193 to db: 'tgadmin_test' user: 'root' host: 'localhost' (Got an error reading communication packets)

И в админке на джанге постоянно вот это вылазит:

(2006, 'MySQL server has gone away')

Или ты не понимаешь, что если ты поделил запрос на части, то ты не сделал его быстрее, а просто спрятал (от кого??) из slow log? Ну то есть нельзя 4 уменьшить превратив его в 2 + 2 (и еще +1).

Уже понял. Предупреждения исчезли - проблема осталась

Qwentor ★★★★★
() автор топика
Ответ на: комментарий от DllMain

Видимо, ты дурачок о БД вообще ни малейшего представления не имеешь, раз у тебя заело слово «бенчи».

anonymous
()
Ответ на: комментарий от Qwentor

Это я не на тебя наезжал.

Я не работал с mysql с 2009 года.

У меня к тебе вопрос. Почему когда ты создал два индекса (по complete и по dt), планировщик выбрал индекс по complete? Тот который по dt, он вообще нормальный? В mysql кстати хинты по-моему есть.

B еще вопросы. Как в mysql для dt < '2020-02-01 17:46:13.893177' будет работать приведение типов? Тут точно всё в порядке? Ну это на всякий случай.

Для

WHERE completed = 0 AND dt < '2020-02-01 17:46:13.893177';

Посмотри можно ли в mysql partial composite index (это один индекс) по полям completed(с условием = 0), dt. Другие индексы удали (они будут тебе тормозить вставку). Через explain убедись, что он его «подхватывает».

проблема

в изначальном сообщении ты не говорил, что есть какая-то проблема. это всё меняет.

это уже надо у mysqlщиков спрашивать: может быть там какой-то таймаут есть?

проблема

но вообще, если ты уже выгружаешь не «большим» набором, а множеством кусков, но некая проблема всё равно присутствует… то это говорит о том, что твоя БД не может обработать серию обыкновенных запросов? что-то не клеится! Так и select 1; скоро будет БД ронять…

anonymous
()
Ответ на: комментарий от no-such-file

PK в innodb есть всегда, товарищ иксперт. Я говорил о явном PK, объявленном в схеме таблицы у ОПа, товарищ мудак.

Ну раз он говорит, что PK у него есть, и раз вдруг выяснилось, что запрос не выполняется и соединение рвется (это ооооочень странно для такой небольшой выборки ну да ладно), то пусть попробует забирать кусками и границы выставлять по PK. Правда как он говорит, соединение всё равно рвется, даже на меньших выборках, что намекает на то, что с сервером, вероятно, что-то не то в принципе.

anonymous
()
Ответ на: комментарий от Qwentor

но не помогло

ИМХО у тебя с самой базой что-то не то. Памяти ей отсыпал? Там из коробки вроде бы очень скромно даётся.

no-such-file ★★★★★
()
Ответ на: комментарий от Qwentor

2020-02-01 22:40:06 193 [Warning] Aborted connection 193 to db: ‘tgadmin_test’ user: ‘root’ host: ‘localhost’ (Got an error reading communication packets)

Стоп-стоп - это лог на стороне mysql?

anonymous
()
Ответ на: комментарий от anonymous

Хмм..
https://blog.maddevs.io/got-an-error-reading-communication-packets-here-is-ho...

вот контейнеров у меня несколько запущено, не только докер, но и lxc.

Правда MySQL не в контейнере.

По незакрытию соединений тоже читал, вчера везде проставил закрытие, но все равно появляются ошибки

Qwentor ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.