Linq 和 SQL 查询比较

发布于 2024-10-29 18:36:53 字数 1843 浏览 0 评论 0原文

我有这个 SQL 查询:

SELECT Sum(ABS([Minimum Installment])) AS SumOfMonthlyPayments FROM tblAccount 
INNER JOIN tblAccountOwner ON tblAccount.[Creditor Registry ID] = tblAccountOwner.
[Creditor Registry ID] AND tblAccount.[Account No] = tblAccountOwner.[Account No] 
WHERE (tblAccountOwner.[Account Owner Registry ID] = 731752693037116688)
 AND (tblAccount.[Account Type] NOT IN 
('CA00', 'CA01', 'CA03', 'CA04', 'CA02', 'PA00', 'PA01', 'PA02', 'PA03', 'PA04'))
AND (DATEDIFF(mm, tblAccount.[State Change Date], GETDATE()) <= 
4 OR tblAccount.[State Change Date] IS NULL)
AND ((tblAccount.[Account Type] IN ('CL10','CL11','PL10','PL11')) OR
CONTAINS(tblAccount.[Account Type], 'Mortgage')) AND (tblAccount.[Account Status ID] <> 999)   

我创建了一个 Linq 查询:

var ownerRegistryId = 731752693037116688;
var excludeTypes = new[]
{
    "CA00", "CA01", "CA03", "CA04", "CA02",
    "PA00", "PA01", "PA02", "PA03", "PA04"
};

var maxStateChangeMonth = 4;
var excludeStatusId = 999;
var includeMortgage = new[] { "CL10", "CL11", "PL10", "PL11" };

var sum = (
    from account in context.Accounts
    from owner in account.AccountOwners
    where owner.AccountOwnerRegistryId == ownerRegistryId
    where !excludeTypes.Contains(account.AccountType)
    where account.StateChangeDate == null ||
       (account.StateChangeDate.Month - DateTime.Now.Month)
            <= maxStateChangeMonth
    where includeMortgage.Contains(account.AccountType) ||
        account.AccountType.Contains("Mortgage")
    where account.AccountStatusId != excludeStatusId
    select account.MinimumInstallment).ToList()
    .Sum(minimumInstallment =>
        Math.Abs((decimal)(minimumInstallment)));

return sum;

它们相等/相同吗?我在数据库中没有记录,所以我无法确认它们是否相等。在 SQL 中有括号(),但在 Linq 中我没有使用它们,所以可以吗?

请建议。

I have this SQL query:

SELECT Sum(ABS([Minimum Installment])) AS SumOfMonthlyPayments FROM tblAccount 
INNER JOIN tblAccountOwner ON tblAccount.[Creditor Registry ID] = tblAccountOwner.
[Creditor Registry ID] AND tblAccount.[Account No] = tblAccountOwner.[Account No] 
WHERE (tblAccountOwner.[Account Owner Registry ID] = 731752693037116688)
 AND (tblAccount.[Account Type] NOT IN 
('CA00', 'CA01', 'CA03', 'CA04', 'CA02', 'PA00', 'PA01', 'PA02', 'PA03', 'PA04'))
AND (DATEDIFF(mm, tblAccount.[State Change Date], GETDATE()) <= 
4 OR tblAccount.[State Change Date] IS NULL)
AND ((tblAccount.[Account Type] IN ('CL10','CL11','PL10','PL11')) OR
CONTAINS(tblAccount.[Account Type], 'Mortgage')) AND (tblAccount.[Account Status ID] <> 999)   

I have created a Linq query:

var ownerRegistryId = 731752693037116688;
var excludeTypes = new[]
{
    "CA00", "CA01", "CA03", "CA04", "CA02",
    "PA00", "PA01", "PA02", "PA03", "PA04"
};

var maxStateChangeMonth = 4;
var excludeStatusId = 999;
var includeMortgage = new[] { "CL10", "CL11", "PL10", "PL11" };

var sum = (
    from account in context.Accounts
    from owner in account.AccountOwners
    where owner.AccountOwnerRegistryId == ownerRegistryId
    where !excludeTypes.Contains(account.AccountType)
    where account.StateChangeDate == null ||
       (account.StateChangeDate.Month - DateTime.Now.Month)
            <= maxStateChangeMonth
    where includeMortgage.Contains(account.AccountType) ||
        account.AccountType.Contains("Mortgage")
    where account.AccountStatusId != excludeStatusId
    select account.MinimumInstallment).ToList()
    .Sum(minimumInstallment =>
        Math.Abs((decimal)(minimumInstallment)));

return sum;

Are they equal/same ? I dont have records in db so I cant confirm if they are equal. In SQL there are brackets() but in Linq I didnt use them so is it ok?

Please suggest.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

长不大的小祸害 2024-11-05 18:36:54

可能存在性能差异:

SQL 查询直接从数据库服务器向执行查询的客户端返回单个数字 (SELECT Sum...)。

在 LINQ 查询中,中间有一个贪婪运算符 (.ToList()):

var sum = (...
    ...
    select account.MinimumInstallment).ToList()
    .Sum(minimumInstallment =>
        Math.Abs((decimal)(minimumInstallment)));

这意味着 SQL 服务器上的查询不包含 .Sum 操作。该查询返回一个(可能很长?)MinimumInstallments 列表。然后在客户端的内存中执行.Sum运算。

因此,您可以在 .ToList() 之后有效地从 LINQ to Entities 切换到 LINQ to Objects。

顺便说一句:您能否检查此处的上一个问题中的最后一个提案,这将避免.ToList() 在此查询上(如果建议有效),因此更接近 SQL 语句。

There can be a performance difference:

The SQL query returns a single number (SELECT Sum...) directly from the database server to the client which executes the query.

In your LINQ query you have a greedy operator (.ToList()) in between:

var sum = (...
    ...
    select account.MinimumInstallment).ToList()
    .Sum(minimumInstallment =>
        Math.Abs((decimal)(minimumInstallment)));

That means that the query on the SQL server does not contain the .Sum operation. The query returns a (potentially long?) list of MinimumInstallments. Then the .Sum operation is performed in memory on the client.

So effectively you switch from LINQ to Entities to LINQ to Objects after .ToList().

BTW: Can you check the last proposal in your previous question here which would avoid .ToList() on this query (if the proposal should work) and would therefore be closer to the SQL statement.

揽月 2024-11-05 18:36:53

我们无法对此发表任何评论,因为您没有向我们展示 DBML。模型和数据库之间映射的实际定义对于能够了解其执行方式非常重要。

但在将 DBML 添加到您的问题之前:我们不是来完成您的工作的,因此这里有两个提示来确定它们是否相等:

  1. 在数据库中插入数据并运行查询。
  2. 使用 SQL 探查器并查看 LINQ 提供程序在幕后执行了什么查询。

如果您有任何更具体的问题需要询问,我们将非常乐意提供帮助。

It is not possible for us to say anything about this, because you didn't show us the DBML. The actual definition of the mapping between the model and the database is important to be able to see how this executes.

But before you add the DBML to your question: we are not here to do your work, so here are two tips to find out whether they are equal or not:

  1. Insert data in your database and run the queries.
  2. Use a SQL profiler and see what query is executed by your LINQ provider under the covers.

If you have anything more specific to ask, we will be very willing to help.

人海汹涌 2024-11-05 18:36:53

如有必要,括号将由 LINQ 提供程序生成。
检查 LINQ 查询是否等于初始 SQL 查询的最简单方法是像@Atanas Korchev 建议的那样记录它。
但是,如果您使用的是实体框架,则没有 Log 属性,但您可以尝试将查询转换为 ObjectQuery,然后调用 ToTraceString 方法:
string sqlQuery = (sum as ObjectQuery).ToTraceString();
UPD。 ToTraceString 方法需要一个 ObjectQuery 实例来进行跟踪,并且 ToList() 调用已经执行了具体化,因此无需跟踪任何内容。以下是更新后的代码:

var sum = (
from account in context.Accounts
from owner in account.AccountOwners
where owner.AccountOwnerRegistryId == ownerRegistryId
where !excludeTypes.Contains(account.AccountType)
where account.StateChangeDate == null ||
   (account.StateChangeDate.Month - DateTime.Now.Month)
        <= maxStateChangeMonth
where includeMortgage.Contains(account.AccountType) ||
    account.AccountType.Contains("Mortgage")
where account.AccountStatusId != excludeStatusId
select account.MinimumInstallment);
string sqlQuery = (sum as ObjectQuery).ToTraceString();  

请注意,此代码不会执行实际查询,它仅可用于测试目的。
查看这篇文章 如果您对可用于生产的日志记录实施感兴趣。

The brackets will be generated by LINQ provider, if necessary.
The simplest way to check if the LINQ query is equal to the initial SQL query is to log it like @Atanas Korchev suggested.
If you are using Entity Framework, however, there is no Log property, but you can try to convert your query to an ObjectQuery, and call the ToTraceString method then:
string sqlQuery = (sum as ObjectQuery).ToTraceString();
UPD. The ToTraceString method needs an ObjectQuery instance for tracing, and the ToList() call already performs materialization, so there is nothing to trace. Here is the updated code:

var sum = (
from account in context.Accounts
from owner in account.AccountOwners
where owner.AccountOwnerRegistryId == ownerRegistryId
where !excludeTypes.Contains(account.AccountType)
where account.StateChangeDate == null ||
   (account.StateChangeDate.Month - DateTime.Now.Month)
        <= maxStateChangeMonth
where includeMortgage.Contains(account.AccountType) ||
    account.AccountType.Contains("Mortgage")
where account.AccountStatusId != excludeStatusId
select account.MinimumInstallment);
string sqlQuery = (sum as ObjectQuery).ToTraceString();  

Please note that this code will not perform the actual query, it is usable for testing purposes only.
Check out this article if you are interested in ready-for-production logging implementation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文