为啥在 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.com
的 employee
记录的块已经在 DB Buffer Cache 中,因此查询不必读取整个表。
故意缓存。有一些通过使用resultset caching 的电子邮件地址查询员工,并且admin@xyz.com
的employee
记录缓存在那里。
所以,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数据库的时候违反唯一约束条件是为啥?要怎么解决?