为什么 DNN 中 DAL2 存储库的默认 GetById() 执行缓慢?

Rac*_*erd 3 sql dotnetnuke data-access-layer dotnetnuke-7

我遇到了一个问题,即 DAL2 存储库的默认 Get() 函数需要几秒钟才能返回结果。当我使用 SQL Server Management Studio 直接查询数据库以获取记录时,查询会快速返回。该函数是一个基本函数,如下所示:

public MyThing Get(string primaryKey)
{
    MyThing myThing;
    using (IDataContext ctx = DataContext.Instance(“DATABASECONN”))
    {
        var rep = ctx.GetRepository<MyThing>();
        myThing = rep.GetById(primaryKey);
    }
    return myThing;
}
Run Code Online (Sandbox Code Playgroud)

该表有 800K+ 条目。

即使启用了缓存设置,该函数在后续执行中也具有相同的执行时间。

为什么这个功能运行缓慢,我该如何加快速度?

Rac*_*erd 5

调查

我在调试代码时在数据库上运行了 SQL Profiler。它表明第一次调用 GetById() 函数时,会执行从数据库表中选择所有记录的查询。主键不会传递到数据库。下次执行 GetById() 函数时,不会查询数据库。结果从缓存的值中返回。

因此,从 GetById() 函数返回的单个记录必须是对表中所有记录的结果集进行某种搜索的结果。此函数如何操作和检索记录的详细信息在编译代码中(此编译代码的源可能可用,但我尚未对其进行调查)。

我查看了执行此代码期间的内存使用情况,以确保 IIS 有足够的数量。IIS 中的设置被设置为允许应用程序池使用可用内存。在调试 w3wp.exe 进程的内存使用量在 0.75 和 1.3 GB 之间波动。有足够的额外 RAM 可用,因此该站点可以在需要时使用更多内存。

这些实验的亮点是:

  • GetById() 函数第一次命中数据库表时,它将选择表中的所有记录。
  • 缓存按预期运行,因此重复查询不会访问数据库。
  • 无论 IIS 有多少可用内存,从缓存中检索结果都需要几秒钟的时间。

解决方案

为了解决这个问题,我改变了我的方法。SELECT时直接使用主键查询数据库,查询返回很快。这导致我使用 DAL2 存储库的 Find() 函数,以便我可以自己指定 SELECT 的条件。
我创建的函数如下所示:

public MyThing Get(string primaryKey)
{
    MyThing myThing = (MyThing)DataCache.GetCache(primaryKey);
    if (myThing != null)   
        return myThing;

    IList<MyThing> myThings;
    using (IDataContext ctx = DataContext.Instance(“DATABASECONN”))
    {
        var rep = ctx.GetRepository<MyThing>();
        myThings = (IList<MyThing>)rep.Find("WHERE myPrimaryKeyFieldName = @0", primaryKey);
        if (myThings.Count > 0)
            DataCache.SetCache(primaryKey, myThings[0]);
    }
    return myThings.Count > 0 ? myThings[0] : null;
}
Run Code Online (Sandbox Code Playgroud)

上面的函数使用 Find() 函数,因此 DAL2 没有实现缓存。为了帮助解决这个问题,我包含了一个自定义缓存技术。使用 SQL Profiler 调查此函数表明,使用相同的 primaryKey 值重复调用该函数未命中数据库,因此缓存的行为符合预期。

以这种方式使用的缓存不会像使用 GetById() 那样减慢执行时间。函数内的 DateTimes 用作计时器,显示以下执行时间。当数据库被命中时,00:00:00.1 或更少。当缓存被命中时,执行时间为 0。这没有进行大规模测试,但在我运行的测试中执行时间是一致的。

结论

上述测试和解决方案表明,应谨慎使用 DAL2 中的 GetById()。根据数据库的大小检索记录不一定是最佳解决方案。如果数据检索执行缓慢,请探索替代方法,例如解决方案中建议的方法。

找出表中 GetById() 不再是最佳解决方案的确切记录数会很有帮助。该数字可能因对象中数据的大小而异。它可能是可计算的,但目前没有等式,因此需要根据具体情况计算。

如果其他人有关于此主题的额外信息,请将其添加到讨论中。