我的Linq查询有一个问题,它执行起来非常慢.当我调试并看到翻译后的查询时,我知道问题出在哪里.我的Linq并不是真的做我想要的查询.

这是我现在拥有的Linq:

from doc in context.document
from lasthistory in context.documenthistory
    .Where(x => x.documentid == doc.id)
    .OrderByDescending(x => x.actiondatetime)
    .Take(1)
    .DefaultIfEmpty()
where lasthistory.actiondatetime >= periodFrom
    && lasthistory.actiondatetime < periodTo.AddDays(1)
select new
{
    id = doc.id,
    lastactionby = lasthistory.actionby,
    lastactiondatetime = lasthistory.actiondatetime
}

这是这个linq的翻译查询

SELECT d.id, t0.actionby AS lastactionby, t0.actiondatetime AS lastactiondatetime
FROM dbo.document AS d
LEFT JOIN (
    SELECT t.actionby, t.actiondatetime, t.documentid
    FROM (
        SELECT d0.actionby, d0.actiondatetime, d0.documentid, ROW_NUMBER() OVER(PARTITION BY d0.documentid ORDER BY d0.actiondatetime DESC) AS row
        FROM dbo.documenthistory AS d0
    ) AS t
    WHERE t.row <= 1
) AS t0 ON d.id = t0.documentid
WHERE (t0.actiondatetime >= @__periodFrom_1) AND (t0.actiondatetime < @__AddDays_2)

它try 首先 Select Documenthistory中的所有数据,这就是我的查询执行非常慢的原因.

我现在已经将Linq更新为这样:

from doc in context.document
let lasthistory = context.documenthistory
    .Where(x => x.documentid == doc.id)
    .OrderByDescending(x => x.actiondatetime)
    .FirstOrDefault()
where lasthistory.actiondatetime >= periodFrom
    && lasthistory.actiondatetime < periodTo.AddDays(1)
select new
{
    id = doc.id,
    lastactionby = lasthistory.actionby,
    lastactiondatetime = lasthistory.actiondatetime
}

它比第一个查询执行得更好,但是翻译后的查询有那么多的子查询,有点"难看"

SELECT d.id, 
    (
        SELECT d2.actionby 
        FROM dbo.documenthistory AS d2 
        WHERE d2.documentid = d.id 
        ORDER BY d2.actiondatetime DESC 
        LIMIT 1
    ) AS lastactionby, 
    (
        SELECT d3.actiondatetime 
        FROM dbo.documenthistory AS d3 
        WHERE d3.documentid = d.id 
        ORDER BY d3.actiondatetime DESC 
        LIMIT 1
    ) AS lastactiondatetime
FROM dbo.document AS d
WHERE ((SELECT d0.actiondatetime FROM dbo.documenthistory AS d0 WHERE d0.documentid = d.id ORDER BY d0.actiondatetime DESC LIMIT 1) >= @__periodFrom_1)
    AND ((SELECT d1.actiondatetime FROM dbo.documenthistory AS d1 WHERE d1.documentid = d.id ORDER BY d1.actiondatetime DESC LIMIT 1) < @__AddDays_2)

我想要的查询如下:

SELECT d.id, t.actionby AS lastactionby, t.actiondatetime AS lastactiondatetime
FROM dbo.document AS d
LEFT JOIN LATERAL (
    SELECT d0.actionby, d0.actiondatetime
    FROM dbo.documenthistory AS d0
    WHERE d0.documentid = d.id
    ORDER BY d0.actiondatetime DESC
    FETCH FIRST 1 ROW ONLY
) t ON true
WHERE (t.actiondatetime >= @__periodFrom_1) AND (t.actiondatetime < @__AddDays_2)

在Linq有办法做到这一点吗?或者可能是Linq With Result类似于这个查询?

提前谢谢!

推荐答案

我想到的一个解决办法是使用Distinct.在这种情况下,用窗口函数构建INNER JOIN有点困难. DefaultIfEmpty()删除,根据筛选器您需要CROSS APPLY

var query =
    from doc in context.document
    from lasthistory in context.documenthistory
        .Where(x => x.documentid == doc.id)
        .OrderByDescending(x => x.actiondatetime)
        .Take(1)
        .Select(x => new { x.actionby, x.actiondatetime })
        .Distinct()
    where lasthistory.actiondatetime >= periodFrom
        && lasthistory.actiondatetime < periodTo.AddDays(1)
    select new
    {
        id = doc.id,
        lastactionby = lasthistory.actionby,
        lastactiondatetime = lasthistory.actiondatetime
    };

从另一方面,您可以限制扫描的记录范围

var documents = context.document
    .Where(doc = context.documenthistory.Any(h => h.documentid == doc.id 
        && h.actiondatetime >= periodFrom
        && h.actiondatetime < periodTo.AddDays(1))
    );

var query =
    from doc in documents
    from lasthistory in context.documenthistory
        .Where(x => x.documentid == doc.id)
        .OrderByDescending(x => x.actiondatetime)
        .Take(1)
    where lasthistory.actiondatetime >= periodFrom
        && lasthistory.actiondatetime < periodTo.AddDays(1)
    select new
    {
        id = doc.id,
        lastactionby = lasthistory.actionby,
        lastactiondatetime = lasthistory.actiondatetime
    };

Csharp相关问答推荐

后台线程上的延迟WriteableBitmap写入导致闪烁

将多个enum值传递给MAUI中的转换器参数的XML语法是什么?

Plotly.NET访问互联网时出现异常

Dapper是否可以自动扩展类成员

. NET 8 HttpClient post参数将其情况更改为camel'

. NET在上一个操作完成之前,在此上下文实例上启动了第二个操作

为什么总输出就像12.3没有一分一样?

应用程序启动器,可 Select 物理屏幕

为什么我的表单在绑定到对象时提交空值?

UWP应用程序try 将打包的本机.exe文件加载为C#程序集

在使用Audit.NET的AuditTrail实现中,如何逐月将数据摄取到AzureTableStorage?

在swagger示例中添加默认数组列表

为什么AggregateException的Catch块不足以处理取消?

无法使用[FromForm]发送带有图像和JSON的多部分请求

WPF动态设置弹出窗口水平偏移

如何使用.NET Aspire从Blazor应用程序与GRPC API通信?

C#System.Commandline:如何向命令添加参数以便向其传递值?

如何在.NET Core 8中自定义标识用户模型

ASP.NET核心MVC|如何在控制器方法之间传递值

如何在C#中抽象Vector256;T<;的逻辑以支持不同的硬件配置?