【发布时间】:2020-06-25 12:51:03
【问题描述】:
我有两个查询,第一个返回所有“打开”记录,其中回复日期尚未过去,第二个返回所有“打开未查看”记录,其中回复日期尚未过去,记录有未被用户查看(表 RfqVieweds 中没有条目)。在这种情况下,用户没有查看 1000 条记录中的任何一条,因此返回了所有 1000 条记录。每个查询的倒数第二行(就在“select new RfqDto()”之前)是两个查询之间的差异。
第一个查询需要大约 45 秒才能返回 1000 条记录。第二个查询大约需要 4 秒才能返回相同的 1000 条记录。为什么?如何让第一个查询与第二个查询一样快?
查询 1:
var groupQuery = Rfqs.Where(rfqs => rfqs.IsPrimaryEmail && (rfqs.Contract != "Upstream"))
.GroupBy(rfqs => new {rfqs.RFQ_RFISeqNum})
.Select(g => new {g.Key.RFQ_RFISeqNum, RfqId = g.Max(p => p.RfqId)});
var query = (from m in groupQuery
join t in Rfqs on new {m.RfqId} equals new {t.RfqId}
join s in RfqSupplementals on new {RfqSeqNumber = t.RFQ_RFISeqNum} equals new {s.RfqSeqNumber}
from rfqViewed in RfqVieweds.Where(rv => rv.RfqId == t.RfqId && rv.SalesRep == salesrep).DefaultIfEmpty()
from rfqStarred in RfqUserStarreds.Where(rs => rs.RfqSeqNumber == t.RFQ_RFISeqNum && rs.SalesRep == salesrep).DefaultIfEmpty()
let rcn = RfqCommentNotifications.Where(r => r.RfqSequenceNum == t.RFQ_RFISeqNum && r.SalesRep == salesrep).Select(d => d.LastViewed).FirstOrDefault()
let ch = RfqsChangeHistories.Where(r => r.RfqRfiSeqNum == t.RFQ_RFISeqNum && chgHistList.Contains(r.Action)).OrderByDescending(r => r.Id).FirstOrDefault()
where (isRfqUser == false || ((t.assignedTo == salesrep || t.secndAssignedTo == salesrep || t.addlAssignedTo == salesrep)
|| (agencies.Contains(t.Agency) && (t.assignedTo == null || t.assignedTo.Trim() == string.Empty)
&& (t.secndAssignedTo == null || t.secndAssignedTo.Trim() == string.Empty) && (t.addlAssignedTo == null || t.addlAssignedTo.Trim() == string.Empty))))
&& (!isRfqUser || t.HouseOpportunity == false)
&& t.IsDeleted == false && t.IsPrimaryEmail
&& (t.ReplyByDate > now || (t.ReplyByDate == null && t.IsManualRfq))
select new RfqDto()
查询 2:
var groupQuery = Rfqs.Where(rfqs => rfqs.IsPrimaryEmail && (rfqs.Contract != "Upstream"))
.GroupBy(rfqs => new {rfqs.RFQ_RFISeqNum})
.Select(g => new {g.Key.RFQ_RFISeqNum, RfqId = g.Max(p => p.RfqId)});
var query = (from m in groupQuery
join t in Rfqs on new {m.RfqId} equals new {t.RfqId}
join s in RfqSupplementals on new {RfqSeqNumber = t.RFQ_RFISeqNum} equals new {s.RfqSeqNumber}
from rfqViewed in RfqVieweds.Where(rv => rv.RfqId == t.RfqId && rv.SalesRep == salesrep).DefaultIfEmpty()
from rfqStarred in RfqUserStarreds.Where(rs => rs.RfqSeqNumber == t.RFQ_RFISeqNum && rs.SalesRep == salesrep).DefaultIfEmpty()
let rcn = RfqCommentNotifications.Where(r => r.RfqSequenceNum == t.RFQ_RFISeqNum && r.SalesRep == salesrep).Select(d => d.LastViewed).FirstOrDefault()
let ch = RfqsChangeHistories.Where(r => r.RfqRfiSeqNum == t.RFQ_RFISeqNum && chgHistList.Contains(r.Action)).OrderByDescending(r => r.Id).FirstOrDefault()
where (isRfqUser == false || ((t.assignedTo == salesrep || t.secndAssignedTo == salesrep || t.addlAssignedTo == salesrep)
|| (agencies.Contains(t.Agency) && (t.assignedTo == null || t.assignedTo.Trim() == string.Empty)
&& (t.secndAssignedTo == null || t.secndAssignedTo.Trim() == string.Empty) && (t.addlAssignedTo == null || t.addlAssignedTo.Trim() == string.Empty))))
&& (!isRfqUser || t.HouseOpportunity == false)
&& t.IsDeleted == false && t.IsPrimaryEmail
&& (rfqViewed == null && (t.ReplyByDate > now || (t.ReplyByDate == null && t.IsManualRfq)))
select new RfqDto()
【问题讨论】:
-
每种情况下返回多少行数据?查询时间是数据库大小和传输数据量的函数。两个查询都必须搜索数据库中的整个表,所以我认为数据库的大小不会导致时间差异。因此,第一个查询返回的数据似乎比第二个查询少。数据正在进入内存,因此我会在两个查询运行时查看任务管理器并检查正在使用的内存量。
-
这不会回答这个问题,但是对于如此复杂和庞大的查询,考虑使用视图或存储过程,以便数据库可以做一些优化。
-
@jdweng 两个查询都返回 1000 行。两个查询之间的唯一区别是第二个检查是否 rfqViewed == null 而第一个不检查。
-
rfqViewed 是一个密钥吗?你是对的,性能上不应该有很大的差异。数据库最近是否进行了碎片整理?
-
@jdweng 不,rfqViewed 是“来自 RfqVieweds 中的 rfqViewed ...DefaultIfEmpty()”的结果。如果 reqViewed 为空,则用户尚未查看该 Rfqs 记录,否则他们已查看该 Rfqs 记录。
标签: c# performance linq-to-sql