WedX - журнал о программировании и компьютерных науках

Оптимизация плохо выполняющегося запроса

У меня есть следующий запрос, который работает правильно, однако он работает очень плохо. Я подозреваю, что моя проблема связана с двумя условиями сравнения в инструкции INNER JOIN. Оба поля имеют индекс, но оптимизатор запросов в MySQL их игнорирует. Вот мой запрос:

EDIT: Изменен запрос, чтобы использовать тот, который был предложен Гордоном ниже, так как он сохранил те же результаты, но работает быстрее. Однако инструкция EXPLAIN по-прежнему не работает, и результат показан ниже.

    SELECT a.id
FROM pc a INNER JOIN
     (SELECT correction_value, MAX(seenDate) mxdate
      FROM pc FORCE INDEX (IDX_SEENDATE)
      WHERE seenDate BETWEEN '2017-03-01' AND '2017-04-01'
      GROUP BY correction_value
     ) b
     ON a.correction_value = b.correction_value AND
        a.seenDate = b.mxdate INNER JOIN
     cameras c
     ON c.camera_id = a.camerauid
WHERE c.in_out = 0; 

ОБЪЯСНИТЬ

+----+-------------+------------+------------+-------+-------------------+--------------+---------+----------+---------+----------+---------------------------------------+
| id | select_type | table      | partitions | type  | possible_keys     | key          | key_len | ref      | rows    | filtered | Extra                 |
+----+-------------+------------+------------+-------+-------------------+--------------+---------+----------+---------+----------+---------------------------------------+
|  1 | PRIMARY     | <derived2> | NULL       | ALL   | NULL              | NULL         |    NULL | NULL     | 2414394 |      100 | Using where;              |
|    |             |            |            |       |                   |              |         |          |         |          | Using temporary;              |
|    |             |            |            |       |                   |              |         |          |         |          | Using filesort            |
+----+-------------+------------+------------+-------+-------------------+--------------+---------+----------+---------+----------+---------------------------------------+
|  1 | PRIMARY     | a          | NULL       | ref   | correction_value, | idx_seenDate |       5 | b.mxdate |       1 |      3.8 | Using where               |
|    |             |            |            |       | idx_seenDate,     |              |         |          |         |          |                       |
|    |             |            |            |       | fk_camera_idx     |              |         |          |         |          |                       |
+----+-------------+------------+------------+-------+-------------------+--------------+---------+----------+---------+----------+---------------------------------------+
|  1 | PRIMARY     | c          | NULL       | ALL   | PRIMARY           | NULL         |    NULL | NULL     |      41 |     2.44 | Using where;              |
|    |             |            |            |       |                   |              |         |          |         |          | Using join buffer (Block Nested Loop) |
+----+-------------+------------+------------+-------+-------------------+--------------+---------+----------+---------+----------+---------------------------------------+
|  2 | DERIVED     | pc         | NULL       | range | correction_value, | idx_seenDate |       5 | NULL     | 2414394 |      100 | Using index Condition;        |
|    |             |            |            |       | idx_seenDate      |              |         |          |         |          | Using temporary;              |
|    |             |            |            |       |                   |              |         |          |         |          | Using filesort            |
+----+-------------+------------+------------+-------+-------------------+--------------+---------+----------+---------+----------+---------------------------------------+

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

18.04.2017

  • столбец in_out принадлежит из какой таблицы ?? 18.04.2017
  • @AshutoshSIngh - таблица камер. Но это не имеет значения, потому что проблема производительности заключается в условии внутреннего соединения. 18.04.2017
  • В каком столбце находится in_out? 18.04.2017
  • @GordonLinoff - таблица камер. Обновил вопрос. 18.04.2017
  • Какие индексы у вас есть в таблице ПК и каков порядок столбцов? Также не могли бы вы поместить вывод EXPLAIN. 18.04.2017
  • @Aruna - добавил EXPLAIN к вопросу. 18.04.2017
  • Я удивлен, что никто еще не упомянул об этом, но, как и EXPLAIN, вопросы оптимизации запросов ВСЕГДА требуют операторов CREATE TABLE для ВСЕХ соответствующих таблиц. 18.04.2017
  • @MathLover кажется, проблема в количестве строк, которые необходимо проанализировать в таблице ПК. Несмотря на то, что у вас есть индекс в таблице, ему все равно нужно проанализировать 2,4 миллиона записей. Это в любом случае потребует времени. Есть ли другие фильтры, с помощью которых можно уменьшить количество записей? Кстати, сколько записей у вас на компьютере? также каков порядок столбцов idx_seenDate? 18.04.2017
  • Цифры подразумевают, что все значения correction_value различны. Они? 18.04.2017
  • Какая версия MySQL? 18.04.2017
  • @RickJames - Последнее 19.04.2017
  • @MathLover создайте индекс для camera.camera_id, затем используйте этот индекс с JOIN 19.04.2017

Ответы:


1

Начнем с подзапроса.

SELECT  correction_value,
        MAX(seenDate) mxdate
    FROM  pc
    WHERE  seenDate BETWEEN '2017-03-01' AND '2017-04-01'
    GROUP BY  correction_value

Пожалуйста, запустите это дважды, с

INDEX sc (seenDate, correction_value)
INDEX cs (correction_value, seenDate)

Пожалуйста, форсируйте один индекс, затем другой. В зависимости от того, какую версию MySQL вы используете, один из индексов будет работать лучше, чем другой.

Я думаю, что более поздние версии предпочтут "cs", потому что он может очень эффективно перескакивать через индекс.

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

Поскольку ваша задача, по-видимому, связана с «групповым максимумом», я предлагаю вам посмотреть, есть ли здесь советы по повышению производительности: https://mysql.rjweb.org/doc.php/groupwise_max

18.04.2017

2

Попробуй это

SELECT 
    a.id
FROM pc a
INNER JOIN 
(SELECT  correction_value, MAX(seenDate) mxdate
FROM pc
INNER JOIN cameras ON (cameras.camera_id = pc.camerauid AND cameras.in_out = 0)
WHERE pc.seenDate BETWEEN '2017-03-01' AND '2017-04-01'
GROUP BY correction_value) b ON (a.correction_value = b.correction_value AND a.seenDate = b.mxdate);

используйте индекс в столбце pc.seenDate.

18.04.2017
  • В какой части должен быть индекс? 18.04.2017
  • Я разместил его после присоединения к ПК, однако он все еще неоптимизирован. 18.04.2017
  • Есть ли у вас какое-либо представление о выполнении запроса с объяснением, когда вы выполняете запрос с объяснением, он даст, какая таблица использует какой индекс и какой возможный индекс и т. д. 18.04.2017
  • Возвращаемые результаты теперь отличаются от моего исходного запроса. Проблема связана с размещением предложения WHERE in_out = 0. Это должно быть после группировки. 18.04.2017
  • Я думаю, вы превратили производный подзапрос в коррелированный подзапрос. А это значит, что подзапрос нужно будет запустить 2,4 миллиона раз. Не красивая картинка. 18.04.2017

  • 3

    Я бы начал с написания запроса так:

    SELECT a.id
    FROM pc a INNER JOIN
         (SELECT correction_value, MAX(seenDate) mxdate
          FROM pc
          WHERE seenDate BETWEEN '2017-03-01' AND '2017-04-01'
          GROUP BY correction_value
         ) b
         ON a.correction_value = b.correction_value AND
            a.seenDate = b.mxdate INNER JOIN
         cameras c
         ON c.camera_id = a.camerauid
    WHERE c.in_out = 0;  - don't use single quotes if `in_out` is a number
    

    С этого запроса следует начать с индексов: pc(seendate, correction_value, seendate) и cameras(camera_id, in_out).

    Также могут быть способы переписать запрос, если этого недостаточно.

    18.04.2017
  • Это улучшило производительность и сохранило те же результаты, но EXPLAIN по-прежнему не устраивает. Я обновлю свой вопрос, чтобы использовать этот запрос, а также покажу результат EXPLAIN. 18.04.2017
  • Я также добавил FORCE INDEX, как показано в отредактированном вопросе, что помогло улучшить EXPLAIN. 18.04.2017
  • Небольшое примечание: одна плохая комбинация - это сравнение varchar с числом без кавычек. То есть c.in_out = '0' преобразует '0' в 0 при компиляции запроса. 18.04.2017

  • 4

    СУБД использует выходные данные первого запроса в качестве входных данных для следующего запроса. Итак, если мы посмотрим на производный запрос, он использует фильтр, поэтому мы можем использовать его как первый запрос, затем присоединиться к компьютеру, а затем присоединиться к >камера стол.

    Индексы: упомянутые Гордоном Линофом или pc(id, correct_value, seedate) и camera(camera_id, in_out)

    Окончательный запрос можно переписать следующим образом:

    SELECT a.id 
     --add any other column here, you want to show in the EXPLAINED output
    FROM
    (
        SELECT id, correction_value, MAX(seenDate) mxdate
        FROM pc
        WHERE seenDate BETWEEN '2017-03-01' AND '2017-04-01'
        GROUP BY correction_value
    ) a 
    INNER JOIN pc b
            ON a.correction_value = b.correction_value 
            AND a.seenDate = b.mxdate 
    INNER JOIN cameras c
            ON c.camera_id = a.camerauid
    WHERE c.in_out = 0; 
    
    18.04.2017
  • Это MySQL, поэтому, похоже, он не поддерживает предложение WITH. 18.04.2017

  • 5

    Из вашего вопроса не понятно как индексируются таблицы, но в этом подзапросе

    (SELECT correction_value, MAX(seenDate) mxdate
      FROM pc FORCE INDEX (IDX_SEENDATE)
      WHERE seenDate BETWEEN '2017-03-01' AND '2017-04-01'
      GROUP BY correction_value
     ) b
    

    вы хотите иметь составной индекс для обоих полей seenDate, correction_value:

    CREATE INDEX seenCorr_ndx ON pc (seenDate, correction_value);
    

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

    В конечном итоге вам может понадобиться два составных индекса: один с seenDate первым, один с correction_value первым.

    18.04.2017
  • Небольшое примечание: я думаю, что составной индекс является стандартным термином. 18.04.2017
  • Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: [email protected]