只是好奇Skip&Take应该如何工作.我得到了我想在客户端看到的结果,但是当我连接AnjLab SQL Profiler并查看正在执行的SQL时,它看起来好像在查询并将整个行集返回到客户.
是否真的返回所有行,然后在客户端使用LINQ对事物进行排序和缩小?
我尝试过使用Entity Framework和Linq to SQL; 两者似乎都有相同的行为.
不确定它有什么不同,但我在VWD 2010中使用C#.
任何见解?
public IEnumerable<Store> ListStores(Func<Store, string> sort, bool desc, int page, int pageSize, out int totalRecords)
{
var context = new TectonicEntities();
totalRecords = context.Stores.Count();
int skipRows = (page - 1) * pageSize;
if (desc)
return context.Stores.OrderByDescending(sort).Skip(skipRows).Take(pageSize).ToList();
return context.Stores.OrderBy(sort).Skip(skipRows).Take(pageSize).ToList();
}
Run Code Online (Sandbox Code Playgroud)
结果SQL(注意:我排除了Count查询):
SELECT
[Extent1].[ID] AS [ID],
[Extent1].[Name] AS [Name],
[Extent1].[LegalName] AS [LegalName],
[Extent1].[YearEstablished] AS [YearEstablished],
[Extent1].[DiskPath] AS [DiskPath],
[Extent1].[URL] AS [URL],
[Extent1].[SecureURL] AS [SecureURL],
[Extent1].[UseSSL] AS [UseSSL]
FROM [dbo].[tec_Stores] AS [Extent1] …Run Code Online (Sandbox Code Playgroud) 此MSDN文章列出了改善实体框架性能的方法:
https://msdn.microsoft.com/zh-CN/data/hh949853.aspx
其建议(4.3)之一是将未映射对象的属性转换为局部变量,以便EF可以缓存其内部查询计划。
这主意听起来很不错。因此,我通过一个简单的查询对它进行了测试,该查询将查询中的间接属性引用的10,000次迭代与局部变量的性能进行了比较。像这样:
[Fact]
public void TestQueryCaching()
{
const int iterations = 1000;
var quote = new Quote();
using (var ctx = new CoreContext())
{
quote.QuoteId = ctx.Quotes.First().Id;
}
double indirect = 0;
double direct = 0;
10.Times(it =>
{
indirect += PerformCoreDbTest(iterations, "IndirectValue", (ctx, i) =>
{
var dbQuote = ctx.Quotes.First(x => x.Id == quote.QuoteId);
}).TotalSeconds;
direct += PerformCoreDbTest(iterations, "DirectValue", (ctx, i) =>
{
var quoteId = quote.QuoteId;
var dbQuote = ctx.Quotes.First(x => x.Id == quoteId);
}).TotalSeconds;
}); …Run Code Online (Sandbox Code Playgroud) 我试图通过构建表达式树在通用存储库(.NET Core 3.1 + EF Core 3.1)中实现动态过滤器,但生成的 SQL 查询从未参数化(我正在通过"Microsoft.EntityFrameworkCore.Database.Command": "Information"appsettings.json验证生成的查询)并EnableSensitiveDataLogging在 Startup.cs 中)
构建表达式树的代码如下(为了简单起见,仅在此处使用字符串值):
public static IQueryable<T> WhereEquals<T>(IQueryable<T> query, string propertyName, object propertyValue)
{
var pe = Expression.Parameter(typeof(T));
var property = Expression.PropertyOrField(pe, propertyName);
var value = Expression.Constant(propertyValue);
var predicateBody = Expression.Equal(
property,
value
);
var whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new[] { typeof(T) },
query.Expression,
Expression.Lambda<Func<T, bool>>(predicateBody, new ParameterExpression[] { pe })
);
return query.Provider.CreateQuery<T>(whereCallExpression);
}
Run Code Online (Sandbox Code Playgroud)
该方法有效,但值总是合并到生成的 SQL 查询中,我担心它可能会导致 SQL 注入。
以下是生成的查询的示例:
Microsoft.EntityFrameworkCore.Database.Command: Information: Executed DbCommand (33ms) …Run Code Online (Sandbox Code Playgroud) 我遇到以下Entity Framework查询的性能问题:
using (MyEntities context = new MyEntities())
{
return context.Companies
.Single(c => c.CompanyId == company.CompanyId)
.DataFile.Sum(d => d.FileSize);
}
Run Code Online (Sandbox Code Playgroud)
在SQL事件探查器中进行跟踪时,我看到以下SQL命令:
exec sp_executesql N'SELECT
[Extent1].[DataFileID] AS [DataFileID],
[Extent1].[LocalFileName] AS [LocalFileName],
[Extent1].[ServerFileName] AS [ServerFileName],
[Extent1].[DateUploaded] AS [DateUploaded],
[Extent1].[FileSize] AS [FileSize],
[Extent1].[CompanyID] AS [CompanyID]
FROM [dbo].[DataFile] AS [Extent1]
WHERE [Extent1].[CompanyID] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=16
Run Code Online (Sandbox Code Playgroud)
从我所看到的,所有数据文件行都被返回(超过10,000)到内存然后Sum()正在发生.
编辑:
根据Patryk的建议,我已将查询更改为:
using (MyEntities context = new MyEntities())
{
return context.Companies
.Where(c => c.CompanyId == company.CompanyId)
.Select(x => x.DataFiles.Sum(d => d.FileSize))
.Single();
}
Run Code Online (Sandbox Code Playgroud)
SQL跟踪看起来像这样:
SELECT TOP …Run Code Online (Sandbox Code Playgroud)