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

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

Вот схема таблицы

CREATE TABLE `tblCheck` (
    `id` VARCHAR(50) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
    `token` VARCHAR(50) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
    `domainId` VARCHAR(50) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
    `time` DATETIME NULL DEFAULT NULL,
    `responseCode` INT(11) NULL DEFAULT NULL,
    `totalTime` DECIMAL(10,2) NULL DEFAULT NULL,
    `namelookupTime` INT(11) NULL DEFAULT NULL,
    `connectTime` INT(11) NULL DEFAULT NULL,
    `pretransferTime` INT(11) NULL DEFAULT NULL,
    `startTransferTime` INT(11) NULL DEFAULT NULL,
    `redirectTime` INT(11) NULL DEFAULT NULL,
    `appconnectTime` INT(11) NULL DEFAULT NULL,
    `responseText` TEXT(65535) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
    `agentId` VARCHAR(50) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
    `isHealthy` CHAR(50) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
    `ftp_connect_time` DECIMAL(10,4) NULL DEFAULT NULL,
    `ftp_login_time` DECIMAL(10,4) NULL DEFAULT NULL,
    `ftp_change_mode_time` DECIMAL(10,4) NULL DEFAULT NULL,
    `ftp_list_time` DECIMAL(10,4) NULL DEFAULT NULL,
    `syntheticToken` VARCHAR(50) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
    UNIQUE INDEX `id` (`id`) USING BTREE,
    INDEX `domainId` (`domainId`) USING BTREE,
    INDEX `deleteTime` (`time`) USING BTREE,
    INDEX `SearchIndex` (`domainId`, `time`, `agentId`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
ROW_FORMAT=COMPACT
;

Запрос

SELECT *
FROM `tblCheck`
WHERE (`time` BETWEEN '2020-05-04 22:15:04' AND '2020-05-05 22:15:04')
  AND `domainId` = '03d4c1ce-8b13-11ea-abf5-124e96b5f417'
  AND `agentId` != '145a-f6bb-11e8-983f-1231322cbdb6'
ORDER BY `time` DESC
;
/* Affected rows: 0  Found rows: 2,418  Warnings: 0  Duration for 1 query: 0.109 sec. (+ 10.360 sec. network) */

Он вернул 2418 строк, но занял почти 10 секунд.

Запуск с EXPLAIN

EXPLAIN SELECT *
FROM `tblCheck`
WHERE (`time` BETWEEN '2020-05-04 22:15:04' AND '2020-05-05 22:15:04')
  AND `domainId` = '03d4c1ce-8b13-11ea-abf5-124e96b5f417'
  AND `agentId` != '145a-f6bb-11e8-983f-1231322cbdb6'
ORDER BY `time` DESC

Возвращает это

enter image description here

Похоже, он использует индекс «SearchIndex». Однако я не могу понять, зачем обрабатывать 10 секунд для 2k строк

Ответы [ 3 ]

3 голосов
/ 06 мая 2020

Для этого запроса:

SELECT *
FROM `tblCheck`
WHERE 
    `time` BETWEEN '2020-05-04 22:15:04' AND '2020-05-05 22:15:04'
    AND `domainId` = '03d4c1ce-8b13-11ea-abf5-124e96b5f417' 
    AND `agentId` != '145a-f6bb-11e8-983f-1231322cbdb6'
ORDER BY `time` DESC

Правильный индекс будет: (domainId, agentId, time) или (domainId, time, agentId). У вас есть второй индекс, и план запроса показывает, что MySQL с радостью его использует.

Глядя на сводку объяснения, вы можете увидеть:

Продолжительность для 1 запрос: 0.109 se c. (+ 10.360 se c. Network)

Запрос в базе данных выполняется быстро. Узким местом является сеть, то есть время, необходимое для возврата более 2000 строк из базы данных клиенту. С точки зрения базы данных сделать немногое. Ускорьте работу сети или переключитесь на локальную базу данных, если можете.

В качестве примечания: select * не способствует производительности; вам следует попытаться уменьшить количество столбцов, возвращаемых запросом (это также может уменьшить количество, которое необходимо передать по сети).

1 голос
/ 06 мая 2020

У вас нет первичного ключа. У вас есть только УНИКАЛЬНЫЙ ИНДЕКС.

0 голосов
/ 06 мая 2020

Если вам не нужен громоздкий столбец responseText в результатах, не включайте его. Это может значительно ускорить запрос.

(Это связано с тем, что большие столбцы хранятся «вне записи», что требует дополнительного чтения с диска, если таблица огромна.)

...