【问题标题】:Optimal way to store datetime values in SQLite database (Delphi)在 SQLite 数据库(Delphi)中存储日期时间值的最佳方法
【发布时间】:2011-01-07 13:18:23
【问题描述】:

我将在 SQLite 数据库中存储日期时间值(使用 Delphi 和 DISqlite 库)。 db 的性质是它永远不需要在计算机或系统之间传输,因此互操作性不是一个约束。相反,我的重点是阅读速度。日期时间字段将被索引,我将对其进行大量搜索,并按顺序读取数千个日期时间值。

由于 SQLite 没有明确的日期时间值数据类型,因此有多种选择:

  • 使用 REAL 数据类型并直接存储 Delphi 的 TDateTime 值:最快,加载时无需从字符串转换;不可能使用诸如 SQLiteSpy 之类的数据库管理器来调试日期,因为日期不是人类可读的。无法使用 SQLite 日期函数 (?)

  • 使用简单的字符串格式,例如YYYYMMDDHHNNSS:需要转换,但在 CPU 上相对容易(无需扫描分隔符),数据是人类可读的。仍然无法使用 SQLite 日期函数。

  • 做点别的。建议做什么?

我已经阅读了http://www.sqlite.org/lang_datefunc.html,但没有提及要使用什么数据类型,而且,由于没有接受过正式的编程教育,我不太了解朱利安日期的关注点。为什么要额外转换?我会大量阅读这些值,因此字符串和 TDateTime 之间的任何额外转换都会增加大量成本。

【问题讨论】:

  • 我也见过stackoverflow.com/questions/1933720/…,但它没有回答我关于最佳方式是什么的问题,或者是否有真正令人信服的理由更喜欢 ISO 字符串格式(和相关的转换)直接插入 Delphi 的 TDateTime 值。

标签: delphi datetime sqlite format


【解决方案1】:

您可以使用一种 SQLite 支持的字符串格式,例如。 YYYY-MM-DD HH:MM:SS.SSS

它就像YYYYMMDDHHNNSS 一样简单——您仍然不需要扫描分隔符,因为所有数字都是固定长度的——并且您将获得 SQLite 日期函数支持。

如果您需要 SQLite 日期函数支持,我会采用该方法。

如果没有,我建议使用 REAL 值。您仍然可以将它们相互比较(数字越大时间越晚),并分别考虑日期和时间(分别在小数点之前和之后),而无需转换为 TDateTime。

【讨论】:

  • 我在 CSV 和其他数据库中大量使用了这个 ASCII 解决方案,我会这样做。此外,SQLite 日期函数可以工作。双赢。
【解决方案2】:

一种折衷方案是坚持使用 REAL 值,但使用 Delphi 的 DateTimeToJulianDate 将它们存储为儒略日期。这样,它们的阅读速度仍然很快,在会话中几乎没有性能损失,而且它们仍然采用在 Delphi 之外有意义的格式。

【讨论】:

  • 我之前使用的是 REAL 值,一个缺点是数据库中的值不是人类可读的,这在使用 SQL 工具进行调试/分析时很不方便。
【解决方案3】:

为此,我通常使用整数数据类型并存储 Unix 时间戳值(例如 eq # seconds since 1-1-2000)。从 TDateTime 计算此 t/ 等于乘以/除以 86400 并为“since”添加一个常数。

如果您需要更高的精度,您可以将 DateTime 用作增量为 100 ns 的 FILETIME(例如 int64)。 SysUtils 中有用于此的转换例程,并且您的时间戳存储在 UTC 中。

【讨论】:

    【解决方案4】:

    如果您关心的只是数据库级别的人类可读格式,您可以存储两个单独的字段,例如:

    DELPHI_DATE 实数(如果可能,双数,但我不知道 SQLite),已编入索引。您的所有程序化查询和比较都应使用此字段。

    HUMAN_READABLE_DATE Varchar(23),格式为 'YYYY-MM-DD HH:MM:SS.SSS'。也许索引(如果真的有必要)。大多数人工输入查询应包含此字段,并且您可以使用(如其他人所说)SQLite 日期函数。

    它有一些缺点:

    • 数据库和网络流量的空间消耗增加,
    • 插入操作需要更多时间,因为需要转换,
    • 如果在程序外更新,值之间不会自动同步

    是否适合您的特定需求,由您决定。

    【讨论】:

      【解决方案5】:

      我不知道这个答案是否适用于 DISqlite 库,但是...
      下面是一些代码,说明了使用 Delphi 2010 和 Tim Anderson 的 SQLite3 包装器对我有用的方法。

      创建字段的 SQL:

        sSQL :=  'CREATE TABLE [someTable] (' +
                  '  [somefield1] VARCHAR(12),' +
                  '  [somefield2] VARCHAR(12),' +
                  '  [myDateTime] DATETIME );';
      

      用于填充字段的 SQL:

       sSQL := 'INSERT INTO someTable(somefield1, somefield2, myDateTime)' + 
               '  VALUES ( "baloney1", "baloney2","' + FloatToStr(Now) + '");';
      

      从字段中检索数据的示例:

      var
      sDBFilePathString: string;
      sl3tbl: TSqliteTable;
      fsldb : TSQLiteDatabase;
      FromdbDTField : TDateTime;
      
      begin
         ...
         ... 
          fsldb := TSQLiteDatabase.Create(sDBFilePathString); 
          sl3tbl := fsldb.GetTable('SELECT * FROM someTable');
          FromdbDateTime := StrToFloat(sl3tbl.FieldAsString(sl3tbl.FieldIndex['myDateTime']));
          Showmessage('DT: ' + DateTimeToStr(FromdbDTField));
      end;
      

      结果:

      **DT: 10/10/2013 1:09:53 AM**
      

      就像我在第一行提到的 - 我不知道这是否适用于 DISqlite 库,但如果它确实是一种非常干净的处理方式。 我把它留给你,让事情变得更漂亮或更优雅。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-05-27
        • 2011-04-16
        • 2018-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多