Как оптимизировать запрос mysql, поскольку полный ProcessList показывает отправку данных более 24 часов - PullRequest
0 голосов
/ 27 февраля 2020

У меня есть следующий запрос, который выполняется вечно, и я смотрю, есть ли возможность оптимизировать его. Это выполняется для таблицы, которая содержит в общей сложности 1 406 480 строк данных, но кроме Имени файла и столбца рефлексии, ID и End_Date оба были проиндексированы.

Мой запрос:

INSERT INTO UniqueIDs
    (
    SELECT
        T1.ID
    FROM
        master_table T1
    LEFT JOIN
        master_table T2
    ON
    (
        T1.Ref_No = T2.Ref_No
    AND
        T1.End_Date = T2.End_Date
    AND
        T1.Filename = T2.Filename
    AND
        T1.ID > T2.ID
    )
    WHERE T2.ID IS NULL
    AND
        LENGTH(T1.Ref_No) BETWEEN 5 AND 10
    )
    ;

Объяснить Результаты: enter image description here

Причина отсутствия индексации Ref_No заключается в том, что это текстовый столбец, и поэтому я получаю ошибку BLOB / TEXT при попытке индексировать этот столбец.

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

Спасибо


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

CREATE INDEX I_DELETE_DUPS ON master_table(id, End_Date);

Затем я добавил новый столбец, чтобы показать длину Ref_No, но мне пришлось изменить его на запрос, который Билл упомянул, поскольку моя версия MySQL равна 5.5. Поэтому я запустил его в 3 этапа:

ALTER TABLE master_table
ADD COLUMN Ref_No_length SMALLINT UNSIGNED;

UPDATE master_table SET Ref_No_length = LENGTH(Ref_No);

ALTER TABLE master_table ADD INDEX (Ref_No_length);

Последним шагом было изменение запроса на вставку с предложением where для длины. Это было изменено на:

AND t1.Ref_No_length between 5 and 10;

Затем я запустил этот запрос, и в течение 15 минут в таблицу UniqueIDs были вставлены идентификаторы с идентификатором 280k. Я go изменил свой скрипт вставки, чтобы посмотреть, смогу ли я добавить дополнительные значения к длине, выполнив следующее:

AND t1.Ref_No_length IN (5,6,7,8,9,10,13);

Это должно было привести к значениям, длина которых также была равна 13. Это запрос занимал намного больше времени, точнее 2 часа 50 минут, но дополнительный запрос поиска всех строк длиной 13 дал мне дополнительные 700 000 уникальных идентификаторов.

Я ищу способы оптимизировать запрос с помощью предложение IN, но большое улучшение, когда этот запрос продолжал работать в течение 24 часов. Так что большое спасибо, Билл.

Ответы [ 2 ]

0 голосов
/ 28 февраля 2020

ID и End_Date оба были проиндексированы.

У вас есть PRIMARY KEY(id) и с избыточностью INDEX(id)? PK - это уникальный ключ.

"оба были проиндексированы" - INDEX(a), INDEX(b) не то же самое, что INDEX(a,b) - они используются по-разному. Читайте о «составных» индексах.

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

Я скомпилировал самые быстрые способы выполнения этой задачи здесь: http://mysql.rjweb.org/doc.php/groupwise_max (Есть несколько версий, основанных на MySQL версия и какие проблемы ваш код может / не может терпеть.)

Пожалуйста, укажите SHOW CREATE TABLE. Один важный вопрос: id ПЕРВИЧНЫЙ КЛЮЧ?

Этот составной индекс может быть полезен:

(Filename, End_Date, Ref_No,  -- first, in any order
 ID)    -- last

Это, как отметили другие, вряд ли поможет какой-либо индекс, следовательно, T1 потребуется полное сканирование таблицы:

AND  LENGTH(T1.Ref_No) BETWEEN 5 AND 10

Если Ref_No не может быть больше 191 символа, измените его на VARCHAR, чтобы его можно было использовать в индексе. О, я попросил SHOW CREATE TABLE? Если вы не можете сделать это VARCHAR, то мой рекомендуемый составной индекс

INDEX(Filename, End_Date, ID)
0 голосов
/ 27 февраля 2020

Для JOIN у вас должен быть многостолбцовый индекс на (Ref_No, End_Date, Filename).

Вы можете создать индекс префикса для столбца TEXT следующим образом:

ALTER TABLE master_table ADD INDEX (Ref_No(10));

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

В MySQL 5.7 или более поздних версиях вы можете создать виртуальный столбец, подобный этому, с индексом значений, рассчитанных для виртуального столбца:

ALTER TABLE master_table
  ADD COLUMN Ref_No_length SMALLINT UNSIGNED AS (LENGTH(Ref_No)),
  ADD INDEX (Ref_No_length);

Тогда MySQL распознает, что ваше условие в вашем запросе совпадает с выражением для виртуального столбца, и будет автоматически использовать индекс (исключение: по моему опыту это не так работать с выражениями, используя JSON функции).

Но это не гарантия того, что индекс поможет. Если большинство строк соответствует условию длины от 5 до 10, оптимизатор не будет беспокоиться об индексе. Использование индекса может быть более трудоемким, чем сканирование таблицы.

...