sql-server - SQL Server LINQ selectman 和 orderby 超时
问题描述
在 SQL Server 2017 Express 中,我有两个级别的主/详细信息关系表,如下所示
CREATE TABLE ADHERANTS(
[ID_ADHERANT] int IDENTITY(1,1) NOT NULL primary key,
[ADH_NOM] [varchar](50) NULL,
[ADH_PRENOM [varchar](50) NULL,
)
CREATE TABLE INSCRIPTIONS(
[ID_INSCRIPTION] [int] IDENTITY(1,1) NOT NULL primary key,
[INS_ID_ADHERANT] [int] NOT NULL /* foreign key for ADHERANTS*/,
[INS_DATE_DEBUT] [date] NULL,
[INS_DUREE] [int] NULL,
[INS_DATE] [date] NULL
);
CREATE TABLE SEANCES(
[ID_SEANCE] [int] IDENTITY(1,1) NOT NULL primary key,
[INS_ID_INSCRIPTION] [int] NULL /* foreign key for INSCRIPTIONS*/,
[SEA_DEBUT] [datetime2](7) NULL,
[SEA_FIN] [datetime2](7) NULL,
[SEA_MANUAL] [int] NULL,
[SEA_MONTANT] [decimal](14, 2) NULL,
[SEA_NOM] [varchar](50) NULL,
);
请注意,外键 inSEANCEs
可以为空。
我想要的是ADHERANTS
根据日期为每个最后的详细记录获取。
在 EF Core 3.1 LINQ 我有这样的事情:
var res = (from adh in _context.ADHERANTS
.Include(x => x.Inscriptions)
.ThenInclude(x => x.Seances)
select new
{
ID_ADHERANT = adh.ID_ADHERANT,
ADH_NOM = adh.ADH_NOM,
ADH_PRENOM = adh.ADH_PRENOM,
LastInscription = (from nn in adh.Inscriptions.OrderByDescending(a => a.INS_DATE_DEBUT)
select new LastInscription()
{
Date = nn.INS_DATE_DEBUT,
Duree = nn.INS_DUREE.Value
}).FirstOrDefault(),
LastSeance = (from mm in adh.Inscriptions.SelectMany(a => a.Seances).OrderByDescending(a => a.SEA_DEBUT)
select mm.SEA_DEBUT).FirstOrDefault()
});
IncrementalItemsSource.LoadItems(res.Skip(baseIndex).Take(10));
哪个有效并产生此 SQL 查询:
exec sp_executesql N'SELECT [a].[ID_ADHERANT], [a].[ADH_NOM], [a].[ADH_PRENOM], [t0].[INS_DATE_DEBUT], [t0].[INS_DUREE], [t0].[c], (
SELECT TOP(1) [s].[SEA_DEBUT]
FROM [INSCRIPTIONS] AS [i]
INNER JOIN [SEANCES] AS [s] ON [i].[ID_INSCRIPTION] = [s].[INS_ID_INSCRIPTION]
WHERE [a].[ID_ADHERANT] = [i].[INS_ID_ADHERANT]
ORDER BY [s].[SEA_DEBUT] DESC)
FROM [ADHERANTS] AS [a]
LEFT JOIN (
SELECT [t].[INS_DATE_DEBUT], [t].[INS_DUREE], [t].[c], [t].[ID_INSCRIPTION], [t].[INS_ID_ADHERANT]
FROM (
SELECT [i0].[INS_DATE_DEBUT], [i0].[INS_DUREE], 1 AS [c], [i0].[ID_INSCRIPTION], [i0].[INS_ID_ADHERANT], ROW_NUMBER() OVER(PARTITION BY [i0].[INS_ID_ADHERANT] ORDER BY [i0].[INS_DATE_DEBUT] DESC) AS [row]
FROM [INSCRIPTIONS] AS [i0]
) AS [t]
WHERE [t].[row] <= 1
) AS [t0] ON [a].[ID_ADHERANT] = [t0].[INS_ID_ADHERANT]
ORDER BY (SELECT 1) desc
OFFSET @__p_0 ROWS FETCH NEXT @__p_0 ROWS ONLY',N'@__p_0 int',@__p_0=10
但是,如果我尝试在此orderby
之上添加一个,则会出现超时异常:
var res = (from adh in _context.ADHERANTS
.Include(x => x.Inscriptions)
.ThenInclude(x => x.Seances)
select new
{
ID_ADHERANT = adh.ID_ADHERANT,
ADH_NOM = adh.ADH_NOM,
ADH_PRENOM = adh.ADH_PRENOM,
LastInscription = (from nn in adh.Inscriptions.OrderByDescending(a => a.INS_DATE_DEBUT)
select new LastInscription()
{
Date = nn.INS_DATE_DEBUT,
Duree = nn.INS_DUREE.Value
}).FirstOrDefault(),
LastSeance = (from mm in adh.Inscriptions.SelectMany(a => a.Seances).OrderByDescending(a => a.SEA_DEBUT)
select mm.SEA_DEBUT).FirstOrDefault()
});
res = res.OrderByDescending(x => x.LastInscription.Date);
IncrementalItemsSource.LoadItems(res.Skip(baseIndex).Take(10));
作为一种解决方法,我尝试修改生成的 SQL 查询并将订单放在那里。
它适用于所有列,除了lastseance
执行时需要永远的列。
exec sp_executesql N'SELECT [a].[ID_ADHERANT], [a].[ADH_NOM], [a].[ADH_PRENOM], [t0].[INS_DATE_DEBUT], [t0].[INS_DUREE], [t0].[c], (
SELECT TOP(1) [s].[SEA_DEBUT]
FROM [INSCRIPTIONS] AS [i]
INNER JOIN [SEANCES] AS [s] ON [i].[ID_INSCRIPTION] = [s].[INS_ID_INSCRIPTION]
WHERE [a].[ID_ADHERANT] = [i].[INS_ID_ADHERANT]
ORDER BY [s].[SEA_DEBUT] DESC)
FROM [ADHERANTS] AS [a]
LEFT JOIN (
SELECT [t].[INS_DATE_DEBUT], [t].[INS_DUREE], [t].[c], [t].[ID_INSCRIPTION], [t].[INS_ID_ADHERANT]
FROM (
SELECT [i0].[INS_DATE_DEBUT], [i0].[INS_DUREE], 1 AS [c], [i0].[ID_INSCRIPTION], [i0].[INS_ID_ADHERANT], ROW_NUMBER() OVER(PARTITION BY [i0].[INS_ID_ADHERANT] ORDER BY [i0].[INS_DATE_DEBUT] DESC) AS [row]
FROM [INSCRIPTIONS] AS [i0]
) AS [t]
WHERE [t].[row] <= 1
) AS [t0] ON [a].[ID_ADHERANT] = [t0].[INS_ID_ADHERANT]
ORDER BY 7 desc /* order by the last seance*/
OFFSET @__p_0 ROWS FETCH NEXT @__p_0 ROWS ONLY',N'@__p_0 int',@__p_0=10
感谢您的任何帮助或建议。
解决方案
用以下方式重写您的查询,我认为它会更快。
var query =
from adh in _context.ADHERANTS
from nn in adh.Inscriptions
.OrderByDescending(a => a.INS_DATE_DEBUT)
.Take(1).DefaultIfEmpty()
from mm in nn.Seances
.OrderByDescending(a => a.SEA_DEBUT)
.Take(1).DefaultIfEmpty()
select new
{
ID_ADHERANT = adh.ID_ADHERANT,
ADH_NOM = adh.ADH_NOM,
ADH_PRENOM = adh.ADH_PRENOM,
LastInscription = new LastInscription
{
Date = nn.INS_DATE_DEBUT,
Duree = nn.INS_DUREE.Value
},
LastSeance = mm.SEA_DEBUT
};
推荐阅读
- kubernetes-health-check - IApplicationBuilder 不包含 UseHealthChecks 的定义
- azure-cosmosdb - Gremlin客户管理
- php - 用 Wordpress 中变量中包含的字符串替换页面内容的挂钩
- css - 无法让滚动捕捉全屏工作
- rdbms - 关系数据库管理系统
- python - 带掩码的 numpy 赋值
- google-sheets - “冻结”谷歌表格列值
- python - 使用 apply 更新 Dataframe 中的行不起作用
- c# - Unity 播放器的射击功能将不起作用
- javascript - 如何在javascript代码中执行另一个nodejs?