Почему этот MYSQL запрос использует подзапросы так медленно? - PullRequest
0 голосов
/ 13 марта 2020

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

SELECT 
    peers.ip, 
    peers.datetime AS first_seen, 
    (SELECT MAX(datetime) FROM uptimes WHERE ip = peers.ip) AS last_seen,
    peers.user_agent, 
    (SELECT COUNT(id) FROM uptimes WHERE ip = peers.ip) AS total_uptime,
    (SELECT COUNT(id) FROM tries WHERE datetime >= peers.datetime) AS tries,
    ((SELECT total_uptime) / (SELECT tries)) AS average_uptime
    FROM peers, uptimes
    WHERE peers.ip=uptimes.ip
    GROUP BY peers.ip
    HAVING total_uptime > 10
    ORDER BY average_uptime DESC
    LIMIT 100;

Ответ API выглядит следующим образом:

[
  {
    "ip": "200.0.0.24",
    "first_seen": "1584106440008",
    "last_seen": "1584116482293",
    "user_agent": "Grin++ 0.7.5",
    "total_uptime": 40,
    "tries": 40,
    "average_uptime": 1
  },
  ...
]

И ниже приведены таблицы, используемые в запросе:

CREATE TABLE `peers` (
  `id` int NOT NULL AUTO_INCREMENT,
  `ip` varchar(45) NOT NULL,
  `datetime` varchar(45) NOT NULL,
  `user_agent` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`),
  UNIQUE KEY `ip_UNIQUE` (`ip`)
) ENGINE=InnoDB AUTO_INCREMENT=772 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

CREATE TABLE `uptimes` (
  `id` int NOT NULL AUTO_INCREMENT,
  `ip` varchar(45) NOT NULL,
  `user_agent` varchar(45) DEFAULT NULL,
  `datetime` varchar(45) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3567 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

CREATE TABLE `tries` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `status` VARCHAR(45) NOT NULL,
  `datetime` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `id_UNIQUE` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3567 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

Ответы [ 2 ]

1 голос
/ 14 марта 2020
  1. Для таблицы uptimes предназначен ли ваш уникальный ключ для столбца ip, а не id? Наличие индексов для атрибута фильтра ip может значительно увеличить скорость второго подзапроса. Кроме того, указание уникальных ограничений / индексов для первичного ключа является излишним.
  2. 3-й и 4-й подзапросы будут дорогостоящими, так как вы получаете доступ ко всей таблице tries для каждого узла. Индекс B-дерева на tries.datetime может немного помочь, но, вероятно, не сильно.
  3. Не связан с производительностью, но то, что мне кажется странным, это то, что tries не организован ip. Просто подумал, что упомяну это на всякий случай, это на самом деле проблема.
0 голосов
/ 14 марта 2020

Причины медленного, A) каждая таблица имеет PRIMARY KEY, а следующая строка является избыточным ключом, который следует удалить. Б) Если ваш тип данных datetime был изменен с VARCHAR на DATETIME, столбец будет меньше для хранения, быстрее для управления и более полезным, отображая дату и время, и вы сможете выбрать Datetime BETWEEN startdate AND enddate. C) Вероятно, использование CHARSET utf8mb4 увеличивает время, необходимое для обработки. Если это ТРЕБОВАНИЕ, вы ничего не можете сделать с этой деталью, кроме настройки конфигурации MySQL. Посмотрите мой профиль, сетевой профиль для бесплатных загружаемых служебных скриптов, чтобы помочь с настройкой производительности.

...