c# - EF 核心与 Devart 提供程序,光标共享问题
问题描述
我们的 WEB API 使用了大约 2 年,突然一些高负载使我们的一个 API 工作非常缓慢,DBA 说这是因为游标共享问题,这本身就是因为 NLS 参数正在改变。
API 仅使用 EF Core 2.1 和 Devart 提供程序 (9.6.621) 供 oracle 进行简单查询:
public IQueryable<NotificationEndUserViewEntity> InboxQuerable(string userId, string clientId)
{
var client = _dbContext.Clients.FirstOrDefault(x => x.ClientId == clientId);
var inboxQuerable = _dbContext
.NotificationsUserView
.Where(nots =>
!nots.IsCancelled &&
!nots.IsDeleted &&
nots.IsOutGoing &&
nots.ActiveFrom < DateTime.Now &&
(nots.ActiveTill == null || nots.ActiveTill > DateTime.Now) &&
nots.ClientId == client.Id &&
nots.RecipientId == userId);
return inboxQuerable.AsNoTracking();
}
var firstMastRead = await InboxQuerable(userId, clientId)
.OrderByDescending(x => x.ActiveFrom)
.FirstOrDefaultAsync(x => x.IsMustRead && !x.IsRead);
这里有什么问题?DBA 说这个查询有超过 300-500 个游标。是参数绑定问题,EF 还是 Devart(我们使用旧版本,但在更新之前我们必须确定),如何控制 NLS 设置?
更新:DBA 看到的。
SELECT nots.Id,
nots.ActiveFrom,
nots.ActiveTill,
nots.BodyEn,
nots.BodyKa,
nots.ClientId,
nots.HasAttachment,
nots.IsCancelled,
nots.IsDeleted,
nots.IsMustRead,
nots.IsNoReplay,
nots.IsOutGoing,
nots.IsRead,
nots.RecipientId,
nots.SubjectEn,
nots.SubjectKa
FROM VW_USER_NOTIFICATIONS nots
WHERE ( ( ( ( ( ( (nots.IsCancelled = :"SYS_B_0")
AND (nots.IsDeleted = :"SYS_B_1"))
AND (nots.IsOutGoing = :"SYS_B_2"))
AND (nots.ActiveFrom < CURRENT_DATE))
AND ( nots.ActiveTill IS NULL
OR (nots.ActiveTill > CURRENT_DATE)))
AND (nots.ClientId = :p__client_Id_0))
AND (nots.RecipientId = :p__userId_1))
AND ((nots.IsMustRead = :"SYS_B_3") AND (nots.IsRead = :"SYS_B_4"))
ORDER BY nots.ActiveFrom DESC FETCH FIRST :"SYS_B_5" ROWS ONLY
这是由 Linq 生成的:
SELECT
nots.Id,
nots.ActiveFrom,
nots.ActiveTill,
nots.BodyEn,
nots.BodyKa,
nots.ClientId,
nots.HasAttachment,
nots.IsCancelled,
nots.IsDeleted,
nots.IsMustRead,
nots.IsNoReplay,
nots.IsOutGoing,
nots.IsRead,
nots.RecipientId,
nots.SubjectEn,
nots.SubjectKa FROM VW_USER_NOTIFICATIONS nots WHERE (((((((nots.IsCancelled = 0)
AND (nots.IsDeleted = 0))
AND (nots.IsOutGoing = 1))
AND (nots.ActiveFrom < CURRENT_DATE))
AND (nots.ActiveTill IS NULL OR (nots.ActiveTill > CURRENT_DATE)))
AND (nots.ClientId = :p__client_Id_0))
AND (nots.RecipientId = :p__userId_1))
AND ((nots.IsMustRead = 1) AND (nots.IsRead = 0)) ORDER BY nots.ActiveFrom DESC FETCH FIRST 1 ROWS ONLY
解决方案
//DBA 说这个查询有超过 300-500 个游标。//
作为开发人员,您(恕我直言)......应该始终查看生成的 SQL,尤其是在创建非平凡查询时。
所以这里有一个面包屑来连接它。
这将允许您共享生成的 SQL。
如果您记录并研究您的日志,您希望非常注意以下评论,例如
“无法翻译,将在当地进行评估。”
我的猜测是,由于这个问题,您可能会获得超多游标。
在我的示例中,您可以在下面的面包屑中看到这些警告。
https://github.com/granadacoder/oracle-ef-issues-demo/blob/master/src/ConsoleOne/Program.cs#L160
============================
另外,我注意到了这一点:
nots.ActiveTill > DateTime.Now
尝试创建一个局部变量并使用它.......与拥有 DateTime.Now “内联”。
例子:
DateTime myNow = DateTime.Now;
然后
nots.ActiveTill > myNow
我不记得确切,但那个“内联”的东西正在响起我内心的声音。
稍微偏离主题,考虑使用 IDateTimeProvider 与直接使用 DateTime。
https://www.nuget.org/packages/Chronos.Abstractions/1.0.2
============================
另外,我没有使用过 Devart 提供程序,但是 Oracle.EF 驱动程序遇到了一个巨大的问题,即我所说的“列别名错误”。
我在这里的例子:
https://github.com/granadacoder/oracle-ef-issues-demo
错误报告在这里:
https://support.oracle.com/rs?type=bug&id=31234903
https://support.oracle.com/rs?type=bug&id=31240915
(“讨论”在这里: https ://community.oracle.com/thread/4327311 )
附言
Oracle 3.1 EF 驱动程序看起来比 2.1 版本好很多。我认为 3.1 的认证过程一定要严格得多。也许是 Oracle 3.1 EF 驱动程序花了这么长时间的原因(我猜想)(我猜因为它处于测试阶段,它实际上“花了这么长时间”).. 走出门。
https://www.nuget.org/packages/Oracle.EntityFrameworkCore/
当然,这可能就是为什么 devart 是一个受欢迎的选择。
总之。
知道如何查看生成的 SQL。
了解如何调试/跟踪日志以获取有关生成的 SQL 的警告。
调整您的 C# 代码以避免出现警告。
ORM 有时是“善变的”。归根结底,他们创建了 SQL,但需要批判性地查看该 SQL。
推荐阅读
- javascript - 防止元素收缩
- c++ - 从内部系统调用生成调用堆栈
- mysql - 用其他字段唯一值的序号更新表中的字段
- ruby-on-rails - Rails 5 - 访问关联表中的外键以外的另一列
- c# - 如何修复 UIPickerViewModel 中的 Override 方法 GetTitle
- vba - 删除使用 VBA 保存为 msg 文件的电子邮件?
- java - 变量表示的Java对象类型
- c++ - 在 C++ 中调用作为参数传递的同一模板函数的两个版本
- apache-spark - 通过 PySpark 加载数据并执行连接时面临的问题
- bash - 如何在bash中加入一个文件夹中的两个连续文件(1和2、3和4,...)