2015-01-10 189 views
1

我试图使用索引的src_ip像这样一个表来执行一个简单的选择查询:优化慢,索引选择MySQL查询

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,采用接近最大 RAM: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-树,并且有索引日期,src_ip和dest_ip,但只有src_ip将被真正使用 - 基于解释的输出时,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 | 

在此先感谢

+0

你可以添加 SHOW CREATE TABLE'netflow_nov2' 结果 –

+0

你对src_IP领域或与一些其他领域的成份指数指数? –

+0

@DmitryBezik show create table已包含在问题的底部。正如你所看到的,src_ip确实有一个索引。还有,SHOW INDEXES OUTPUT:https://www.dropbox.com/s/iyh6335c0uconh8/Screen%20Shot%202015-01-10%20at%2011.02.37%20AM.png?dl=0 – SPLASHT0N

回答

0

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

不幸的是,这种结构所支持的唯一读取模式是全表扫描。 使用未覆盖的二级索引仍然会导致大量的随机磁盘查找,从而影响性能。

当数据读取顺序与磁盘上的顺序相同时,获得最佳读取性能,对于InnoDB而言,数据以主键顺序表示。

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

更新:这个想法是实现数据局部性,并避免随机磁盘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场你的原始表,这是InnoDB如何处理它)。

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

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

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

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

+0

你能解释一下物化视图表的外观吗?我认为每一行索引都是src_ip,并且这些值将是它们存储在其中的行的id。我对此有点困惑,任何帮助将不胜感激。 – SPLASHT0N

+0

@ SPLASHT0N请看帖子更新,希望有帮助。 –

+0

我看到这会起作用,但我担心创建索引需要很长时间。不过,我看不到其他解决方案。感谢您的详细解答。 – SPLASHT0N

0

我认为,读表没有指数将需要不到5个小时。但你有一张大桌子。有两种“环境”可能性会导致性能下降:

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

但我的第一个猜测是,查询是而不是使用索引。起初我错过了这个,但你有一个多部分索引。 只有这个查询可以利用的索引是其中第一个键是src_IP的索引。所以,如果你的索引是netflow_nov2(src_IP, date, dest_ip)netflow_nov2(src_IP, dest_ip, date),那么你没事。如果其他列中的任何一列都是第一个,则不会使用该索引。通过在查询前加上explain来查看索引是否正在被使用,您可以很容易地看到发生了什么。

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

+0

Mul并不意味着复合索引'如果键是MUL,该列是非唯一索引的第一列,其中多次出现在列中允许给定的值“ – Mihai

+0

我很确定索引正在被使用。 EXPLAIN命令表明它确实在使用:https://www.dropbox.com/s/e6szvyi6kiflfn8/Screen%20Shot%202015-01-10%20at%2011.02.26%20AM.png?dl=0。是的,Mihai在他的断言中是正确的,即他们不是多部分键,而是具有非唯一值的键。事实上,每个src_ip可能会有数百万次匹配,这可能是问题所在。 – SPLASHT0N