我正在尝试使用 LINQ to SQL 查询语法查询一天中每小时打开的票证数量。我得到了正确的结果,但是生成的 SQL 与我预期的有很大不同。
我在 LinqPad 上的查询是:
int[] hours = Enumerable.Range(0, 24).ToArray();
DateTime Nov = new DateTime(2023, 11, 14);
var q = (
from h in hours
join t in Tickets on h equals t.CreatedAt.Hour into ht
from lht in ht.Where(tk => (tk.CreatedAt.Date == Nov.Date) && (tk.OrganizationId == 1) && (!tk.IsDeleted) ).DefaultIfEmpty()
group lht by h into ftable
select new {id = ftable.Key, count = ftable.Count(f => f != null)}
).Dump();
由于某种原因,生成的 SQL 查询是整个门票表的简单选择:
SELECT `t`.`Id`, `t`.`ClosedAt`, `t`.`CreatedAt`, `t`.`CreatedBy`, `t`.`isDeleted`, `t`.`LastUpdatedAt`, `t`.`LastUpdatedBy`, `t`.`LinkedSessionId`, `t`.`OrganizationId`, `t`.`Priority`, `t`.`PropertyId`, `t`.`PublicId`, `t`.`RecipientId`, `t`.`Source`, `t`.`Status`, `t`.`Subject`, `t`.`TicketId`
FROM `tickets` AS `t`
我不确定这里发生了什么,但看起来
join t in Tickets on h equals t.CreatedAt.Hour into ht
行只是简单地获取整个表,然后在内存中进行其余的分组和where条件,这是非常低效的。
是否有人遇到过类似的事情或者可以解释这种行为,以及如何强制它在生成的 sql 中生成带有 WHERE 和 GROUP BY 子句的正常 LEFT JOIN。
如果您从本地集合开始查询,则意味着您将使用
Enumerable
扩展,这意味着将整个表加载到内存中并且不会应用任何过滤器。
我建议对服务器上的现有数据进行分组,然后通过错过的时间来丰富数据:
DateTime Nov = new DateTime(2023, 11, 14);
var startDate = Nov;
var endDate = startDate.AddDays(1);
var query =
from t in Tickets
where t.CreatedAt >= startDate && t.CreatedAt < endDate
group t by t.CreatedAt.Hour into g
select new
{
id = g.Key,
count = g.Count()
};
int[] hours = Enumerable.Range(0, 24).ToArray();
var enriched =
from h in hours
join d in query on h equals d.id into gj
from d in gj.DefaultIfEmpty()
select new
{
id = h,
count = d == null ? 0 : d.count
};
enriched.Dump();