我正在尝试使用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 |
提前致谢
答案 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