Производительность подзапроса MySQL от 5.0 до 5.1 - PullRequest
2 голосов
/ 28 декабря 2011

Я столкнулся со следующим запросом как часть приложения PHP. Запрос выполняется быстро (менее 1 секунды) в mysql 5.0, но в mysql 5.1 и более поздних занимает около 7 минут.

Возвращенный результат - только 3 строки, но когда я выполняю strace для процесса mysqld на сервере 5.1, когда он выполняет этот запрос, я вижу, как он непрерывно читает данные из таблицы Event в течение нескольких минут ( таблица, содержащая только 7000 строк (по 200 байт на строку) - возможно, перечитывает ее несколько раз.

Итак, вопрос в том, что здесь отличается от того, с чем я сталкиваюсь, и как я могу что-то изменить (или запрос, или, что еще лучше, некоторые настройки MySQL), чтобы он работал под 5.1 так же быстро, как под 5.0.


Ссылочные данные

Запрос на обвинение

SELECT S.Sections_ID, S.Sections_Name, S.Sections_CustomURL
FROM Sections S
WHERE S.Sections_Status = 'Active'
    AND S.Sections_Name!='Hidden'
    AND S.Sections_ParentID = 0
    AND S.Sections_MainSection = 1
    AND (
        SELECT COUNT(MainEvent.Event_ID) AS tot
        FROM Event MainEvent, Event_Section ES
        WHERE ES.EventSection_EventID=MainEvent.Event_ID
            AND ES.EventSection_SectionID=S.Sections_ID
            AND (
                (MainEvent.Event_DateTime > '2011-12-27 18:05:00')
                OR
                    (
                        (
                        SELECT ChildEvent.Event_DateTime
                        FROM Event ChildEvent
                        WHERE ChildEvent.Event_ParentEventID=MainEvent.Event_ID
                        ORDER BY ChildEvent.Event_DateTime DESC LIMIT 1
                        ) > '2011-12-27 18:05:00'
                    )
                )
            AND (MainEvent.Event_ParentEventID=0 or MainEvent.Event_ParentEventID IS NULL) 
            AND (MainEvent.Event_Status='Active' or MainEvent.Event_Status='Canceled') 
            AND MainEvent.Event_ID IN (
                SELECT
                Event_Website.EventWebsite_EventID
                FROM Event_Website 
                WHERE Event_Website.EventWebsite_CompanyID='3'
            )
        )>0
ORDER BY S.Sections_Order ASC, S.Sections_Name ASC

Таблицы, на которые имеются ссылки, имеют следующее количество строк

Разделы: 60
Событие: 7000
Event_Section: 7000
Event_Website: 15000

Ниже приведен EXPLAIN для вышеуказанного запроса с сервера 5.0 (быстрый) и 5.1 (медленный).
Обрезано для места; Надеюсь, я ничего полезного не вырубил.

МЕДЛЕННО (5.1)

+----+---------------+-------------+----------------------------+------------------------+---------+----------------------------------+------+-----------------------------+
| id | table         | type        | possible_keys              | key                    | key_len | ref                              | rows | Extra                       |
+----+---------------+-------------+----------------------------+------------------------+---------+----------------------------------+------+-----------------------------+
|  1 | S             | ref         | Sections_ParentID          | Sections_ParentID      | 5       | const                            |   10 | Using where; Using filesort |
|  2 | MainEvent     | ref_or_null | PRIMARY,Event_DateTime,... | Event_ParentID         | 5       | const                            | 4582 | Using where                 |
|  2 | ES            | ref         | EventSection_EventID       | EventSection_EventID   | 10      | MainEvent.Event_ID,S.Sections_ID |    1 | Using where; Using index    |
|  4 | Event_Website | ref         | EventWebsite_CompanyID     | EventWebsite_CompanyID | 4       | const                            | 4421 | Using where                 |
|  3 | ChildEvent    | index       | Event_ParentID             | Event_DateTime         | 8       | NULL                             |    1 | Using where                 |
+----+---------------+-------------+----------------------------+------------------------+---------+----------------------------------+------+-----------------------------+

FAST (5.0)

+----+---------------+--------+---------------------------+------------------------+---------+-------------------------+------+-----------------------------+
| id | table         | type   | possible_keys             | key                    | key_len | ref                     | rows | Extra                       |
+----+---------------+--------+---------------------------+------------------------+---------+-------------------------+------+-----------------------------+
|  1 | S             | ref    | Sections_ParentID         | Sections_ParentID      | 5       | const                   |   10 | Using where; Using filesort | 
|  2 | ES            | index  | EventSection_EventID      | EventSection_EventID   | 10      | NULL                    | 5610 | Using where; Using index    | 
|  2 | MainEvent     | eq_ref | PRIMARY,Event_DateTime,...| PRIMARY                | 4       | ES.EventSection_EventID |    1 | Using where                 | 
|  4 | Event_Website | ref    | EventWebsite_CompanyID    | EventWebsite_CompanyID | 4       | const                   | 5809 | Using where                 | 
|  3 | ChildEvent    | ref    | Event_ParentID            | Event_ParentID         | 5       | MainEvent.Event_ID      |    4 | Using where; Using filesort | 
+----+---------------+--------+---------------------------+------------------------+---------+-------------------------+------+-----------------------------+

Ответы [ 3 ]

2 голосов
/ 28 декабря 2011

Два предложения по переписыванию:

  1. Изменить IN (SELECT ...) на JOIN запрос.

  2. Изменить (SELECT COUNT(MainEvent.Event_ID) ...) > 0 на EXISTS (SELECT * ...).

1 голос
/ 28 декабря 2011

Я переписал ваш запрос, теперь он использует JOINS. Я не смог проверить этот запрос, потому что вы не подключили схему БД. Пожалуйста, приложите его к вашему вопросу.

SELECT S.Sections_ID, S.Sections_Name, S.Sections_CustomURL
FROM Sections AS S
JOIN Event_Section AS ES ON ES.EventSection_SectionID = S.Sections_ID
JOIN Event AS MainEvent ON ES.EventSection_EventID = MainEvent.Event_ID
JOIN Event_Website ON Event_Website.EventWebsite_EventID = MainEvent.Event_ID
LEFT JOIN Event AS ChildEvent ON ChildEvent.Event_ParentEventID = MainEvent.Event_ID
WHERE S.Sections_Status = 'Active'
    AND S.Sections_Name != 'Hidden'
    AND S.Sections_ParentID = 0
    AND S.Sections_MainSection = 1
    AND (MainEvent.Event_ParentEventID = 0 OR MainEvent.Event_ParentEventID IS NULL)
    AND (MainEvent.Event_DateTime > '2011-12-27 18:05:00' OR ChildEvent.Event_DateTime > '2011-12-27 18:05:00')
    AND (MainEvent.Event_Status='Active' OR MainEvent.Event_Status='Canceled')
    AND Event_Website.EventWebsite_CompanyID = '3'
GROUP BY S.Sections_ID
ORDER BY S.Sections_Order ASC, S.Sections_Name ASC
1 голос
/ 28 декабря 2011

Mysql версии 5.0 и 5.1 (и все более низкие версии) не являются лучшими версиями для использования при работе с (зависимыми) подзапросами таким способом.

Если вы застряли на этих версиях, попробуйте еще разнаписание ваших запросов к объединениям.Также использование

"{columnname} IN (SELECT .... FROM {tablename} WHERE ....)"

часто приводит к снижению производительности.Разделение его на 2 запроса часто происходит быстрее, чем при использовании этого синтаксиса.

Выполните первый запрос, получите все необходимые идентификаторы, затем поместите эти идентификаторы в запросе выше

"{columnname} IN (12, 345, 356, 653 и т. д.) "

MariaDB частично решил эту проблему и является полной заменой MySQL.Если конфиденциальные данные отсутствуют, вы можете отправить мне дамп базы данных, и я сравню приведенный выше запрос с MariaDB

...