我有一个Oracle绑定查询,它在我的C#程序中执行时非常慢(大约2分钟)但在SQL Developer中运行得非常快。它有两个参数符合表索引:
select t.Field1, t.Field2
from theTable t
where t.key1=:key1
and t.key2=:key2
另外,如果我删除绑定变量并创建动态sql,它就像在SQL Developer中一样运行。
有什么建议吗?
顺便说一句,我使用的是ODP。
答案 0 :(得分:2)
如果你在sql developer中用static varibles替换绑定变量,那么你并没有真正运行相同的测试。确保使用绑定变量,如果它也很慢,那么你只需要通过错误的缓存执行计划。更新该表上的统计信息应该可以解决它。
但是如果你实际上在sql开发人员中使用绑定变量,那么继续阅读。 TLDR版本是ODP.net运行的参数有时会导致稍微悲观的方法。首先更新统计数据,但让dba在两种情况下捕获执行计划并进行比较以确认。
我从这里重新发布我的答案:https://stackoverflow.com/a/14712992/852208 我认为你的标题是重复的,但你的标题更简洁一点,因为它标识了查询在sql developer中运行得很快。我会欢迎以另一种方式处理的建议。
将以下内容添加到配置中会将odp.net跟踪信息发送到日志文件:
如果你能及时找到很大的差距,这可能会有所帮助。实际上有些行可能会以较慢的速度进入。
尝试在连接字符串中添加“enlist = false”。我不认为这是一个解决方案,因为它有效地禁用了分布式事务,但它应该可以帮助您隔离问题。您可以从oracle forumns帖子中获取更多信息:
从ODP的角度来看,我们真正能够指出的是 OCI_ATR_EXTERNAL_NAME和OCI_ATR_INTERNAL_NAME时发生此行为 在基础OCI连接上设置(这是在什么时候发生的 distrib tx支持已启用)。
我猜你没看到的是odp.net调用和sql开发者调用之间的执行计划实际上是不同的(意味着服务器上实际发生的性能损失)。让您的dba跟踪连接并从odp.net调用和直接从SQL Developer调用(或使用enlist = false参数)获取执行计划。
如果您确认了不同的执行计划,或者想要在黑暗中进行抢先拍摄,请更新相关表格的统计信息。在我的情况下,这纠正了问题,表明执行计划生成并不真正遵循不同类型的连接的不同规则,但是当涉及分布式事务时,成本分析只是略微更加悲观。查询提示强制执行计划也是一种选择,但仅作为最后的手段。
最后,它可能是一个网络问题。如果你的odp.net安装使用了一个新的oracle home(除非你做了一些安装后的配置,我会期望),那么tnsnames.ora可能会有所不同。 tnsnams中的主机名可能不完全合格,从而导致解析服务器的延迟更多。我只期望在这种情况下第一次尝试(而不是后续的尝试)是缓慢的,所以我不认为这是问题,但我认为应该提到。
答案 1 :(得分:1)
参数是否绑定到C#中的正确数据类型?列key1
和key2
是否有数字,但参数:key1
和:key2
是字符串?如果是这样,查询可能会返回正确的结果,但需要隐式转换。隐式转换就像使用函数to_char(key1)
一样,它阻止了索引的使用。
答案 2 :(得分:1)
还请检查查询返回的行数。如果数字很大,则可能C#正在获取所有行,而另一个工具只能获取第一个口袋。在这种情况下,获取所有行可能需要更多的磁盘读取,这样会更慢。要检查这一点,请尝试在SQL Developer中运行:
SELECT COUNT(*) FROM (
select t.Field1, t.Field2
from theTable t
where t.key1=:key1
and t.key2=:key2
)
上述查询应该获取最大数据库块数。
在这种情况下的好工具是tkprof实用程序,它显示了SQL执行计划,在上面的情况下可能会有所不同(但不应该)。
您也可能意外连接到不同的数据库。在这种情况下,比较查询结果很好。
因为你提出“绑定很慢”我假设你已经检查了没有绑定的SQL而且速度很快。 99%使用绑定使事情变得更好。请检查查询常量是否会快速运行。如果是,则问题可能是key1或key2列的隐式转换(例如,t.key1是一个数字,而:key1是一个字符串)。