首页 > 解决方案 > MySQL btr_search_guess_on_hash 高负载

问题描述

当我遇到一些多源/通道复制从属设备的“优化问题”时,我正在检查“perf top”输出以检测内核函数负载异常。

输出显示在我看来由btr_search_guess_on_hash.

[性能顶部]
1

有人知道高负载btr_search_guess_on_hash是否暗示 mysql 查询被严重优化或索引或丢失了什么?我在寻找什么来优化潜在问题?

先感谢您!

像这样的一些查询对于服务器来说是最常见的:

select table1.attr0, table1.attr1, table1.attr2, table1.attr3, table1.attr4, table1.attr5, table1.attr8, table1.attr6, table1.attr7

from table1

left outer join table2 on table1.attr6=table2.attr0

where table1.attr4='BLABLABLABLA' and table2.attr0=123456789

order by table1.attr7 desc 

limit 1;

显示创建表table1

 CREATE TABLE `table1` (
  `attr0` bigint(20) NOT NULL AUTO_INCREMENT,
  `attr1` datetime DEFAULT NULL,
  `attr2` datetime DEFAULT NULL,
  `attr3` varchar(255) DEFAULT NULL,
  `attr4` varchar(255) DEFAULT NULL,
  `attr5` varchar(255) DEFAULT NULL,
  `attr6` bigint(20) DEFAULT NULL,
  `attr7` int(11) NOT NULL,
  `attr8` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`attr0`),
  KEY `FK2` (`attr6`),
  KEY `FK1` (`attr8`),
  CONSTRAINT `FK1` FOREIGN KEY (`attr8`) REFERENCES `table1` (`attr0`),
  CONSTRAINT `FK2` FOREIGN KEY (`attr6`) REFERENCES `table2` (`attr0`)
) ENGINE=InnoDB AUTO_INCREMENT=12202000 DEFAULT CHARSET=utf8

显示创建表table2

CREATE TABLE `table2` (
  `attr0` bigint(20) NOT NULL AUTO_INCREMENT,
  `attr1` datetime DEFAULT NULL,
  `attr2` datetime DEFAULT NULL,
  `attr3` varchar(255) DEFAULT NULL,
  `attr4` varchar(255) DEFAULT NULL,
  `attr5` varchar(255) DEFAULT NULL,
  `attr6` bigint(20) DEFAULT NULL,
  `attr7` int(11) NOT NULL,
  `attr8` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`attr0`),
  KEY `FK3` (`attr6`),
  KEY `FK4` (`attr8`),
  CONSTRAINT `FK4` FOREIGN KEY (`attr8`) REFERENCES `table2` (`attr0`),
  CONSTRAINT `FK3` FOREIGN KEY (`attr6`) REFERENCES `table3` (`attr0`)
) ENGINE=InnoDB AUTO_INCREMENT=145366 DEFAULT CHARSET=utf8

显示创建表table3

CREATE TABLE `table3` (
  `attr0` bigint(20) NOT NULL AUTO_INCREMENT,
  `attr1` datetime DEFAULT NULL,
  `attr2` datetime DEFAULT NULL,
  `attr3` varchar(255) NOT NULL,
  `attr4` varchar(255) DEFAULT NULL,
  `attr5` varchar(255) NOT NULL,
  `attr6` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`attrr0`),
  KEY `FK5` (`attr6`),
  CONSTRAINT `FK5` FOREIGN KEY (`attr6`) REFERENCES `table4` (`attr0`)
) ENGINE=InnoDB AUTO_INCREMENT=5994 DEFAULT CHARSET=utf8

显示创建表table4

CREATE TABLE `table4` (
  `attr0` bigint(20) NOT NULL AUTO_INCREMENT,
  `attr1` datetime DEFAULT NULL,
  `attr2` datetime DEFAULT NULL,
  `attr3` bit(1) NOT NULL,
  `attr4` bit(1) NOT NULL,
  `attr5` varchar(255) NOT NULL,
  `attr6` bit(1) NOT NULL,
  `attr7` bit(1) NOT NULL,
  `attr8` bit(1) NOT NULL,
  `attr9` varchar(255) NOT NULL,
  `attr10` date NOT NULL,
  `attr11` varchar(255) DEFAULT NULL,
  `attr12` bit(1) NOT NULL DEFAULT b'0',
  `attr13` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`attr0`)
) ENGINE=InnoDB AUTO_INCREMENT=5959 DEFAULT CHARSET=utf8

标签: mysqloptimizationkernelloadcpu

解决方案


高 CPU --> 不良索引和/或不良配方。在这种情况下,它是其中一个表的索引。

    from  table1
    left outer join  table2  ON table1.attr6=table2.attr0
    where  table1.attr4='BLABLABLABLA'
      and  table2.attr0=123456789
    order by  table1.attr7 desc

我们不一定能判断优化器是否会以table1or开头table2,所以让我们为两者设计最佳索引并让它决定。

如果t1.a0更具选择性:

t2: INDEX(a0)
t1: INDEX(a4, a6)

Ift1.a4是一个更好的起点,或者优化器决定ORDER BY在索引中包含 :

t1: INDEX(a4, a7)
t2: INDEX(a0)

attr0(在两个表中表示两个不同的值是令人困惑的。我认为它是真的id吗?)

看到 t2.a0 是 PK,我建议将这些“复合”索引都添加到 t1:

INDEX(a4, a6)
INDEX(a4, a7)

由于您对两个表都有约束,因此它并不是真正的LEFT JOIN. 为避免人为混淆,请改为 just JOIN。(INNER并且OUTER被忽略。)

由于您没有从 t2 中选择任何列,因此JOIN可以将其转换为“半连接”:

select  table1.attr0, table1.attr1, table1.attr2, table1.attr3,
        table1.attr4, table1.attr5, table1.attr8, table1.attr6,
        table1.attr7
    from  table1
    where  table1.attr4='BLABLABLABLA'
      AND  EXISTS( SELECT 1 FROM table2
            WHERE table1.attr6=table2.attr0
              AND table2.attr0=123456789 )
    order by  table1.attr7 desc
    limit  1;

(但是,我不确定这会加快速度。我担心您的混淆会弄乱某些列名或逻辑。)


推荐阅读