• mysql5.6 TIME,DATETIME,TIMESTAMP


    【背景】

    5.6.4以后时间类型(TIME,DATETIME,TIMESTAMP)支持微秒

    DATETIME范围 :'1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999'

    TIMESTAMP范围: values is '1970-01-01 00:00:01.000000' to'2038-01-19 03:14:07.999999'

     

    1) 5.6 支持指定小数精度

    use test

    CREATE TABLE fractest( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) );
    INSERT INTO fractest VALUES ('17:51:04.777', '2014-09-08 17:51:04.777', '2014-09-08 17:51:04.777');
    SELECT * FROM fractest;

    +-------------+------------------------+------------------------+
    | c1          | c2                     | c3                     |
    +-------------+------------------------+------------------------+
    | 17:51:04.78 | 2014-09-08 17:51:04.78 | 2014-09-08 17:51:04.78 |
    +-------------+------------------------+------------------------+

     

    2)5.6.4以前 插入的数据支持微秒,但插入存储的数据会忽略微秒

    use test

    CREATE TABLE fractest( c1 TIME, c2 DATETIME, c3 TIMESTAMP );
    INSERT INTO fractest VALUES ('17:51:04.777', '2014-09-08 17:51:04.777', '2014-09-08 17:51:04.777');
    SELECT * FROM fractest;

    +----------+---------------------+---------------------+
    | c1       | c2                  | c3                  |
    +----------+---------------------+---------------------+
    | 17:51:04 | 2014-09-08 17:51:04 | 2014-09-08 17:51:04 |
    +----------+---------------------+---------------------+

    3)5.6时间函数(CURTIME()SYSDATE(), or UTC_TIMESTAMP())可以指定微秒精度

    mysql> select CURTIME(2);
    +-------------+
    | CURTIME(2)  |
    +-------------+
    | 11:26:56.43 |
    +-------------+

    4)存储

    5.6.4以前,TIME,DATETIME,TIMESTAMP 分别固定占用3,8,4字节

    5.6.4以后,TIME,DATETIME,TIMESTAMP占有大小取决于微秒的精度。

    TIME 3 bytes + fractional seconds storage
    DATETIME 5 bytes + fractional seconds storage
    TIMESTAMP 4 bytes + fractional seconds storage

    而微秒的存储长度和精度的关系如下

    Fractional Seconds PrecisionStorage Required
    0 0 bytes
    1, 2 1 byte
    3, 4 2 bytes
    5, 6 3 bytes

    例如上例中的c1 TIME: 占4字节,c2 DATETIME占6字节,TIMESTAMP 占7字节,TIMESTAMP占用5字节

    相关函数可以参考my_datetime_packed_to_binary

     

    5)新老时间类型在源码中的表现 

    5.6 内部增加了一些新的时间类型

    MYSQL_TYPE_TIMESTAMP2

    MYSQL_TYPE_DATETIME2,
    MYSQL_TYPE_TIME2,

    用于支持微秒的存储。

    而老的时间类型

    MYSQL_TYPE_TIMESTAMP,
    MYSQL_TYPE_DATETIME,
    MYSQL_TYPE_TIME

    仍然保留和支持,从而兼容老的时间数据

     

    5.6 新建的表时间字段默认使用新的类型,参考如下代码

    sql/sql_yacc.yy:6514

      | DATETIME type_datetime_precision
        { $$= MYSQL_TYPE_DATETIME2; }

     

    6)binlog与新时间类型

     binlog的Table_map_log_event中会记录表的元数据信息,包括库,表,列信息等。新时间类型的微秒精度信息就作为列的元数据(m_field_metadata)进行存储。类似的大字段列的列元数据存储大字段的实际长度(Field_blob::do_save_field_metadata)。

     

    【问题重现】

    1 master 上执行

      use zy

      CREATE TABLE t1 (id int primary key, c1 TIME, c2 DATETIME, c3 TIMESTAMP );

      set sql_log_bin=0;

      alter table t1 modify c3 timestamp(4);

      set sql_log_bin=1;

      INSERT INTO t1 VALUES (10, '17:51:04.98887', '2014-09-08 17:51:04.866666', '2014-09-08 17:51:04.777');

     

    2 slave上执行

      show slave statusG        

      Last_Errno: 1677

      Last_Error: Column 3 of table 'zy.t1' cannot be converted from type 'timestamp' to type 'timestamp'

     

    【分析】

      

    1)先尝试修复,修改slave_type_conversions='ALL_LOSSY';参数slave_type_conversions可以参考 http://dev.mysql.com/doc/refman/5.5/en/replication-options-slave.html#sysvar_slave_type_conversions 

    mysql> show variables like 'slave_type_conversions';                                                                                          
    
    +------------------------+-------+
    
    | Variable_name          | Value |
    
    +------------------------+-------+
    
    | slave_type_conversions |       |
    
    +------------------------+-------+
    
    1 row in set (0.00 sec) 
    
    mysql> set global slave_type_conversions='ALL_LOSSY';
    
    Query OK, 0 rows affected (0.00 sec)
     
    show slave statusG
    
      Last_Errno: 1610
    
      Last_Error: Could not execute Write_rows event on table zy.t1; Corrupted replication event was detected, Error_code: 1610; handler error No Error!; the event's master log mysql-bin.000002, end_log_pos 550
    

      

     发现备库用备库的表结构信息解析binlog行数据(unpack_row)时出错,因此,此方法修复失败。

     

    2)查看源码:

    Rows_log_event::do_apply_event
    
      table_def::compatible_with
    
       can_convert_field_to
    
      ....
    
     
    
       if (field->real_type() == source_type)//本例主备类型一致
    
      {
    
        if (metadata == 0) // Metadata can only be zero if no metadata was provided  // 本例主库精度为4
    
        {
    
          /*
    
            If there is no metadata, we either have an old event where no
    
            metadata were supplied, or a type that does not require any
    
            metadata. In either case, conversion can be done but no
    
            conversion table is necessary.
    
           */
    
          DBUG_PRINT( "debug" , ("Base types are identical, but there is no metadata"));
    
          *order_var= 0;
    
          DBUG_RETURN( true );
    
        }
    
     
    
        DBUG_PRINT( "debug" , ("Base types are identical, doing field size comparison"));
    
        if (field->compatible_field_size(metadata, rli, mflags, order_var))
    
          DBUG_RETURN(is_conversion_ok(*order_var, rli));
    
        else
    
          DBUG_RETURN( false );
    
      }
    
       else if (metadata == 0 && //这里有对新老时间类型的兼容处理
    
               ((field->real_type() == MYSQL_TYPE_TIMESTAMP2 &&
    
                 source_type == MYSQL_TYPE_TIMESTAMP) ||
    
                (field->real_type() == MYSQL_TYPE_TIME2 &&
    
                 source_type == MYSQL_TYPE_TIME) ||
    
                (field->real_type() == MYSQL_TYPE_DATETIME2 &&
    
                 source_type == MYSQL_TYPE_DATETIME)))
    
      {
    
        /*
    
          TS-TODO: conversion from FSP1>FSP2.
    
          Can do non-lossy conversion
    
          from old TIME, TIMESTAMP, DATETIME
    
          to new TIME(0), TIMESTAMP(0), DATETIME(0).
    
        */
    
        *order_var= -1;
    
        DBUG_RETURN( true);
    
      } 
    

      上面代码进行类型兼容性判断,本例由于精度不一致在is_conversion_ok处会返回失败。

  • 相关阅读:
    30天敏捷结果(17):找出高效时间,并利用它来处理重要事情
    需求:需求获取技术之 观察
    30天敏捷结果(13):如何对事情付诸行动
    2010年11月blog汇总:敏捷练习、需求和建模
    MDSF:Eclipse MDD Day学习
    需求:结合TOGAF做好需求获取工作
    MDSF:架构工具简要功能说明
    信息系统开发平台OpenExpressApp:【OpenTest】 之 框架实现说明
    吃:第二次去吃香草香草
    30天敏捷生活(911):调整30天的节奏
  • 原文地址:https://www.cnblogs.com/justfortaste/p/4119722.html
Copyright © 2020-2023  润新知