Triumph 2021-10-31 22:28 采纳率: 0%
浏览 20

关于 EntityFrameworkCore.Sqlite 效率的问题

一个简单的应用:管理员发布电子文档,若干用户进行签收。


/*
    三个 Model,分别是代表电子文档的 EDoc,代表签收的 Sign,代表用户的 User。
    EDoc 有创建者导航属性是 User 对象,Sign 有签收者导航属性也是 User 对象。
    EDoc 有对应的签收列表导航属性,是 List<Sign> 对象
*/

    [Index("Title")]
    public class EDoc
    {
        [Key]
        public int Id { get; set; }

        [Comment("标题")]
        [StringLength(250), Required]
        public string Title { get; set; }

        [Comment("文档内容")]
        public string Content { get; set; }

        [Comment("发布的用户Id")]
        public int CreaterId { get; set; }

        [Comment("发布的用户")]
        public User Creater { get; set; }

        [Comment("创建时间")]
        public DateTime CreateDateTime { get; set; } = DateTime.Now;

        [Comment("签收列表")]
        public List<Sign> SignList { get; set; } = new();
    }

    public class Sign
    {
        [Key]
        public int Id { get; set; }

        [Comment("所属的 EDoc 对象 Id")]
        public int EDocId { get; set; }

        [Comment("所属的 EDoc 对象")]
        public EDoc EDoc { get; set; }

        [Comment("签收的用户Id")]
        public int SignerId { get; set; }

        [Comment("签收的用户")]
        public User Signer { get; set; }

        [Comment("签收的内容")]
        public string Content { get; set; }

        [Comment("签收时间")]
        public DateTime? SignTime { get; set; }
    }

    [Index("Username")]
    public class User
    {
        [Key]
        public int Id { get; set; }

        [Comment("显示名称")]
        [StringLength(50), Required]
        public string DisplayName { get; set; }

        [StringLength(50), Required]
        public string Username { get; set; }

        [StringLength(128), Required]
        public string Password { get; set; }

        [Comment("是否禁用")]
        public bool Forbid { get; set; }

        [Comment("是否是管理员")]
        public bool IsAdmin { get; set; }
    }

很简单是吧?

用户登录后,要获取用户需要签收的文档对象:

// _db 为 DBContext,curUserId 是当前登录用户的 Id

//主语句:
var _q = _db.EDoc.OrderByDescending(x => x.CreateDateTime).Where(x => x.SignList.Any(y => y.SignerId == curUserId));

//因为要分页,所以先获取总数:
int recordCount = _q.Count();

//接下来再获取分页的列表:
_q.Skip(...).Take(...).ToList();

整个过程的示意代码步骤如上所示。

数据量也不大,EDoc 表 1.5W,Sign 表 10W

当执行 _q.Count() 时生成如下 SQL 语句:

SELECT COUNT(*)
FROM "EDocs" AS "e"
WHERE EXISTS (
    SELECT 1
    FROM "Signs" AS "s"
    WHERE ("e"."Id" = "s"."EDocId") AND ("s"."SignerId" = @curUserId))

DBContext 分别使用 EntityFrameworkCore.SQLServer 和 EntityFrameworkCore.Sqlite
SQLServer 正常,执行时间 50ms 以下,而切换到 Sqlite 时,执行时间竟然将近 1 分 30 秒!

两个数据库都是通过 EntityFrameworkCore.Tools 生成的,结构和数据相同,主键索引等也都正常。

请教各位看看是哪里出现了问题,是不是我的 Linq 语句写得不对,还是需要对 Sqlite 优化的问题?

  • 写回答

2条回答 默认 最新

  • hhhljlishen 2021-10-31 22:46
    关注

    建议对比一下在两个数据库上直接执行sql的执行时间,看看是不是数据库本身的效率差异

    评论

报告相同问题?

问题事件

  • 修改了问题 10月31日
  • 创建了问题 10月31日

悬赏问题

  • ¥15 虚拟机打包apk出现错误
  • ¥30 最小化遗憾贪心算法上界
  • ¥15 用visual studi code完成html页面
  • ¥15 聚类分析或者python进行数据分析
  • ¥15 逻辑谓词和消解原理的运用
  • ¥15 三菱伺服电机按启动按钮有使能但不动作
  • ¥15 js,页面2返回页面1时定位进入的设备
  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝