为什么MySQL不支持毫秒/微秒的精度?

Byr*_*ock 41 php mysql doctrine

所以我发现了MySQL中最令人沮丧的错误.

显然,TIMESTAMP现场和支持功能不支持比秒更精确!?

所以我使用PHP和Doctrine,我真的需要那些微秒(我正在使用该actAs: [Timestampable]属性).

我发现我可以使用BIGINT字段来存储值.但是教条会加几毫秒吗?我认为它只是将NOW()赋予该领域.我也担心通过代码散布的日期操作函数(在SQL中)会破坏.

我还看到了有关编译UDF扩展的一些内容.这是不可接受的,因为我或未来的维护者将升级和噗,改变了.

有没有人找到合适的解决方法?

Xav*_*ois 36

有关下一位读者的信息,最终将在5.6.4版本中更正此错误:

"MySQL现在支持TIME,DATETIME和TIMESTAMP值的小数秒,精度高达微秒."

  • MySQL doc中的参考:http://dev.mysql.com/doc/refman/5.6/en/news-5-6-4.html (3认同)
  • 使用上面的链接读取5.6.4中的所有新内容...但如果您正在寻找如何进行小数秒,请阅读:http://dev.mysql.com/doc/refman/5.6/en/分数seconds.html.基本上代替DATETIME(或TIMESTAMP),执行DATETIME(6)(或TIMESTAMP(6))或其他精度. (3认同)

Mic*_*zka 29

从SQL92标准:

  • TIMESTAMP - 包含日期时间字段的年,月,日,小时,分钟和秒.

从我的角度来看,符合SQL92的数据库不需要支持毫秒或微秒.因此Bug#8523被正确标记为"功能请求".

Doctrine如何处理微秒等?我刚刚发现以下内容: Doctrine #Timestamp:

时间戳数据类型仅仅是日期和时间数据类型的组合.时间戳类型的值的表示是通过将日期和时间字符串值连接在由空格连接的单个字符串中来完成的.因此,格式模板是YYYY-MM-DD HH:MI:SS.

因此,在SQL92-docs中也没有提到微秒.但我不是深入学说,但它似乎是一个像java中的hibernate之类的ORM.因此,可以/应该可以定义您自己的模型,您可以将时间信息存储在BIGINT或STRING中,并且您的模型负责将其相应地读/写到PHP类中.

顺便说一句:我不认为MySQL会在不久的将来(如未来5年)以毫秒/微秒的速度支持TIMESTAMP.

  • 但是每个其他RDBMS在其时间戳字段和时间函数(GETDATE()NOW()等)中支持毫秒或更高的精度.关于SQL-92技术上正确的+1 (5认同)

Byr*_*ock 9

我找到了解决方法!它非常干净,不需要更改任何应用程序代码.这适用于Doctrine,也可以应用于其他ORM.

基本上,将时间戳存储为字符串.

如果日期字符串格式正确,则比较和排序有效.MySQL时间函数将在传递日期字符串时截断微秒部分.如果不需要微秒精度,这是可以的date_diff.

SELECT DATEDIFF('2010-04-04 17:24:42.000000','2010-04-04 17:24:42.999999');
> 0

SELECT microsecond('2010-04-04 17:24:42.021343');
> 21343 
Run Code Online (Sandbox Code Playgroud)

我最后写了一个MicroTimestampable实现这个的类.我只是注释我的字段,actAs:MicroTimestampable并且使用MySQL和Doctrine来实现微时间精度.

Doctrine_Template_MicroTimestampable

class Doctrine_Template_MicroTimestampable extends Doctrine_Template_Timestampable
{
    /**
     * Array of Timestampable options
     *
     * @var string
     */
    protected $_options = array('created' =>  array('name'          =>  'created_at',
                                                    'alias'         =>  null,
                                                    'type'          =>  'string(30)',
                                                    'format'        =>  'Y-m-d H:i:s',
                                                    'disabled'      =>  false,
                                                    'expression'    =>  false,
                                                    'options'       =>  array('notnull' => true)),
                                'updated' =>  array('name'          =>  'updated_at',
                                                    'alias'         =>  null,
                                                    'type'          =>  'string(30)',
                                                    'format'        =>  'Y-m-d H:i:s',
                                                    'disabled'      =>  false,
                                                    'expression'    =>  false,
                                                    'onInsert'      =>  true,
                                                    'options'       =>  array('notnull' => true)));

    /**
     * Set table definition for Timestampable behavior
     *
     * @return void
     */
    public function setTableDefinition()
    {
        if ( ! $this->_options['created']['disabled']) {
            $name = $this->_options['created']['name'];
            if ($this->_options['created']['alias']) {
                $name .= ' as ' . $this->_options['created']['alias'];
            }
            $this->hasColumn($name, $this->_options['created']['type'], null, $this->_options['created']['options']);
        }

        if ( ! $this->_options['updated']['disabled']) {
            $name = $this->_options['updated']['name'];
            if ($this->_options['updated']['alias']) {
                $name .= ' as ' . $this->_options['updated']['alias'];
            }
            $this->hasColumn($name, $this->_options['updated']['type'], null, $this->_options['updated']['options']);
        }

        $this->addListener(new Doctrine_Template_Listener_MicroTimestampable($this->_options));
    }
}
Run Code Online (Sandbox Code Playgroud)

Doctrine_Template_Listener_MicroTimestampable

class Doctrine_Template_Listener_MicroTimestampable extends Doctrine_Template_Listener_Timestampable
{
    protected $_options = array();

    /**
     * __construct
     *
     * @param string $options 
     * @return void
     */
    public function __construct(array $options)
    {
        $this->_options = $options;
    }

    /**
     * Gets the timestamp in the correct format based on the way the behavior is configured
     *
     * @param string $type 
     * @return void
     */
    public function getTimestamp($type, $conn = null)
    {
        $options = $this->_options[$type];

        if ($options['expression'] !== false && is_string($options['expression'])) {
            return new Doctrine_Expression($options['expression'], $conn);
        } else {
            if ($options['type'] == 'date') {
                return date($options['format'], time().".".microtime());
            } else if ($options['type'] == 'timestamp') {
                return date($options['format'], time().".".microtime());
            } else {
                return time().".".microtime();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • -1存储数十个字节而不是4个字节会使你的索引膨胀,谋杀插入和查找速度,除了玩具项目.而且,所有这些强制都是昂贵的,CPU方面的.最后,字符串强制确实*不*提供与本机时间类型的一对一等价(例如,我可以从另一个时间戳中减去一个时间戳,但如果我为它们的字符串表示执行此操作,我总是得到零.鉴于所有这些需要注意的是,只需将spade称为spade并将毫秒精度时间戳存储在适当命名的BIGINT列中,它就会更简单,更安全,更快捷. (5认同)
  • 整数很简单,在每种情况下都要处理的数据要少得多,"Hi There"的处理成本要比1871239471294871290843712974129043192741890274311234要贵得多.整数更具可伸缩性,特别是在用于比较时,除了最短的字符串之外,每次比较的CPU周期更多.索引有所帮助,但它并没有改变你正在处理更多的比较数据,至少在某些时候. (3认同)