GetAllWithChildren() 性能问题

GetAllWithChildren() performance issue

我使用了 SQLite-Net 扩展 在以下代码中从 Sqlite 数据库检索 1000 行及其子关系:

var list =
SQLiteNetExtensions.Extensions.ReadOperations.GetAllWithChildren<DataModel>(connection);

问题是性能很尴尬。因为GetAllWithChildren()returns一个List不是一个Enumerable。是否存在使用 Sqlite.net 扩展将记录加载到 Enumerable 中的方法?

我现在使用 Sqlite.net 中的 Table() 方法,将获取的行加载到 Enumerable 中,但我不想使用它,因为它不理解关系并且不加载子实体完全没有。

GetAllWithChildren 受到 N+1 problem 的影响,在您的特定情况下,这表现得特别糟糕。你的问题不清楚你在尝试什么,但你可以尝试这些解决方案:

使用GetAllWithChildren中的filter参数:

您可以使用 filter 属性,而不是将所有对象加载到内存然后进行过滤,它在内部执行 Table<T>().Where(filter) 查询,SQLite-Net 将转换为一个 SELECT-WHERE 子句,所以它非常有效:

var list = connection.GetAllWithChildren<DataModel>(d => d.Name == "Jason");

执行查询然后加载关系

如果您查看 GetAllWithChildren code,您会发现它只是执行查询,然后 然后 加载现有关系。您可以自己执行此操作以避免自动加载不需要的关系:

// Load elements from database
var list = connection.Table<DataModel>().Where(d => d.Name == "Jason").toList();
// Iterate elements and load relationships
foreach (DataModel element in list) {
    connection.GetChildren(element, recursive = false);
}

手动加载关系

要完全解决 N+1 问题,您可以使用带有外键的 Contains 过滤器手动获取关系。这在很大程度上取决于您的实体模型,但看起来像这样:

// Load elements from database
var list = connection.Table<DataModel>().Where(d => d.Name == "Jason").toList();
// Get list of dependency IDs
var dependencyIds = list.Select(d => d.DependencyId).toList();
// Load all dependencies from database on a single query
var dependencies = connection.Table<Dependency>.Where(d => dependencyIds.Contains(d.Id)).ToList();
// Assign relationships back to the elements
foreach (DataModel element in list) {
    element.Dependency = dependencies.FirstOrDefault(d => d.Id == element.DependencyId);
}

这个解决方案解决了 N+1 问题,因为它只执行两个数据库查询。

另一种手动加载关系的方法

假设我们有这些 类:

public class Parent
{
    [PrimaryKey, AutoIncrement] public int Id { get; set; }
    public string Name { get; set; }

    public List<Child> children { get; set; }

    public override bool Equals(object obj)
    {
        return obj != null && Id.Equals(((BaseModel) obj).Id);
    }
    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

public class Child
{
    [PrimaryKey, AutoIncrement] public int Id { get; set; }
    public string Name { get; set; }
    public int ParentId { get; set; }
}

提示这些类有一对多的关系。然后它们之间的内部连接将是:

        var parents = databaseSync.Table<Parent>().ToList();
        var children = databaseSync.Table<Child>().ToList();

        List<Parent> parentsWithChildren = parents.GroupJoin(children, parent => parent.Id, child => child.ParentId,
            (parent, children1) =>
            {
                parent.children = children1.ToList();
                return parent;
            }).Where(parent => parent.children.Any()).ToList();