[英]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
。
索引“标志”是一种浪费,我假设type
和has_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.