SQL Server报错The datediff function resulted in an overflow

zabbix的监控有一个报错:

经检查,这个报错,调用的是下面的一个监控:

这个监控脚本,是用来监控发生在temp上的pagelatch_up的争用。监控脚本中,包含了datediff函数。datediff的返回值如果overflow,将导致上面的报错。

我们来看看,datediff这个值溢出的情况。在官方文档中,datediff函数定义返回的是int值,int值的取值范围是 (-2,147,483,648 to +2,147,483,647)。所以,第一步的怀疑,是抓取的起始时间和结束时间之差,溢出了。

那么,什么时候会溢出? 如果进程是刚刚发起的,那么之间的差值,应该会很短,不会溢出。那么离目前时间最远的进程,会不会溢出?

在SQL Server中进程分为客户端进程和系统进程,一般情况下,客户端进程都是最近发起的,所以时间差不会溢出。是否是系统进程导致时间差溢出的呢?

因为系统进程不是客户端发起的,所以系统进程的last_batch时间,就是数据库的启动时间,我们检查了一下数据库的启动时间:

发现是2018-04-14 22:02:46.377。这个时间是否有可能导致溢出?

还是根据官方文档:

可以看到,如果是到秒级,即datediff(ss),中间的时间差是可以长达68年19天3小时14分7秒的。而我们的数据库启动时间,远远没有超过68年。

去掉where条件之后,重新运行了几次上述的SQL语句,没有发现早于2018-04-14的。

正当束手无策的时候,想起在这个数据库上部署过msawr,会定期snapshot各项性能指标,那么可以从msawr中去找找线索。

确实,我们在msawr中发现了有些进程的last_batch早于数据库启动的时间,这个时间,是1900-01-01 00:00:00.000。

last_batch的含义,在官方文档是这样解释的:

last_batch是个datetime的值,在官方文档中说明中,datetime类型默认值是1900:

而last_batch的这个字段,是not null:

也就是说,在为null的情况下,这个datetime类型的值,将有默认值来填充,所以也就出现了1900-01-01 00:00:00.000。

那么sysprocesses的last_batch会出现控制,进而被替代成1900-01-01 00:00:00.000 ?这个在网上找很多文章,都归结到微软的这个文章:”INF: Last Batch Date is Seen as 1900-01-01 00:00:00.000″ at http://support.microsoft.com/?kbid=306625 , 但是点进去你会发现,这个文章已经404找不到了。

幸好,还有另外的一个文章启发了我:

它说:

也就是说,由非远程调用(RPC,remote procedure call)发起的进程,其last_batch是null值,而null值继而会被1900-01-01 00:00:00.000所替代。

我们进而看lastwaittype:发现其大部分的,是CXPACKET的并发等待。

所以,应该是并发进程,不是有RPC远程调用的,而是直接在本地调用的。在第一次的时候,last_batch没有被更新,只是留有了null值,进而被替换成了1900年。从而导致了我们的溢出报错。

解决方式也很简单。因为1900年的固定的值,加个条件and last_batch<>‘1900-01-01 00:00:00.000’ 就可以了。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据