为啥在 oracle SQL 中,在条件相差很大的情况下,对同一列执行具有两个不同值的查询所花费的时间

Posted

技术标签:

【中文标题】为啥在 oracle SQL 中,在条件相差很大的情况下,对同一列执行具有两个不同值的查询所花费的时间【英文标题】:Why In oracle SQL the time taken to execute a query with two different values for the same column in where condition differs a lot为什么在 oracle SQL 中,在条件相差很大的情况下,对同一列执行具有两个不同值的查询所花费的时间 【发布时间】:2017-07-18 06:30:25 【问题描述】:

假设我们有一个表员工。我正在这张表上执行以下 2 个查询。

查询 1

select * from employee where email_id = 'admin@xyz.com'

查询 2

select * from employee where email_id = 'abc@xyx.com'

假设我有一个庞大的数据集,我正在其上执行此查询。观察是 Query1 比 Query2 花费的时间要少得多。我还检查了 email_id 列上没有索引。我的假设是服务器以某种方式缓存 Query1 而不是 Query2。如果这是真的,那么我该如何强制服务器缓存 Query2?另外,如果可能的话,我想在不使用索引的情况下优化 Query2。有什么建议吗?

【问题讨论】:

【参考方案1】:

如果没有email_id 上的索引,我们希望两个查询花费相同的时间,即对employees 表执行全表扫描所需的时间。那么为什么一个查询的返回速度会比另一个快得多呢?

假设:

    您的查询确实使用硬编码值而不是绑定变量(即 not select * from employee where email_id = ':1')。 更具执行力的查询实际上是搜索admin 电子邮件地址。

包含文字的查询通常是一件坏事:每个版本都必须进行硬解析,它们会占用游标缓存中的空间。但它们也可能具有不同的执行路径(因为它们是单独解析的)或性能配置文件。这里似乎就是这种情况。如果没有索引,访问路径将是相同的,但总经过的时间可能会因缓存而有所不同。

有两种可能的缓存在起作用。

    意外缓存。包含 admin@xyz.comemployee 记录的块已经在 DB Buffer Cache 中,因此查询不必读取整个表。 故意缓存。有一些通过使用resultset caching 的电子邮件地址查询员工,并且admin@xyz.comemployee 记录缓存在那里。

所以,admin@xyz.com 可以被缓存的两个原因。显然,任何员工都是如此。但似乎人们会更频繁地寻找admin@xyz.com,而不是joe.soap@xyz.com。很简单,(在不知道您的应用程序或数据的情况下),管理员用户被频繁查询,因此比任何其他随机用户更有可能在缓存中。

"如何强制服务器缓存 Query2?"

如果admin 用户被意外缓存——它只是在缓冲区中保持温暖,因为它经常被查询——你真的无能为力。的确,我们可以将表格固定在内存中,但这通常是个坏主意。大多数时候,数据库比我们更好地管理其资源:如果块没有保存在 DB 缓冲区缓存中,那是因为它们不经常使用(假设 DBC 的大小正确)。

如果您的应用程序正在使用结果集缓存,那么您可以显式检索abc@xyz.com 的记录。但是您不能对所有用户都这样做,原因与以前相同:如果经常使用记录,您不希望将记录固定在内存中。

这使我们达到目标。你想在这里优化什么?用户子集的访问时间/或任何用户的访问时间?如果是后者,那么您需要在email_id 上建立索引。

【讨论】:

感谢您提及许多方法的优缺点。我反对索引的原因是我想针对一部分用户优化查询。【参考方案2】:

更多假设:

    一旦您运行 query2,它就会在您的缓冲区缓存中,并且在您第二次运行它时,您会遇到缓存命中,除非您运行查询的时间很晚,并且到那时它已经过期。 您正在使用 cursor_sharing=FORCE 强制系统绑定 您有充分的理由不在 email_id 上使用索引。您真的非常想充分利用索引。 query3、query4等以后呢?

【讨论】:

我在完成第 8 题之前不小心按了enter-| 我故意按下回车键 :) 很好的答案 APC。我投了赞成票。

以上是关于为啥在 oracle SQL 中,在条件相差很大的情况下,对同一列执行具有两个不同值的查询所花费的时间的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Oracle SQL 不允许我们在条件中使用别名?

为啥logit模型和probit模型结果相差很大

在导入Oracle数据库的时候违反唯一约束条件是为啥?要怎么解决?

SQL中 为啥要避免在where后使用'1=1'这种表达式作为部分条件

sql 数据量很大 ,为啥加了order by速度变慢了?

oracle删除分区还在编辑表中显示吗为啥