MySQL NOW()函数的高精度用法

11

我正在开发一个使用远程MySQL数据库存储数据的C++应用程序。

其中一个功能是尽可能地与远程数据保持同步。为了实现这个功能,我使用NOW()函数来获取最后更新时间,并在更新记录时将last_changed字段设置为NOW()。

目前这个方法可以正常工作,但有一个问题是它的最大精度只有1秒。这会导致大量重复的条目,浪费带宽且需要手动删除。

为了减少这种情况,我想要更高的精度,最好能达到微秒级别(就像Unix的gettimeofday()函数)。然而,我在文档中找不到关于这方面的任何信息。我所找到的是NOW()函数使用了一种变量类型,可以存储高达微秒级别的精度(source)。但在使用它时,秒后面的所有精度都是0。

是否有一种方式可以强制Mysql服务器使用更高精度的计时器(即使性能可能受到影响)?或者有其他的实现方式吗?

5个回答

11

在MariaDB中,您可以使用

SELECT NOW(4);

要在您的时间戳中获取毫秒,请参见此处


6

http://dev.mysql.com/doc/refman/5.1/en/datetime.html

在 MySQL 中,DATETIME 或 TIMESTAMP 值可以包含高达微秒(6 位数字)精度的小数部分。尽管这个小数部分被识别,但它会从存储到 DATETIME 或 TIMESTAMP 列中的值中被丢弃。

使用 varchar 或 text 列来保留小数部分。

注:MySQL 本身无法获取带有微秒的时间。

另外,未来版本除外。

http://dev.mysql.com/doc/refman/5.6/en/news-5-6-4.html

MySQL 现在允许 TIME、DATETIME 和 TIMESTAMP 值具有高达微秒(6 位数字)精度的小数秒。要定义包含小数秒部分的列,请使用 type_name(fsp) 语法,其中 type_name 是 TIME、DATETIME 或 TIMESTAMP,fsp 是小数秒精度。

某些表达式产生与以前不同的结果。例如:timestamp 系统变量返回一个包含微秒小数部分而不是整数值的值。


谢谢您的回复,但正如我所提到的,尽管NOW()函数支持它,但它不会填充小数部分,而这正是我想要的,即具有微秒精度的当前系统时间。当使用NOW()+!时,我得到的是'20120123234744.000000'(最高精度为秒)。 - Marking
1
@标记 MySQL 无法获取微秒级时间,请在您的应用程序中获取它们。 - Cheery
做一个UDF来实现这个函数怎么样?据我所知,Mysql的这个特性应该允许我使用最大精度,对吧? - Marking

4

在得到一些提示后,我研究了MySQL用户定义函数,并使其正常工作。

在Code::Blocks中,我编写了这个简单的库文件:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef long long longlong;    
#include <mysql.h>
#include <ctype.h>    
#include <sys/time.h>
#include <unistd.h>
static pthread_mutex_t LOCK_hostname;
extern "C" longlong PreciseNow(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error);
extern "C" my_bool PreciseNow_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
extern "C" void PreciseNow_deinit(UDF_INIT *initid);
my_bool PreciseNow_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
 return 0; //optional
}
void PreciseNow_deinit(UDF_INIT *initid)
{ //optional
}

longlong PreciseNow(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
{
   struct timeval start;
   long mtime, seconds, useconds;
   gettimeofday(&start, NULL);
   return start.tv_sec * 1000000 + start.tv_usec;
}

它所做的唯一事情就是返回当前系统时间。我将lib文件放在“/usr/lib/mysql/plugin/”中。 其次,在数据库中,我执行了以下查询:
CREATE FUNCTION PreciseNow RETURNS INTEGER SONAME 'libhrt.so'
最后,我将我的时间戳列转换为bigint(8字节整数)。也许这并不是必要的,但由于C函数返回相同的对象类型,所以为什么不呢...... 现在运行SQL查询“SELECT PreciseNow()”,我会得到一个微秒精确的内置“NOW()”版本! 由于我对MySQL的知识非常有限,因此我认为这是解决我的问题的完全合法和有效的解决方案?

我在Linux命令行中遇到了一些问题,无法使其正常工作,所以这是最终为我工作的内容:g++ -c -fpic libhrt.cpp && g++ -shared -lc -o libhrt.so libhrt.o && cp libhrt.so /usr/lib/mysql/plugin/ - Tim Tisdall
你可以使用自MySQL 5.6起的 NOW(<precision>) 函数 - 参见文档。MySQL 5.6发布时间比你回答自己的问题晚了1周。但无论如何,干得好伙计 +1。 - Peter VARGA

3

补充amra的内容。在您设置列的fsp后,您可以使用MySQL内置函数。

NOW(6)或CURTIME(6)等函数。它在MySQL 5.6中得到支持。


2
MySQL将支持微秒级精度,详见MySQL 5.6.4日志:

处理小数秒

不兼容变更:MySQL现在允许对TIME、DATETIME和TIMESTAMP值使用小数秒,最高精度可达微秒(6位)。若要定义包括小数秒部分的列,请使用类型名(fsp)语法,其中类型名为TIME、DATETIME或TIMESTAMP,fsp为小数秒精度。例如:

CREATE TABLE t1 (t TIME(3), dt DATETIME(6)); 如果给出了fsp值,它必须在0到6之间。值为0表示没有小数部分。如果省略,则默认精度为0。(这与标准SQL默认精度6有所不同,以保持与先前的MySQL版本兼容性)。

以下内容总结了此变更的影响。另请参见“时间值中的小数秒”第10.3.5节。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接