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

时间:2016-03-14 08:11:53

标签: mysql sql performance indexing

我有这张桌子:

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;

现在,*number

只需要4到5秒的查询时间

坦克为你提供帮助,甚至是给我-1的人。考虑到我的服务器是低端硬件而且我将缓存select count结果,这就足够了。

2 个答案:

答案 0 :(得分:0)

也许

select count(geo_state) from messenger_contacts where geo_state=1

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

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

答案 1 :(得分:0)

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

将“标志”编入索引是浪费,我假设typehas_telegram。优化器永远不会使用它们,因为它的效率低于简单的表扫描效果。

标准编码模式是:

select count(*)
    from messenger_contacts
    where geo_state=1

除非您不需要计算NULLsCOUNT(geo_state)暗示的内容。

geo_state(或索引geo_state开头)上有索引后,查询将扫描索引(这是一个单独的BTree结构),从第一次出现geo_state=1直到最后一次出现,算起来。也就是说,它将触及1.1百万个索引条目。所以,预计几秒钟。计算“罕见”geo_state的速度会快得多。

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

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

INDEX(number,geo_state)对于SELECTs提到的任何geo_state实际上都是无用的 - select count(number)...应该是第一位的。这是var me = this, toastConfig = { top: 10, right: 10, timeout: 5000, hideOnMaskTap : true, message: '<div style="text-align: left; font-size: 14px;">' + ' <p style="font-size:12px;text-align: center;margin-bottom: 8px;">New Message</p>' + ' <p><b>' + receivedMessage.Sender + ' : </b></p>' + ' <p>' + Ext.util.Format.ellipsis(Ext.util.Format.htmlEncode(receivedMessage.MessageBody), 80) + '</p>' + '</div>' }; var toastWindow = Ext.toast(toastConfig); var msg_toast = document.getElementsByClassName('x-toast')[0]; if(msg_toast){ msg_toast.addEventListener( "touchend", function(){ me.showMsgPanel(); toastWindow.hide(); }, true ); } 案例的“覆盖”索引的示例。

More on building indexes.