`
丁林.tb
  • 浏览: 789603 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

MySQL关于timestamp和mysqldump的一个“bug”

阅读更多

复现

来源于一个同事在做数据转储碰到的的问题,简化如下:

1、建表

drop table if exists tb;

CREATE TABLE tb (

  c timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'

) ENGINE=InnoDB DEFAULT CHARSET=gbk;

insert into tb values(now());

select * from tb;

 

返回

mysql> select * from tb;

+---------------------+

| c                   |

+---------------------+

| 2012-12-14 00:42:45 |

+---------------------+

1 row in set (0.00 sec)

 

2dump“出错”

  mysqldump   -Srun/mysql.sock -uroot   test tb   --where='c="2012-12-14 00:42:45"' | grep INSERT

返回为空,也就是说导不到数据。

 

 

分析

从上面的结论看上去,似乎是mysqldump”bug”,看得到的数据都导不出来。 如果我们先不加where条件,

mysqldump   -Srun/mysql.sock -uroot   test tb    |grep INSERT                         

INSERT INTO `tb` VALUES ('2012-12-13 16:42:45');

 

接下来我们要说说关于timestamp这个字段类型。

首先,从大小上你可以看出来,它不是个字符串,实际上是一个整型。所以当我们执行 where c=” 2012-12-14 00:42:45的时候,需要将其转换为整型。这就涉及到转换规则。也就是说,对于相同的时间戳,在不同的时区显示的结果是不一样的。反过来也一样,相同的字符串,在不同的时区解释下,会得到不同的时间戳。

我们来看一下整个mysqldump的结果。在文件头部,可以看到

/*!40103 SET TIME_ZONE='+00:00' */; 字样,说明mysqldump在默认情况下,是按’+00:00’(中时区).

mysql客户端的默认值呢:

mysql> select @@time_zone;

+-------------+

| @@time_zone |

+-------------+

| SYSTEM      |

+-------------+

 

这个SYSTEM表示MySQL取操作系统的默认时区,因此是东8区。如果我们设置为与mysqldump相同时区,

mysql> set time_zone='+00:00';  

Query OK, 0 rows affected (0.00 sec)

 

mysql> select * from tb;

+---------------------+

| t                   |

+---------------------+

| 2012-12-13 16:42:45 |

+---------------------+

1 row in set (0.00 sec)

就跟我们上面看到的全表导出的结果一样了。

也就是说,这个问题是因为mysqldump强行设置了时区为中时区造成的。

 

解决1

mysqldump的代码中我们看到,可以用 --tz-utc=0 参数去掉前面的设置时区的动作。这样用的也是默认时区。

mysqldump  --tz-utc=0 -Srun/mysql.sock -uroot   test tb   --where='c="2012-12-14 00:42:45"'  |grep INSERT

INSERT INTO `tb` VALUES ('2012-12-14 00:42:45');

 

可以看到,这个貌似就是我们要的结果,导出的结果也很合理。

 

进一步

如果这个这么好,为什么mysqldump的开发者不把—tz-utc=0作为默认行为呢?也就是说哦这样做有什么风险?

实际上是因为要防止跨时区导数据。假设你把中国一个机器上的数据导入到美国的一个mysqld(想起@plinux 说的b2b就有这种情况),若不显式地设置一个时区,在导入时就会出错了。因为都用系统默认的时区,相同的字符串值会得到不同的时间戳。如我们前面说的, 时间戳是以整型方式存储的。

 

解决2

所以上面的--tz-utc=0存在风险。当然如果你确定源和目标系统时区没变,是ok的。我们讨论看看有没有更保险的方法。

既然是时间戳是保险的,其实可以考虑,用时间戳来做where条件。

mysql> select unix_timestamp(c) from tb;

+-------------------+

| unix_timestamp(c) |

+-------------------+

|        1355416965 |

+-------------------+

 

按照表里的这个值,我们的dump命令改成

mysqldump   -Srun/mysql.sock -uroot   test tb   --where=' unix_timestamp(c)=1355416965' | grep INSERT

INSERT INTO `tb` VALUES ('2012-12-13 16:42:45');

这次对了,而且与是否使用 --tz-utc=0  无关,都能得到结果,区别只是显示问题。

 

不过对MySQL比较熟悉的同学就知道,这个写法还是存在一个问题:用不上索引,因为我们在字段上做了unix_timestamp这个操作。有时候我们在这种表上为了导出方便有一个索引专门建在timestamp字段上。

 

因此想到用逆函数

mysqldump   -Srun/mysql.sock -uroot   test tb   --where='c= from_unixtime(1355416965)'  | grep INSERT         

INSERT INTO `tb` VALUES ('2012-12-13 16:42:45');

 

5
0
分享到:
评论
4 楼 lidayu_up 2013-04-11  
虽然dump出来时间不一样,但是导进去的时候,又变回来了
3 楼 andyjackson 2012-12-17  
mark. mysql运维工作需要注意滴
2 楼 xieye 2012-12-15  
更好的办法就是不用这个类型
1 楼 zhoujy 2012-12-14  
非常好,一直都没注意这个事情。

相关推荐

    MySQL 5.6 中的 TIMESTAMP 和 explicit_defaults_for_timestamp 参数

    主要介绍了MySQL 5.6 中的 TIMESTAMP 和 explicit_defaults_for_timestamp 参数,需要的朋友可以参考下

    Mysql中的Datetime和Timestamp比较

    主要介绍了Mysql中的Datetime和Timestamp比较,本文总结了它们的相同点和不同点以及时间格式介绍等,需要的朋友可以参考下

    mysql之TIMESTAMP(时间戳)用法详解

    主要介绍了mysql之TIMESTAMP(时间戳)用法,需要的朋友可以参考下

    MySQL 5.6 中 TIMESTAMP 的变化分析

    ■表中的第一个TIMESTAMP列,如果没有声明NULL属性、DEFAULT或者 ON UPDATE,会自动分配 DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP 属性。 ■表中第二个TIMESTAMP列,如果没有声明为NULL或者DEFAULT...

    MySQL错误TIMESTAMP column with CURRENT_TIMESTAMP的解决方法

    主要介绍了MySQL错误TIMESTAMP column with CURRENT_TIMESTAMP的解决方法,需要的朋友可以参考下

    mysql 数据类型TIMESTAMP

    在mysql中timestamp数据类型是一个比较特殊的数据类型,他可以自动在你不使用程序更新情况下只要你更新了记录timestamp会自动更新时间 通常表中会有一个Create date 创建日期的字段,其它数据库均有默认值的选项。...

    MySQL timestamp自动更新时间分享

    通常表中会有一个Create date 创建日期的字段,其它数据库均有默认值的选项。MySQL也有默认值timestamp,但在MySQL中,不仅是插入就算是修改也会更新timestamp的值! 这样一来,就不是创建日期了,当作更新日期来...

    MySql 5.1 参考手册.chm

    在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用内存 ...

    mysql的日期和时间函数

    mysql的日期和时间函数 这里是一个使用日期函数的例子。下面的查询选择所有 date_col 值在最后 30 天内的记录。 mysql> SELECT something FROM tbl_name WHERE TO_DAYS(NOW()) - TO_DAYS(date_col) ...

    mysql官方中文参考手册

    在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用内存 ...

    MySQL timestamp的类型与时区实例详解

    MySQL的timestamp类型时间范围between ‘1970-01-01 00:00:01’ and ‘2038-01-19 03:14:07’,超出这个范围则值记录为’0000-00-00 00:00:00’,该类型的一个重要特点就是保存的时间与时区密切相关,上述所说的时间...

    mysql时间类型对应的java类型1

    Mysql 与 java 的时间类型 MySql的时间类型有 Java中与之对应的时间类型 datejava.sql.Date Datetimejava.sql

    MySQL中datetime和timestamp的区别及使用详解

    主要介绍了MySQL中datetime和timestamp的区别及使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    在MySql中获取当前系统当前时间的函数和TIMESTAMP列类型使用说明

    在MySql中获取当前系统当前时间的函数和TIMESTAMP列类型使用说明

    MySQL 5.1中文手冊

    在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用内存 ...

    MYSQL

    13 维护 MySQL 安装 13.1 使用myisamchk进行表维护和崩溃恢复 13.1.1 myisamchk的调用语法 13.1.2 myisamchk的内存使用 13.2 13.2 建立一个数据库表维护规范 13.3 获得关于一个表的信息 ...

    mysql 时间戳的用法

    时间戳字段在MySQL中经常使用到,比如需要记录一行数据创建的时间或修改的时间时,我们通常会使用时间戳即timestamp字段。本篇文章主要介绍timestamp字段的使用方法及相关参数,希望大家读完能对timestamp有更深的...

Global site tag (gtag.js) - Google Analytics