大会计表,按两个日期分区的最佳方式

Rad*_*ris 5 mysql performance partitioning

我需要创建一个日志表来存储与外部网络的连接(过去 3 年,之后日志将进入备份)。使用的硬件/软件是专有的,为了记账,它只需使用一些参数调用我们的自定义脚本,如下所示:

  • 当用户连接时 ( our_script START user mac ip);
  • 当用户断开连接 ( our_script STOP user mac ip in_bytes out_bytes more)

有时我们不会收到断开连接消息。所以我们需要适应这种情况。

到目前为止,我为会计表提出了这个结构:

CREATE TABLE `accounting` (
  `user` varchar(50) NOT NULL DEFAULT '',
  `mac` varchar(20) NOT NULL DEFAULT '',
  `ip` varchar(15) NOT NULL DEFAULT '',
  `ipv6` varchar(39) DEFAULT NULL,
  `start_datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `stop_datetime` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `in_bytes` bigint(32) unsigned DEFAULT '0',
  `out_bytes` bigint(32) unsigned DEFAULT '0',
  `more_columns` varchar(255) default NULL, 
  PRIMARY KEY (`user`,`mac`,`ip`,`start_datetime`,`stop_datetime`),
  KEY `prim_ipv6` (`user`,`mac`,`ipv6`,`start_datetime`,`stop_datetime`),
  KEY `user` (`user`) USING HASH,
  KEY `mac` (`mac`) USING HASH,
  KEY `ip` (`ip`) USING HASH,
  KEY `ipv6` (`ipv6`) USING HASH,
  KEY `start_datetime` (`start_datetime`),
  KEY `stop_datetime` (`stop_datetime`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
Run Code Online (Sandbox Code Playgroud)

用于写入的查询是(这些需要非常快):

  • 当用户连接一个简单的插入
  • 当用户断开连接时update accounting set stop_datetime=now(), in_bytes=$in_bytes, out_bytes=$out_bytes, more_columns=$more where user="$user" and ip="$ip" and stop_datetime="0000-00-00 00:00:00" order by start_datetime DESC limit 1;,这是一种解决方法,如果我们有不止一行开始,我们只更新最后一个开始。

更好的解决方法是在每次开始时更新没有它的行的 stop_datetime,并使用另一列来存储这不是正常停止,我想我会采用第二种解决方法。

我们有 2 种方法可以从该表中进行选择(最多可能会慢 1 - 2 秒):

  • 为用户选择最后 50 个连接:select ... where user="$user" order by start_datetime DESC limit 50;,为此用户 HASH 键很方便,因为 AFAIK HASH 在平等方面比 BTREE 更好。
  • 选择女巫用户在 date=$date 上与 ip=$ip 连接 select ... where ip="$ip" and $date between start_datetime and stop_datetime;

该表将包含 0.5 到 10 亿行,这就是我想对它进行分区的原因。最好的选择是按月分区,但我有 2 个相关日期,并且在月初/月底开始将在一个分区中,停止将在另一个分区中。

问题:

  • Witch 是通过 start_datetime、stop_datetime、start_datetime 和 stop_datetime 的子分区进行分区的最佳方式?

  • 我真的需要分区吗?

  • 你对如何改进这个有任何其他建议吗?

谢谢

Clo*_*ldo 2

由于在插入时不知道 stop_datetime,因此分区必须由 start_datetime 完成。

\n\n

我认为按天 ( date_format(start_datetime, '%Y-%m-%d')) 进行分区就足够了,因为 10 亿行除以 (3 年 * 365 天) \xe2\x89\x83 每个分区 900,000 行

\n\n

更新索引的成本很高,并且发生在插入、更新和删除时。将索引保持在最低限度。如果主要查询是那些选择,那么我将保留主键,如下所示,并丢弃所有其他键:

\n\n
PRIMARY KEY (`user`,`start_datetime`,`stop_datetime`,`mac`,`ip`)\n
Run Code Online (Sandbox Code Playgroud)\n