为何继承AuditBase的模型调用db.select<T>查询性能极差?
性能差异原因分析及解决方案
核心原因
继承AuditBase后查询变慢的核心问题出在SQLite对DateTime类型的处理方式:
SQLite没有原生的DateTime数据类型,ServiceStack.OrmLite默认会将AuditBase中包含的CreatedDate、ModifiedDate这类DateTime字段存储为ISO8601格式的字符串。当执行Db.Select<Record>()查询时,ORM需要将每条记录的两个DateTime字符串解析为.NET的DateTime对象,这个字符串解析过程的开销被累积放大——100条记录就需要200次解析,最终导致总耗时大幅上升。
而不继承AuditBase的实体没有这些DateTime字段,无需进行字符串到DateTime的转换,因此查询仅需约8毫秒。
验证方法
你可以通过以下方式确认这个问题:
- 查看SQLite表结构:执行
PRAGMA table_info(Record),检查CreatedDate和ModifiedDate的字段类型是否为TEXT。 - 直接查看存储值:查询表中这两个字段的内容,会看到类似
2024-05-20T14:30:00的字符串格式数据。
解决方案
1. 配置OrmLite用数值类型存储DateTime
在应用启动时,修改SQLite方言的配置,让DateTime以整数形式存储(如Unix时间戳或Ticks),彻底避免字符串解析开销:
var dbFactory = new OrmLiteConnectionFactory(":memory:", SQLiteDialect.Provider); // 使用32位整数存储(适合1970-2038年时间范围) SQLiteDialect.Provider.UseDateTime32(); // 若需要更大时间范围,改用64位整数 // SQLiteDialect.Provider.UseDateTime64();
2. 手动指定字段存储类型
在AuditBase的DateTime属性上添加[CustomField]特性,强制使用整数存储:
public abstract class AuditBase { public string CreatedBy { get; set; } [CustomField("INTEGER")] public DateTime CreatedDate { get; set; } public string ModifiedBy { get; set; } [CustomField("INTEGER")] public DateTime ModifiedDate { get; set; } }
3. 替换DateTime为DateTimeOffset(可选)
如果业务场景允许,将AuditBase中的DateTime类型改为DateTimeOffset,并配合数值存储配置,OrmLite对DateTimeOffset的解析效率也会远高于字符串存储的DateTime。
内容的提问来源于stack exchange,提问作者pvieira
相关产品推荐
相关产品推荐

