GetAllWithChildren()性能问题

a.t*_*aby 1 c# sqlite xamarin sqlite-net sqlite-net-extensions

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

var list =
SQLiteNetExtensions.Extensions.ReadOperations.GetAllWithChildren<DataModel>(connection);
Run Code Online (Sandbox Code Playgroud)

问题是表现很尴尬.因为GetAllWithChildren()返回List而不是Enumerable.是否存在使用Sqlite.net扩展将记录加载到Enumerable的任何方法?

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

red*_*t84 7

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

使用以下filter参数GetAllWithChildren:

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

var list = connection.GetAllWithChildren<DataModel>(d => d.Name == "Jason");
Run Code Online (Sandbox Code Playgroud)

执行查询,然后加载关系

如果你查看GetAllWithChildren代码,你会发现它只是执行查询然后加载现有的关系.您可以自己做,以避免自动加载不需要的关系:

// 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);
}
Run Code Online (Sandbox Code Playgroud)

手动加载关系

要完全解决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);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这是最有效的方式,是的.将"内存中"过滤器转换为SQL',其中'语句通常更有效.由于加载实体树时出现N + 1问题,您的情况更糟. (2认同)