Разница между временем выполнения локального запроса MySQL и производственным сервером - PullRequest
0 голосов
/ 02 декабря 2018

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

Итак, проблема в том, что у меня есть несколько запросов, которые используют много JOIN s и некоторые из таблиц имеют пару тысяч записей, в то время как некоторые другие имеют около 200-300 тысяч записей.У меня был опыт замедления работы сайта, и мне приходилось оптимизировать некоторые запросы.

Дело в том, что в этом случае на моем локальном компьютере конкретный раздел, использующий эти запросы, занимает около 2,5 секунд для загрузки с включенным регулированием сети какОбычный Wi-Fi.При хорошем Wi-Fi загрузка занимает около 1,3 секунды.

На моем производственном сервере, который является виртуальной машиной в DigitalOcean, требуется примерно 5 минут! для загрузки точно такого же контента с точно таким же запросом.Теперь я не эксперт, но мой компьютер не работает в 120 раз быстрее, чем производственный сервер DigitalOcean.

Мой ноутбук имеет следующие характеристики: Intel Core i7-6700 HQ, 16 ГБ оперативной памяти DDR4 и серверработающий на жестком диске со скоростью 5400 об / мин, его нет даже на моем SSD-накопителе, а только там, где используется движок MySQL.

Рабочий сервер изначально был базовым экземпляром DO с 1 ГБ ОЗУ и 1 VCPU.Я подумал, что это, вероятно, нуждается в некотором повышении, поэтому я временно обновил его, чтобы иметь 2VCPU и 2 ГБ оперативной памяти, но это не имело никакого значения.Другие разделы загружаются невероятно быстро, за исключением одного, который использует много объединений.

Теперь я не эксперт, но мой компьютер не в 120 раз быстрее сервера, и он также работает кучадругие процессы.У меня есть GeForce 1070M, но я не думаю, что это влияет на производительность mysql.

Я попытался разделить запрос на как можно меньше JOIN s, а затем выполнить несколько простых запросов, чтобы добавить дополнительныеинформация в мой информационный массив, но потом у меня возникла другая проблема.С такой логикой даже на моем компьютере он завис на 4-5 секунд, а затем неожиданно загрузил контент.

Ниже приведены скриншоты вкладки сети Chrome, показывающие разницу во времени.Как видите, все остальное загружается невероятно быстро, за исключением начальной загрузки.Я почти уверен, что это проблема MySQL, но разница ошеломляет.Я подумываю о попытке загрузить сайт на 16 ГБ экземпляра памяти с 6VCPU на DigitalOcean, чтобы увидеть, связано ли это с памятью / процессором, но я не уверен, что мой клиент хотел бы платить 80 долларов США в месяц или больше за такую ​​виртуальную машину.

Одним из возможных решений, о котором я думал, было разделение таблиц Localidades и Asentamientos (в каждой из них около 200-300 тыс. Записей) на 32 таблицы меньшего размера, по одной для каждого штата Мексики, и имеющиеспециальная функция для каждого состояния для ссылки на другую таблицу, но я не думаю, что это будет ни масштабируемой, ни хорошей практикой.

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

Myлокальный компьютер имеет:

  • Windows 10 1803
  • Apache / 2.4.25 (Win64)
  • MySQL 5.7.23

Myрабочий сервер имеет:

  • Ubuntu 18.04.1 LTS
  • Apache / 2.4.29 (Ubuntu)
  • 5.7.24-0ubuntu0.18.04.1

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

Сгенерированный запрос выглядит следующим образом:

SELECT 
    `Propiedades`.*,
    `Propiedades`.`directorio` AS `main_dir`,
    DATEDIFF(Propiedades.fecha_finalizacion,
            '2018-12-02 11:11:49') AS quedan,
    `OperacionesPorPropiedad`.*,
    `Operaciones`.`nombre_operacion`,
    `Operaciones`.`nombre_operacion_slug`,
    `TiposDePropiedades`.*,
    `FotografiasPorPropiedad`.*,
    `Empresas`.`nombre_empresa`,
    `Estados`.*,
    `Municipios`.*,
    `Localidades`.*,
    `Asentamientos`.*,
    `Clientes`.`nombres`,
    `Clientes`.`apellidos`,
    `Clientes`.`email`,
    `TiposDeClientes`.*
FROM
    `Propiedades`
        JOIN
    `OperacionesPorPropiedad` ON `OperacionesPorPropiedad`.`id_propiedad` = `Propiedades`.`id_propiedad`
        JOIN
    `Operaciones` ON (`Operaciones`.`id_operacion` = `OperacionesPorPropiedad`.`id_operacion`
        AND `OperacionesPorPropiedad`.`id_propiedad` = Propiedades.id_propiedad)
        JOIN
    `TiposDePropiedades` ON `TiposDePropiedades`.`id_tipo` = `Propiedades`.`id_tipo`
        JOIN
    `FotografiasPorPropiedad` ON (`FotografiasPorPropiedad`.`id_propiedad` = `Propiedades`.`id_propiedad`
        AND `FotografiasPorPropiedad`.`orden` = 1)
        JOIN
    `Empresas` ON `Empresas`.`id_empresa` = `Propiedades`.`id_empresa`
        JOIN
    `Estados` ON `Estados`.`id_estado` = `Propiedades`.`id_estado`
        LEFT OUTER JOIN
    `Municipios` ON `Municipios`.`id_municipio` = `Propiedades`.`id_municipio`
        LEFT OUTER JOIN
    `Localidades` ON `Localidades`.`id_localidad` = `Propiedades`.`id_localidad`
        LEFT OUTER JOIN
    `Asentamientos` ON `Asentamientos`.`id_asentamiento` = `Propiedades`.`id_asentamiento`
        JOIN
    `Clientes` ON `Clientes`.`id_cliente` = `Empresas`.`id_cliente`
        JOIN
    `TiposDeClientes` ON (`Clientes`.`id_tipo_cliente` = `TiposDeClientes`.`id_tipo_cliente`
        AND `Clientes`.`id_cliente` = `Empresas`.`id_cliente`)
WHERE
    `Propiedades`.`id_estatus_propiedad` = 1
GROUP BY `Propiedades`.`id_propiedad`
ORDER BY FIELD(`Propiedades`.`destacada`, '1', '0') , FIELD(`Clientes`.`id_tipo_cliente`, 1, 2, 3) , RAND()
LIMIT 24

Query cost

This is my local benchmark with throttling enabled and cache disabled

This is my remote benchmark with cache disabled

Ответы [ 2 ]

0 голосов
/ 02 декабря 2018

Это даст вам разумные 24 строки?Или вы зависите от фильтрации из других таблиц?

    WHERE  P.`id_estatus_propiedad` = 1
    ORDER BY  FIELD(P.`destacada`, '1', '0') ,
              FIELD(C.`id_tipo_cliente`, 1, 2, 3) ,
              RAND()
    LIMIT  24

Если это так, то подумайте о следующем:

Ваш текущий запрос состоит из полных строк из lot таблиц, затем перетасовывая их и, наконец, получая только 24.

Лучший способ - выяснить, какие 24, затем перейти к деталям:

SELECT lots-of-stuff
    FROM ( SELECT id_propiedad
               FROM Propiedades AS P1
               JOIN ...   -- as few as needed to get to Clientes
               JOIN  `Clientes` AS C1  ON C1.`id_cliente` = Em.`id_cliente`
               WHERE  P1.`id_estatus_propiedad` = 1
               ORDER BY  FIELD(P1.`destacada`, '1', '0') ,
                         FIELD(C1.`id_tipo_cliente`, 1, 2, 3) ,
                         RAND()
               LIMIT  24
         ) AS x
    JOIN  `Propiedades` AS P  ON P.id_propiedad = x.id_propiedad
    JOIN  `OperacionesPorPropiedad` AS OP  ON OP.`id_propiedad` = P.`id_propiedad`
    JOIN  `Operaciones` AS O  ON (O.`id_operacion` = OP.`id_operacion` ...
    ...
    -- no WHERE, GROUP BY, or LIMIT, but repeat the ORDER BY:
    ORDER BY  FIELD(P.`destacada`, '1', '0') ,
              FIELD(C.`id_tipo_cliente`, 1, 2, 3) , RAND()

Назадна вопрос о разнице в производительности ...

  • Ваша персональная машина имеет большее значение для innodb_buffer_pool_size, чем крошечная виртуальная машина в облаке?
  • Вы выбираете все столбцы измножество строк из дюжины таблиц.
  • Вы (в настоящее время) собираете массу потенциальных выходных строк сначала, затем используете GROUP BY для устранения дублирования и, наконец, LIMITing длявсего 24. Размер временной таблицы, вероятно, огромен.(синдром «inflate-deflate» JOIN плюс GROUP BY.
  • Возможно, в некоторых из этих списков столбцов * есть столбцы TEXT; это усугубляет проблему с временной таблицей.

Они в совокупности вызывают быструю / медленную производительность. Мое предложение, если оно жизнеспособно, устраняет большую его часть.

Также FotografiasPorPropiedad необходимо INDEX(id_propiedad, orden) (в любом порядке).

0 голосов
/ 02 декабря 2018

Извините, что потратили ваше время, ребята ... Это была ошибка новичка, в которой я не читал сообщения об ошибках при импорте базы данных.

Когда я генерировал mysqldump, некоторые имена таблиц были сгенерированы неправильнос только строчными буквами, что приводило к ошибке при импорте.

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

Я исправил свой файл SQL и снова создал базу данных, и она работала как чудо.Извините, что потратили ваше время, ребята.

PS: Я фактически увеличил сервер до 16 ГБ ОЗУ и 6 ВЦП, и это не имело никакого значения.

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