优化慢速,索引选择MySql查询

时间:2015-01-10 16:44:27

标签: mysql database innodb

我正在尝试使用src_ip索引的表执行简单的选择查询,如下所示:

SELECT * FROM netflow_nov2 WHERE src_IP = 3111950672;

然而,即使4或5小时后也没有完成。我需要响应在几秒钟的范围内。我想知道如何优化它,所以情况就是这样。

另请注意,使用内置的SQL命令将源IP转换为整数。

有关该表的其他信息: 该表包含从nfdump解析的netflow数据。我正在使用该表来获取有关特定IP地址的信息。换句话说,基本上只会使用上面的查询。

以下是该表的SHOW TABLE STATUS给出的相关信息:

Rows: 4,205,602,143 (4 billion)
Data Length: 426,564,911,104 (426 GB)
Index Length: 57,283,706,880 (57 GB)

有关系统的信息: 硬盘:~2TB,使用接近最大值 内存:64GB

my.cnf文件: 见要点:https://gist.github.com/ashtonwebster/e0af038101e1b42ca7e3

表格结构:

   mysql> DESCRIBE netflow_nov2;
+-----------+------------------+------+-----+---------+-------+
| Field     | Type             | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+-------+
| date      | datetime         | YES  | MUL | NULL    |       |
| duration  | float            | YES  |     | NULL    |       |
| protocol  | varchar(16)      | YES  |     | NULL    |       |
| src_IP    | int(10) unsigned | YES  | MUL | NULL    |       |
| src_port  | int(2)           | YES  |     | NULL    |       |
| dest_IP   | int(10) unsigned | YES  | MUL | NULL    |       |
| dest_port | int(2)           | YES  |     | NULL    |       |
| flags     | varchar(8)       | YES  |     | NULL    |       |
| Tos       | int(4)           | YES  |     | NULL    |       |
| packets   | int(8)           | YES  |     | NULL    |       |
| bytes     | int(8)           | YES  |     | NULL    |       |
| pps       | int(8)           | YES  |     | NULL    |       |
| bps       | int(8)           | YES  |     | NULL    |       |
| Bpp       | int(8)           | YES  |     | NULL    |       |
| Flows     | int(8)           | YES  |     | NULL    |       |
+-----------+------------------+------+-----+---------+-------+
15 rows in set (0.02 sec)

我有关于索引和解释结果的其他信息,但简要说明: - 索引是b-trees,并且有date,src_ip和dest_ip的索引,但只使用src_ip - 基于EXPLAIN的输出,src_ip索引用于顶部提到的特定查询

和mysqltuner的输出: 见要点:https://gist.github.com/ashtonwebster/cbfd98ee1799a7f6b323

SHOW CREATE TABLE输出:

| netflow_nov2 | CREATE TABLE `netflow_nov2` (
  `date` datetime DEFAULT NULL,
  `duration` float DEFAULT NULL,
  `protocol` varchar(16) DEFAULT NULL,
  `src_IP` int(10) unsigned DEFAULT NULL,
  `src_port` int(2) DEFAULT NULL,
  `dest_IP` int(10) unsigned DEFAULT NULL,
  `dest_port` int(2) DEFAULT NULL,
  `flags` varchar(8) DEFAULT NULL,
  `Tos` int(4) DEFAULT NULL,
  `packets` int(8) DEFAULT NULL,
  `bytes` int(8) DEFAULT NULL,
  `pps` int(8) DEFAULT NULL,
  `bps` int(8) DEFAULT NULL,
  `Bpp` int(8) DEFAULT NULL,
  `Flows` int(8) DEFAULT NULL,
  KEY `src_IP` (`src_IP`),
  KEY `dest_IP` (`dest_IP`),
  KEY `date` (`date`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |

提前致谢

2 个答案:

答案 0 :(得分:0)

我认为在没有索引的情况下阅读表将花费不到5个小时。但你确实有一张大桌子。有两种“环境”可能会破坏性能:

  • 该表已被另一个进程锁定。
  • 结果集很大(数千万行),返回结果集的网络延迟/处理时间导致问题。

我的第一个猜测是,使用索引查询。我一开始错过了这个,但你有一个多部分索引。此查询可以利用的索引是第一个键为src_IP的索引。因此,如果您的索引是netflow_nov2(src_IP, date, dest_ip)netflow_nov2(src_IP, dest_ip, date),那么您没问题。如果其他列中的任何一个是第一列,则不会使用此索引。您可以通过将explain放在查询前面来查看正在使用的索引,从而轻松查看发生的情况。

如果这是一个问题,请创建一个索引src_IP作为索引中的第一个(或唯一)键。

答案 1 :(得分:0)

您当前的表结构针对随机写入进行了优化:记录按写入顺序放在磁盘上。

不幸的是,这种结构很好地支持的唯一读取模式是全表扫描。 使用非覆盖二级索引仍会导致大量随机磁盘搜索,从而导致性能下降。

以与磁盘上相同的顺序读取数据时获得最佳读取性能,对于InnoDB,这意味着主键顺序。

物化视图(具有适当主键的另一个InnoDB表)可能是一种可能的解决方案。在这种情况下,需要以src_IP开头的主键。

upd:这个想法是实现数据局部性并避免随机磁盘IO,目的是顺序读取。这意味着您的物化视图将如下所示:

CREATE TABLE `netflow_nov2_view` (
  `row_id` bigint not null, -- see below
  `date` datetime DEFAULT NULL,
  `duration` float DEFAULT NULL,
  `protocol` varchar(16) DEFAULT NULL,
  `src_IP` int(10) unsigned DEFAULT NULL,
  `src_port` int(2) DEFAULT NULL,
  `dest_IP` int(10) unsigned DEFAULT NULL,
  `dest_port` int(2) DEFAULT NULL,
  `flags` varchar(8) DEFAULT NULL,
  `Tos` int(4) DEFAULT NULL,
  `packets` int(8) DEFAULT NULL,
  `bytes` int(8) DEFAULT NULL,
  `pps` int(8) DEFAULT NULL,
  `bps` int(8) DEFAULT NULL,
  `Bpp` int(8) DEFAULT NULL,
  `Flows` int(8) DEFAULT NULL,
  PRIMARY KEY (`src_IP`, `row_id`) -- you won't need other keys
) ENGINE=InnoDB DEFAULT CHARSET=latin1

其中row_id必须由您的具体化逻辑维护,因为您没有在原始表格中使用它(或者您可以在原始表格中引入显式的auto_increment字段,它是' s无论如何InnoDB如何处理它。)

关键的区别在于,现在磁盘上的所有数据都按主键顺序排列,这意味着一旦找到第一条带有给定的' src_IP'所有其他记录可以按顺序获得。

根据数据的写入方式和相邻的应用程序逻辑,可以通过触发器或某些自定义外部进程来完成。

如果有可能牺牲当前的写入性能(或者使用一些异步队列作为缓冲区),那么可能只需要一个针对读取进行优化的表即可。

有关InnoDB索引的更多信息: http://dev.mysql.com/doc/refman/5.6/en/innodb-index-types.html