Неожиданно медленный MYSQL-запрос по вновь проиндексированным данным - PullRequest
0 голосов
/ 11 октября 2018

У меня следующий запрос:

SELECT DISTINCT
        CONCAT(COALESCE(location.google_id, ''),
                '-',
                COALESCE(locationData.resolution, ''),
                '-',
                COALESCE(locationData.time_slice, '')) AS google_id
    FROM
        LocationData AS locationData
            JOIN
        Location AS location ON location.id = locationData.location_id

    WHERE
        location.company_google_id = 5679037876797440
            AND location.google_id IN (4679055472328704, 6414382784315392, 5747093579759616)
            AND locationData.resolution = 8
            AND locationData.time_slice >= ((SELECT max(s.time_slice) FROM LocationData as s WHERE s.location_id = location.id ORDER BY s.time_slice ASC) - 255)
            AND location.active = TRUE
    ORDER BY location.google_id ASC , locationData.time_slice ASC
    LIMIT 0 , 101

У меня есть индексы для всех столбцов в предложениях WHERE и ORDER BY, и я добавил составной индекс для (LocationData.time_slice, LocationData.location_id)

Выполнение объяснения дает (что дало некоторые проблемы с форматированием здесь, так что, надеюсь, это хорошо видно):

   id | select_type        | table        | type  | possible_keys                              | key                |  key_len | ref                | rows | Extra
    1 | PRIMARY            | location     | range | PRIMARY,google_id_UNIQUE                   | google_id_UNIQUE   | 8        | NULL               |    3 | Using index condition; Using where; Using temporary; Using filesort
    1 | PRIMARY            | locationData | ref   | max_time_slice_idx,max_time_slice_idx_desc | max_time_slice_idx | 5        | index2.location.id |  301 | Using where
    2 | DEPENDENT SUBQUERY | s            | ref   | max_time_slice_idx,max_time_slice_idx_desc | max_time_slice_idx | 5        | index2.location.id |  301 | Using index

Я знаю, что зависимый подзапрос медленный, и я открытк предложениям по схожему поведению, но я вижу, что выполнение этого запроса занимает около 92 секунд, что примерно на 4 порядка отличается от тестовых данных, которые я выполнял до добавления нового составного индекса в производство.

Isесть построение индекса, которое происходит после запуска оператора ALTER?Есть ли способ проверить правильность работы индекса?

Количество строк для двух таблиц:

Производство:

Расположение: 6,814

LocationData: 13,070,888

Тестовые данные:

Location: 626

LocationData: 594,780

Любые мысли илипредложения приветствуются.Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

(Добавление к рекомендации @scaisEdge ...)

WHERE   l.company_google_id = 5679037876797440
    AND l.google_id IN (4679055472328704, 6414382784315392, 5747093579759616)
    AND ld.resolution = 8
    AND ld.time_slice >= t.my_max_time_slice
    AND l.active = TRUE
ORDER BY l.google_id ASC , ld.time_slice ASC

Оптимальные индексы - при условии, что подзапрос должен быть запущен первым.(Это относится к более старым версиям MySQL.)

LocationData: (location_id, time_slice)  -- in this order, for the subquery
locationData: (time_slice, resolution, location_id)  -- for JOIN

Если id - это PRIMARY KEY из location, то здесь дополнительный индекс не требуется.

ДляВ более новых версиях подзапрос может быть материализован и может быть создан подходящий индекс.В этом случае он, вероятно, будет начинаться с location:

location: (company_google_id, active,  -- in either order
           google_id)                  -- last
locationData:  (location_id, time_slice)  -- in this order (for subquery)
locationData:  (location_id, resolution   -- in either order (for JOIN)
                time_slice)               -- last

Нет способа оптимизировать ORDER BY, так как он попадает в две таблицы, или нет способа избежать сортировки.

Предложите добавить все эти индексы, а затем получите EXPLAIN SELECT ..., если вам нужно обсудить это дальше.SHOW CREATE TABLE также было бы удобно.

0 голосов
/ 11 октября 2018

Просто предложение
вы можете избежать подвыбора, используя внутреннее объединение

SELECT DISTINCT
    CONCAT(COALESCE(location.google_id, ''),
            '-',
            COALESCE(locationData.resolution, ''),
            '-',
            COALESCE(locationData.time_slice, '')) AS google_id
FROM LocationData AS locationData
INNER JOIN Location AS location ON location.id = locationData.location_id
INNER JOIN (
            SELECT s.location_id, max(s.time_slice)  -255 my_max_time_slice
            FROM LocationData as s
            GROUP BY s.location_id
        ) t on t.location_id = Location.id

WHERE
    location.company_google_id = 5679037876797440
        AND location.google_id IN (4679055472328704, 6414382784315392, 5747093579759616)
        AND locationData.resolution = 8
        AND locationData.time_slice >= t.my_max_time_slice
        AND location.active = TRUE
ORDER BY location.google_id ASC , locationData.time_slice ASC
LIMIT 0 , 101

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

надеюсь, что это полезно

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...