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();
我使用了 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();