LINUX.ORG.RU

Про качество оптимизации

 , ,


1

2

Есть безобидный запрос

SELECT DISTINCT messages.contact_id FROM messages WHERE messages.failed != true AND messages.timestamp_sent > какое-то значение
Обычно он выполняется 2 секунды, но иногда - все 10 минут. Как выяснилось, при некоторых значениях фазы луны^W^W timestamp_sent оптимизатор решает, что использовать очевидный индекс timestamp_sent ни к чему, и использует contact_id, который вроде бы никак ускорить выборку не может. А если использовать USE INDEX - вообще никакой не использует. И только с костыльным FORCE INDEX понимает, достигая требуемых 2 секунд.

Еще я недавно столкнулся с тем, что оптимизатор подзапрос, выбирающий общий для всего запроса набор ключей, который в памяти теоретически занимает менее мегабайта, иногда (тоже в зависимости от значения datetime-поля) решает вместо однократного выполнения перед запросом (MATERIALIZED) выполнять для каждой строки выборки (DEPENDENT SUBQUERY), увеличивая время выполнения запроса с секунд или минут до более суток.

Главный вопрос: оптимизация MySQL/MariaDB настолько говно, или я чего-то не понимаю? Если первое, то есть ли смысл валить на PostgreSQL?

★★

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

просто статистика кривая, а с постгре ты в принципе в случае чего индекс не зафорсишь

anonymous
()

1. Сделать составной индекс для (failed,timestamp_sent)

2. В запросе вместо messages.failed != true писать messages.failed = false

Получить профит!

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

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

2. Само по себе приводит только к выбору индекса по failed. Ну, это еще можно понять.

Затрудняюсь представить себе, какая статистика с какой логикой вообще может привести к выбору contact_id в качестве индекса и отказу от использования timestamp_sent при хинтинге.

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

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

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

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

Затрудняюсь представить себе, какая статистика с какой логикой вообще может привести к выбору contact_id

Теоретически это как раз просто. Представьте, что условия по timestamp_sent и failed [почти] ничего не отбрасывают, а DISTINCT contact_id у Вас штук 10, и записей в таблице очень много. В этом случае лучшее решение --- loose index scan по contact_id.

Кстати, вы уверены, что оптимизатор MySQL условия вида "!= false" оценивает так же, как «= true» (не все оптимизаторы СУБД это умеют)?

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

Кстати, вы уверены, что оптимизатор MySQL условия вида "!= false" оценивает так же, как «= true» (не все оптимизаторы СУБД это умеют)?

Именно так. Оптимизатор в MySQL не умеет переводить "!= false" в «= true». Неравенство просто выбрасывает все индексы где задействовано поле failed.

Правило там простое. Любой составной индекс использует все свои части слева на право если они присутствуют в запросе в виде констант. Для последней неконстантной части допустим range. Именно для этого и посоветовал топикстартеру сделать составной индекс. В его случае это будет оптимальным решением.

Ну и в довесок другим комментаторам. Практика создания индексов для частых или «тяжелых» запросов - абсолютно нормальное явление

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