MySQL - 为什么在这两个查询中具有时间戳的这种不同性能?

Van*_*las 3 mysql performance

我编写了一个Perl脚本,它在一个超过140000行的表中进行了一些SQL查询并进行了扩展.

我想比较日期并获得一些行,但我意识到只需更改一个SQL查询,我就可以获得如此多的不同执行速度.

看一下执行100 $ sql查询的以下测试结果.我在不同执行之间在脚本中更改的唯一行是$ sql行.

我多次运行测试并且总是得到类似的结果,所以我猜它与缓存问题无关.

my $sql = "SELECT `mem_used`, `swap_used`, `mem_total` 
FROM `$config{db}{data_table}` 
WHERE  `host_id` = $host_id 
AND date >= '$date' 
AND TIMESTAMPDIFF( MINUTE , `date`, '$date' ) <= $interval;"; # VERY SLOW

time ./data_smoothing.pl

real    1m28.818s
user    1m6.516s
sys     0m0.256s
Run Code Online (Sandbox Code Playgroud)
my $sql = "SELECT `mem_used`, `swap_used`, `mem_total` 
FROM `$config{db}{data_table}` 
WHERE  `host_id` = $host_id 
AND date >= '$date' 
AND (UNIX_TIMESTAMP(`date`) - UNIX_TIMESTAMP('$date')) <= ($interval * 60);"; #SLOW

$ time ./data_smoothing.pl

real    0m10.005s
user    0m0.108s
sys     0m0.028s
Run Code Online (Sandbox Code Playgroud)
my $sql = "SELECT `mem_used`, `swap_used`, `mem_total` 
FROM `$config{db}{data_table}` 
WHERE  `host_id` = $host_id 
AND (`date` BETWEEN '$date' 
AND DATE_ADD('$date', INTERVAL $interval MINUTE));"; #FAST

$ time ./data_smoothing.pl

real    0m0.190s
user    0m0.084s
sys     0m0.016s
Run Code Online (Sandbox Code Playgroud)

如何创建表(取自mysqldump)

CREATE TABLE `data` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `host_id` smallint(6) NOT NULL,
  `date` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `mem_total` double(10,3) DEFAULT NULL,
  `mem_used` double(10,3) DEFAULT NULL,
  `swap_total` double(10,3) DEFAULT NULL,
  `swap_used` double(10,3) DEFAULT NULL,
  `CPU_count` smallint(6) DEFAULT NULL,
  `load_avg_1` float DEFAULT NULL,
  `load_avg_5` float DEFAULT NULL,
  `load_avg_15` float DEFAULT NULL,
  `uptime` double(10,3) DEFAULT NULL,
  `cpuIdlingTime` double(10,3) DEFAULT NULL,
  `rxBytesTotal` bigint(20) DEFAULT NULL,
  `txBytesTotal` bigint(20) DEFAULT NULL,
  `rxPacketsTotal` bigint(20) DEFAULT NULL,
  `txPacketsTotal` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`,`host_id`),
  KEY `fk_data_hosts` (`host_id`),
  KEY `date_memtot_hosts` (`date`,`mem_total`,`host_id`),
  CONSTRAINT `fk_data_hosts` FOREIGN KEY (`host_id`) REFERENCES `hosts` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=145300 DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)

cHa*_*Hao 5

最后一个是最快的,因为您的比较非常适合索引.其他人,不是那么多.

在测试之前,当您使用列的值调用函数(或执行其他任何操作)时,您会看到几乎无法使用索引快速查找匹配的行.引擎必须基本上遍历整个表,抓取日期,用它做一些数学运算,然后检查条件是否为真.

同时,如果你只是说BETWEEN this_value AND that_value,MySQL根本不需要做太多 - 它可以参考索引并找到范围的两个端点,这要快得多.

调用对DATE_ADD('$date', INTERVAL $interval MINUTE)运行时没有太大影响,因为MySQL通常足够聪明,可以缓存它知道不会改变的值,因此每次都不需要再次计算它们.

至于前两者之间差异的原因,我无法告诉你.也许TIMESTAMPDIFF就是这么慢.也许转换和数学在时间戳方面要简单得多,特别是考虑到UNIX_TIMESTAMP('$date')每次都不需要重新计算.但所有这些只是在猜测.