【问题标题】:MySQL Composite Index Question - Performance issueMySQL 复合索引问题 - 性能问题
【发布时间】:2020-08-20 18:34:15
【问题描述】:

在此处发布问题之前,我对索引进行了一些研究。到目前为止,我相信我已经正确地做到了这一点,但由于某种原因,返回大约 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

返回这个

这看起来像是在使用索引“SearchIndex”。但是,我不明白为什么要花 10 秒来处理 2k 行

【问题讨论】:

  • DECIMAL 次?
  • 为什么没有PRIMARY KEY

标签: mysql sql date query-optimization where-clause


【解决方案1】:

对于这个查询:

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 秒。 (+ 10.360 秒网络)

查询在数据库中运行得很快。瓶颈是网络,也就是将 2000 多行从数据库返回到客户端所需的时间。从数据库的角度来看,没有什么可以做的。加快您的网络速度,或者尽可能切换到本地数据库。

附带说明:select * 不利于性能;您应该尝试减少查询返回的列数(这也可能会减少需要通过网络传输的数量)。

【讨论】:

  • 我想我同意你的看法。 “responseText”列包含一些大量的字符串数据。当我选择除“responseText”之外的所有列时,它工作得很好,并在一秒钟内返回了数据。应该是网络。谢谢!
  • 它仅使用该索引中的domainId。 (注意 key_len = 53 = 50+2+1)。
【解决方案2】:

您没有主键。 您只有一个唯一索引。

【讨论】:

  • 这并不能解释缓慢。另请注意,唯一索引可以为 NULL,因此不能提升为 PK。
【解决方案3】:

如果您在结果中不需要那个庞大的 responseText 列,请不要包含它。这可能会显着加快查询速度。

(这是因为大列被“记录外”存储,因此如果表很大,则需要额外的磁盘读取。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-15
    • 2012-01-31
    • 2018-12-20
    • 2017-02-28
    • 1970-01-01
    • 2018-08-25
    • 1970-01-01
    相关资源
    最近更新 更多