MySQL для более старой MariaDB - медленная производительность - PullRequest
0 голосов
/ 06 ноября 2018

, поэтому у меня проблема с переносом БД с одного веб-сервера на другой. Сервер 1 имеет MySQL версии 5.6, работающую под хостингом cPanel ... Сервер 2 имеет MariaDB версии 5.5 под управлением Webmin / Virtualmin Версия PHP одинакова на обоих ... 5.6

В любом случае, я хотел переместить сайт с сервера 1 на 2. Я экспортировал БД с использованием HeidiSQL, а затем импортировал данные на сервер 2. Данные импортировались нормально, но производительность запросов в 10 раз хуже , Я просмотрел переменные размера буфера и все остальные «ключевые» переменные, и они одинаковы или увеличены на сервере 2. Я попытался изменить механизм хранения с MyIsam на Aria или InnoDB, но результаты были такими же ... Я также оптимизировал всю БД, но опять же не повезло. Индексы одинаковы на обоих серверах.

Затем я решил разместить БД обратно на исходном сервере и просто загрузить файлы с нового .... Я экспортировал новую БД (только данные, использующие вставку игнорировать) и импортировал этот SQL обратно на Сервер 1. Немедленно после импорта оригинальная БД также начала работать медленно ... Если я не использую исходную резервную копию, когда я перемещал БД в первый раз, независимо от того, как я обновляю БД на новые данные, она начинает работать плохо ...

Пример запроса, который теперь выполняется 35 секунд, тогда как раньше он занимал 3 секунды:

select  p.*, pd.ID detailID,
        s.title subject, s.displayTitle, s.memberPanCode,
        s.virtualDelivery,
        CASE WHEN (DATE_ADD(p.releaseDate, INTERVAL 2 WEEK) > NOW()) THEN 1 ELSE 0 END pNew,
        CASE WHEN(s.publicChoice=1) THEN s.memberPanCode ELSE '' END usableSubject,
        CASE WHEN(s.displayTitle=1) THEN s.ID ELSE '0' END subjectID from  sProduct p
    inner join  sProductDetail pd  ON pd.ID_sProduct=p.ID
    left join  sProductDetailWarehouse pdw  ON pdw.ID_sProductDetail=pd.ID
    left join  sProductDetailSubjectPrice pdsp  ON pdsp.ID_sProductDetail=pd.ID
    left join  sSubject s  ON (s.memberPanCode=pdsp.memberPanCode
                          and  s.shownOnSite=1)
    where  (      s.publicChoice=1
              OR  s.defaultSubject=1
              OR  s.memberPanCode=''
              OR  s.memberPanCode IS NULL
           )
      AND  (      (pd.ID > 0  AND  s.displayTitle IS NOT NULL)
              OR  (pd.ID IS NULL  AND  s.displayTitle IS NULL )
              OR  (pd.ID > 0  and  p.ID_sSupplier > 0 )
              OR  (pd.ID > 0  and  pdsp.ID IS NULL )
              OR  (pd.ID > 0 and  s.displayTitle IS NULL )
           )
      AND  (DATE_ADD(NOW(), INTERVAL 1 DAY) > p.showDate)
      AND  (      pdw.stock > 0
              OR  pd.stock > 0
              OR  (p.ID_sSupplier > 0  AND  p.ID_sSupplier <> '3')
           )
      and  p.published IN (1,2)
    GROUP BY  p.ID, s.memberPanCode
    order by  p.showDate desc
    limit  3 

Структуру БД можно найти здесь: https://igabiba.si/images/biba_scheme.sql

Объяснение оператора для новой, более медленной БД: enter image description here

Объяснение оператора для более старой и быстрой БД: enter image description here

Есть идеи, что осталось проверить? Что я могу сделать, чтобы решить эту проблему?

Спасибо за помощь

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

Этот запрос довольно ранговый, эти WHERE условия излишне сложны

Ваш оригинальный запрос (в формате)

   SELECT p.*,
          pd.ID,
          detailID, /** include table alias? */
          s.title subject,
          s.displayTitle,
          s.memberPanCode,
          s.virtualDelivery,
          (p.releaseDate < NOW() - INTERVAL 2 WEEK) pNew /** Booleans are resolve to 1/0 in MySQL */
          CASE WHEN s.publicChoice = 1 THEN s.memberPanCode ELSE '' END usableSubject,
          CASE WHEN s.displayTitle = 1 THEN s.ID ELSE '0' END subjectID 

     FROM sProduct p

     JOIN sProductDetail pd 
       ON pd.ID_sProduct = p.ID

LEFT JOIN sProductDetailWarehouse pdw 
       ON pdw.ID_sProductDetail = pd.ID

LEFT JOIN sProductDetailSubjectPrice pdsp 
       ON pdsp.ID_sProductDetail = pd.ID 

LEFT JOIN sSubject s 
       ON s.memberPanCode = pdsp.memberPanCode 
      AND s.shownOnSite=1

    WHERE (s.publicChoice=1 OR s.defaultSubject=1 OR s.memberPanCode='' OR s.memberPanCode IS NULL)  
      AND /** (
            (pd.ID > 0 AND s.displayTitle IS NOT NULL)
         OR (pd.ID IS NULL AND s.displayTitle IS NULL) 
         OR (pd.ID > 0 AND p.ID_sSupplier > 0) 
         OR (pd.ID > 0 AND pdsp.ID IS NULL) 
         OR (pd.ID > 0 AND s.displayTitle IS NULL)
          ) */ pd.ID > 0 /** see below */
      AND p.showDate < NOW() + INTERVAL 1 DAY 
      AND (pdw.stock > 0 OR pd.stock > 0 OR (p.ID_sSupplier > 0 AND p.ID_sSupplier <> '3'))  
      AND p.published IN (1,2)

 GROUP BY p.ID, s.memberPanCode 
 ORDER BY p.showDate DESC 
    LIMIT 3

Давайте начнем с этого условия

  AND (
         /** This with the last subcondition is just pd.ID > 0 */
         (pd.ID > 0 AND s.displayTitle IS NOT NULL)  

         /** This is impossible due to your INNER JOIN */
      OR (pd.ID IS NULL AND s.displayTitle IS NULL)

      OR (pd.ID > 0 AND p.ID_sSupplier > 0) 
      OR (pd.ID > 0 AND pdsp.ID IS NULL) 

         /** This with the first subcondition is just pd.ID > 0 */
      OR (pd.ID > 0 AND s.displayTitle IS NULL)
       ) 

Все это условие разрешается до pd.ID > 0, что всегда ИСТИНА, если вы вручную не добавили продукт с идентификатором 0

Я подозреваю, что (p.ID_sSupplier > 0 AND p.ID_sSupplier <> '3') может стать просто p.ID_sSupplier <> 3 по той же причине

Это первое условие, кажется, тоже супер включительно

WHERE (
      s.publicChoice=1 
     OR s.defaultSubject=1 
     OR s.memberPanCode='' 
     OR s.memberPanCode IS NULL
      )  
   ...

Что заставляет меня задаться вопросом, каких строк вы на самом деле пытаетесь избежать с этим условием?

Это предложение GROUP BY также вызывает беспокойство, так как у вас не выбраны агрегированные столбцы ... многие ваши последние столбцы будут выбраны произвольно

Чего вы на самом деле пытаетесь достичь с помощью этого запроса?

Стоит помнить, что условия OR разрешаются медленнее, чем условия AND при использовании запросов

0 голосов
/ 12 ноября 2018

Планы выполнения (показанные в выходных данных EXPLAIN) отличаются. Таким образом, мы ожидаем, что различные характеристики производительности.

Как отметил @RickJames в комментарии, в целевой среде, по-видимому, отсутствуют индексы .

Вопрос гласит: «Индексы одинаковы на обоих серверах».

Но предоставленная информация приводит нас к выводу, что индексы не одинаковы.

Мы видим некоторые индексы, на которые ссылаются в выходных данных первого EXPLAIN. И эти имена индексов не найдены в выходных данных второго EXPLAIN. Эти имена индексов также не найдены в сценарии определения схемы.


В: Почему некоторые индексы (о которых сообщалось в первом EXPLAIN, отсутствуют) из определения схемы?

В: Был ли изменен вывод из файла mysqldump для миграции, чтобы удалить некоторые определения индекса?

Q: Был ли использован какой-либо инструмент, кроме mysqldump, для извлечения определения схемы для миграции, и индексы были опущены?

В: Некоторые операторы «создания индекса» не выполнялись в целевой среде? (Возможно из-за ограничений на размеры столбцов в индексах?)


Или, может быть, у меня все наоборот, может быть есть индексы, которые были добавлены в цель, которых не было в источнике.

0 голосов
/ 08 ноября 2018

Насколько большие таблицы? InnoDB теперь делает FULLTEXT. MyISAM осиротел. Я согласен не использовать что-то старое, как 5.5. MariaDB имеет 10,0, 10,1, 10,2, 10,3. MySQL имеет 5,6, 5,7, 8,0. И в большинстве из них было проделано много работы по оптимизации. Возвращаясь к версии 5.5, вы, вероятно, потеряли некоторые функции оптимизации. Увы, я не заметил, что именно потеряно.

ORs смертельно опасны для производительности. Они по существу препятствуют использованию индексов. Я не вижу очевидного способа перестановки вещей - поскольку ORs в нескольких таблицах.

Вот несколько составных, покрывающих индексов, которые могут помочь:

pd:   INDEX(ID_sProduct, ID, stock)  -- perhaps this order is best
pdw:  INDEX(ID_sProductDetail, stock)  -- in this  order
pdsp: INDEX(ID_sProductDetail, memberPanCode, ID)  -- in this order
s:    INDEX(memberPanCode, shownOnSite)  -- in either order

Также добавьте

p:  INDEX(showDate, published, ID, ID_sSupplier) -- in this order

и реструктурируйте запрос, вытянув p.* из основного потока. В настоящее время громоздкие p. * Перемещаются через соединения и т. Д., А затем сокращаются до 3 строк. Путем реструктуризации мы можем найти, какие 3 строки сначала , , а затем извлекают все данные:

SELECT p2.*, etc.
       p2.releaseDate > NOW() - INTERVAL 2 WEEK  AS pNew,
       etc.
    FROM (
        SELECT  toss p.*, add p.ID, keep other columns
            FROM ...
            LEFT JOIN ...
            ORDER BY...
            LIMIT 3
         ) AS x
    JOIN sProduct AS p2  ON x.ID = p2.ID
    ORDER BY p2.showDate desc

Этот новый индекс «покрывает» тем, что все значения p в подзапросе находятся в индексе. Я заметил, что releaseDate можно было бы опустить и поднять со вторым использованием sProduct.

Я ставлю sShowDate первым в индексе, предполагая, что он хотя бы выполняет некоторую фильтрацию (p.showDate < NOW + INTERVAL 1 DAY).

Комбинация GROUP BY и ORDER BY требует одного или двух файловых сортировок; они не могут быть устранены. Что я сделал, так это минимизировал их стоимость, сделав их менее громоздкими.

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