SQLite-net TableQuery<T>.选择() 性能不佳



将完整的代码块进一步考虑下面的完整代码块,特别是该部分 - 对象初始化(是您所说的?):

new LocalFileInfo() {
  IsFavorite = p.IsFavorite,
  ...
  WhenCrawled = p.WhenCrawled
}

无论如何,是否有将此代码抽象成我可以重复使用的方法,而不是将对象初始化代码复制到每个查询中?我的强烈偏爱是最佳性能的代码,而不是最容易维护的代码(但显然很容易维护是可取的)。

public static List<LocalFileInfo> RecentlyCrawledFiles(int take)
{
    if (take < 1) take = 1;
    List<LocalFileInfo> list = new List<LocalFileInfo>();
        using (SQLite.Net.SQLiteConnection conn = new SQLite.Net.SQLiteConnection(new SQLite.Net.Platform.WinRT.SQLitePlatformWinRT(), sqliteDb))
        {
            // works but is slower.
            // list = (from p in conn.Table<LocalFileInfo>() select p).OrderBy(f => f.WhenCrawled).Take(take).ToList();
            list = (from p in conn.Table<LocalFileInfo>() select new LocalFileInfo() {
                IsFavorite = p.IsFavorite,
                LastModified = p.LastModified,
                Name = p.Name,
                ParentFolder = p.ParentFolder,
                Path = p.Path,
                Size = p.Size,
                SourceId = p.SourceId,
                SourceName = p.SourceName,
                SourceType = p.SourceType,
                WhenCrawled = p.WhenCrawled
            })
            .OrderByDescending(f => f.WhenCrawled)
            .Take(take)
            .ToList();
        };
    return list;
}

我已经看了sqlite-net中的主分支的源代码

该图书馆似乎忽略了您的预测,因此我认为对他们有任何表达不会有任何帮助

例如,请参见SqlLite.cs中的TableQuery<T>

    public IEnumerator<T> GetEnumerator ()
    {
        if (!_deferred)
            return GenerateCommand("*").ExecuteQuery<T>().GetEnumerator();
        return GenerateCommand("*").ExecuteDeferredQuery<T>().GetEnumerator();
    }

每次使用ToList()foreach (var item in query)时,都使用此GetEnumerator()方法。

GenerateCommand()将构建SQL,并且"理论上"支持字符串参数selectList,但是库将永远不会使用此参数

另外,当您进行Select(Expression)时,Libary存储_selector私有属性,但永远不会在GenerateCommand()的调用中使用它,或任何其他调用

此问题已报告

所以,我认为您对性能的最佳选择是:

var list = conn.Table<LocalFileInfo>()
    .OrderByDescending(f => f.WhenCrawled)
    .Take(take)
    .ToList();

您可以在此之后执行Select<T>(),但是该库已经加载了整个实体列表以及每个属性。但是,也许,如果您将这些实体保留在周围(也就是说,ToList()之后的投影不会给您任何即时收益)。

或使用连接对象的Query<T>() ...将带您回到SQL Land。

另外,等待实体框架核心支持Xamarin

路线图中有一个提及:

Xamarin在某些情况下起作用,但尚未被完全测试作为受支持的方案。

对不起,但这是我目前可以提出的最好的:(

编辑:实际上,我相信,如果您执行Select(p => p.IsFavorite)库会惨败,因为它无法映射您的投影(不抨击库,只需抬头)>

而不是

list = (from p in conn.Table<LocalFileInfo>() select new LocalFileInfo() {
            IsFavorite = p.IsFavorite,
            LastModified = p.LastModified,
            Name = p.Name,
            ParentFolder = p.ParentFolder,
            Path = p.Path,
            Size = p.Size,
            SourceId = p.SourceId,
            SourceName = p.SourceName,
            SourceType = p.SourceType,
            WhenCrawled = p.WhenCrawled
        })

怎么样:

list = conn.Table<LocalFileInfo>()

只要您投影所有属性并将其分为同一对象类型,

。如果其中的任何一个都不是真的,那么您实际上可以像这样抽象出来:

public static class FromObjectExtensions
{
  public static IEnumerable<ToObject> ToToObject(this IEnumerable<FromObject> q)
  {
    return q.Select(t=>new ToObject
    {
       Property1=t.Property1,
       ...
    };
  }
}

然后您可以这样称呼:

list = conn.Table<LocalFileInfo>().ToToObject();

只需将ToObjectFromObject替换为您的实际对象类型,然后填写要复制的属性。

这会很好地工作。

     using (SQLite.Net.SQLiteConnection conn = new SQLite.Net.SQLiteConnection(new SQLite.Net.Platform.WinRT.SQLitePlatformWinRT(), sqliteDb))
        {
  var list = conn.Table<LocalFileInfo>().OrderByDesending(f=>f.WhenCrawled).Take(take).ToList();
        };

尽管您的查询有效,但您的重新选择了所选项目,这是没有意义的,

 list = (from p in conn.Table<LocalFileInfo>() select new LocalFileInfo() {
                IsFavorite = p.IsFavorite,
                LastModified = p.LastModified,
                Name = p.Name,
                ParentFolder = p.ParentFolder,
                Path = p.Path,
                Size = p.Size,
                SourceId = p.SourceId,
                SourceName = p.SourceName,
                SourceType = p.SourceType,
                WhenCrawled = p.WhenCrawled
            })

由于这是Linq,您是您的第一个收集对象,并重新创建已经声明的对象的新实例。这是没有意义的,并且高效。

您需要为选择器定义Expression

public static Expression<Func<LocalFileInfo, LocalFileInfo>> MyLocalFileInfoSelector = 
    p => new LocalFileInfo() {
            IsFavorite = p.IsFavorite,
            LastModified = p.LastModified,
            Name = p.Name,
            ParentFolder = p.ParentFolder,
            Path = p.Path,
            Size = p.Size,
            SourceId = p.SourceId,
            SourceName = p.SourceName,
            SourceType = p.SourceType,
            WhenCrawled = p.WhenCrawled
        };

然后您可以在任何地方使用它:

return conn.Table<LocalFileInfo>()
    .Select(MyLocalFileInfoSelector)
    .OrderBy(f => f.WhenCrawled)
    .Take(take)
    .ToList();

最新更新