繁体   English   中英

带有索引的非常慢的简单 MySql 查询

[英]Very Slow simple MySql query with index

我有这张桌子:

CREATE TABLE `messenger_contacts` (
  `number` varchar(15) NOT NULL,
  `has_telegram` tinyint(1) NOT NULL DEFAULT '0',
  `geo_state` int(11) NOT NULL DEFAULT '0',
  `geo_city` int(11) NOT NULL DEFAULT '0',
  `geo_postal` int(11) NOT NULL DEFAULT '0',
  `operator` tinyint(1) NOT NULL DEFAULT '0',
  `type` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `messenger_contacts`
  ADD PRIMARY KEY (`number`),
  ADD KEY `geo_city` (`geo_city`),
  ADD KEY `geo_postal` (`geo_postal`),
  ADD KEY `type` (`type`),
  ADD KEY `type1` (`operator`),
  ADD KEY `has_telegram` (`has_telegram`),
  ADD KEY `geo_state` (`geo_state`);

大约有 1100 万条记录。

这个表上的一个简单的计数选择需要大约 30 到 60 秒才能完成女巫似乎非常高。

select count(number) from messenger_contacts where geo_state=1

我不是数据库专家,所以除了设置索引我不知道我还能做些什么来使查询更快?

更新:

好的,我对列类型和大小进行了一些更改:

CREATE TABLE IF NOT EXISTS `messenger_contacts` (
  `number` bigint(13) unsigned NOT NULL,
  `has_telegram` tinyint(1) NOT NULL DEFAULT '0' ,
  `geo_state` int(2) NOT NULL DEFAULT '0',
  `geo_city` int(4) NOT NULL DEFAULT '0',
  `geo_postal` int(10) NOT NULL DEFAULT '0',
  `operator` tinyint(1) NOT NULL DEFAULT '0' ,
  `type` tinyint(1) NOT NULL DEFAULT '0' ,
  PRIMARY KEY (`number`),
  KEY `has_telegram` (`has_telegram`,`geo_state`),
  KEY `geo_city` (`geo_city`),
  KEY `geo_postal` (`geo_postal`),
  KEY `type` (`type`),
  KEY `type1` (`operator`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

现在查询只需要 4 到 5 秒*number

坦克每个人都需要你的帮助,即使是给我-1的那个人。 现在考虑到我的服务器是低端硬件并且我将缓存select count结果,这已经足够了。

也许

select count(geo_state) from messenger_contacts where geo_state=1

因为它会给出相同的结果但不会使用聚集索引中的数字列?

如果这没有帮助,我会尝试将 number 列更改为 INT 类型,这应该会减小索引大小,或者尝试增加 MySQL 可用于缓存索引的内存量。

您没有更改数据类型。 INT(11) == INT(2) == INT(100) —— 每个都是 4 字节有符号整数。 您可能需要 1 字节无符号TINYINT UNSIGNED或 2 字节SMALLINT UNSIGNED

索引“标志”是一种浪费,我假设typehas_telegram是。 优化器永远不会使用它们,因为它比简单地执行表扫描效率低。

标准编码模式为:

select count(*)
    from messenger_contacts
    where geo_state=1

除非你需要不计NULLs ,这是COUNT(geo_state)暗示。

一旦您拥有geo_state上的索引(或以geo_state开头的索引),查询将扫描索引(这是一个单独的 BTree 结构),从第一次出现geo_state=1开始,直到最后一次,随着它的进行计数。 也就是说,它将触及 110 万个索引条目。 所以,几秒钟是可以预料的。 计算“稀有” geo_state会运行得更快。

30-60 秒与 4-5 秒的原因很可能是缓存。 前者必须从磁盘读取内容; 后者没有。 运行查询两次。

除非存在缓存差异,否则对该查询使用geo_state索引将比使用PRIMARY KEY更快。

INDEX(number,geo_state)对于提到的任何SELECTs几乎都没用—— geo_state应该是第一个。 这是select count(number)...案例的“覆盖”索引示例。

有关构建索引的更多信息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM