在不创建索引的情况下,我可以采取哪些措施来提高 Oracle 查询的查询性能?

这是我试图运行得更快的查询:

SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a,
itempages b,
keygroupdata c
WHERE a.ItemType IN (112,115,189,241)
AND a.ItemNum = b.ItemNum
AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC

这些列都没有索引,每个表都包含数百万条记录。不用说,执行查询需要超过 3 分半钟的时间。这是生产环境中的第三方数据库,我不允许创建任何索引,因此必须对查询本身进行任何性能改进。

谢谢!

有帮助吗?

解决方案

首先,我将查询重写为ANSI标准:

SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a
INNER JOIN itempages b ON b.ItemNum = a.ItemNum
INNER JOIN keygroupdata c ON c.ItemNum = b.ItemNum
WHERE a.ItemType IN (112,115,189,241)
ORDER BY a.DateStored DESC

这使得阅读和理解正在发生的事情变得更加容易。它还可以帮助您避免错误(即交叉加入),这可能会导致真正的大问题。然后我会得到解释计划,看看DBMS在查询中做了些什么。它试图使用一些索引吗?是否正确加入了表格?

然后我会查看我正在使用的表,看看是否有任何已存在的索引可用于更快地查询。最后,正如其他人一样,我建议我删除Order By子句,然后在代码中执行此操作。

其他提示

要求第三方为其连接列编制索引,因为它们应该首先完成!如果没有索引,甲骨文除了蛮力之外别无他法。

您可能想尝试在任何这些表上创建物化视图。然后,您可以在物化视图上创建一个索引,以帮助加快查询速度(然后查询物化视图而不是原始表)。

当然,如果您的基础表已更新,则需要刷新视图和索引。

首先看执行计划。它是否准确反映了查询执行的每个阶段要检索的行数?谓词“a.ItemType IN (112,115,189,241)”的选择性如何?执行计划是否显示临时磁盘空间用于连接或排序的任何使用?

实际上,也许您可​​以修改问题以包含执行计划。

还要确保没有禁用散列连接,这在 OLTP 调整的系统中有时会出现这种情况,因为它们是 Oracle 中等连接批量数据的最有效方法。它们应该出现在执行计划中。

您可以在加入表格之前尝试过滤项目类型,如下所示。

如果您在9i之前运行Oracle,这有时会带来惊人的好处。

select 
  c.claimnumber,
  a.itemdate, 
  c.dtn,
  b.filepath
from 
  (
  select itemdate
  from items it
  where it.itemtype in(112,115,189,241)
  ) a
  itempages b,
  keygroupdata c
where a.itemnum = b.itemnum
  and b.itemnum = c.itemnum

你也可以尝试添加提示/ + RULE /或/ + ORDERED /来看看会发生什么......再次,特别是对于旧版本,这些有时会给出了令人惊讶的结果。

SELECT /*+RULE*/
  c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM
  items a,
  itempages b,
  keygroupdata c
WHERE a.ItemType IN (112,115,189,241)
  AND a.ItemNum = b.ItemNum
  AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC

如果查询输入是常量或可预测的( itemType IN(...)),那么另一种方法是每天运行一次或两次查询并将结果存储在本地表,适当的指数。

然后,您可以使代价高昂的查询“离线”,并为交互式查询提供更快/更好的结果。

这是您经常运行的查询吗?似乎数据库所有者有兴趣创建加速此查询所需的索引。运行查询的3.5分钟必须对其生产环境产生一些影响!

另外,他们是否一直在运行表的更新统计信息?这可能会提高性能,因为连接顺序是根据表的统计信息计算的。

顺便说一下,你有什么可以做的?刚读过?如果您可以创建临时表并在其上放置索引,我可以考虑制作表的临时副本,索引这些表,然后使用临时副本执行索引辅助连接。

我知道这个帖子已经很老了,但对于搜索引擎,我仍然想提供一个可以在oracle上运行的替代解决方案,并且根据数据可能要快得多。

with a as (
  select 
    * 
  from 
    items 
  where 
    ItemType IN (112,115,189,241)
)
SELECT 
  c.ClaimNumber
  , a.ItemDate
  , c.DTN, b.FilePath
FROM 
  a,
  itempages b,
  keygroupdata c
WHERE 
  a.ItemNum = b.ItemNum
  AND b.ItemNum = c.ItemNum
ORDER BY 
  a.DateStored DESC

您还可以在 WITH 子句中尝试 / * + MATERIALIZE * / 提示。

实际上我发现oracle的旧连接语法比ansi sql ^^

更容易阅读

如果没有索引,那么随着表格大小的增加,该查询只会变得更糟。 话虽如此,尝试删除order by子句并在客户端进行那种排序。

有时,您可以通过为优化器添加额外的路径来看到好处,通过向where子句添加看似多余的元素来进行选择。

例如,你有A.ItemNum = B.ItemNum AND B.ItemNum = C.ItemNum。尝试添加A.ItemNum = C.ItemNum。但是,我很确定优化器足够聪明,可以自己解决这个问题 - 值得一试。

根据ItemType列的数据类型,如果它是varchar,使用以下内容可能会更快执行,Oracle将会进行转换。

SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a,
itempages b,
keygroupdata c
WHERE ((a.ItemType IN ('112','115','189','241'))
AND (a.ItemNum = b.ItemNum)
AND (b.ItemNum = c.ItemNum))
ORDER BY a.DateStored DESC

是否收集了这些表格的统计数据?如果没有,收集统计数据可能会改变执行计划,尽管它不一定会好起来。

除此之外,请查看执行计划。您可能会看到它以非最佳顺序连接表(例如,它可能在加入具有过滤条件的a之前加入b和c)。

您可以使用提示尝试影响访问路径,连接顺序或连接方法。

更新:对评论的回应促使我这个演示文稿,可能会有所帮助,或者至少是有趣的。

如果你说没有索引,那么这是否也意味着没有定义主键或外键?显然,分析表和收集统计信息很重要,但是如果不存在诸如定义表应该如何连接的元数据,则Oracle可能会选择较差的执行路径。

在这种情况下,使用诸如/ * + ORDERED * /之类的提示可能是使优化器可靠地选择良好执行路径的唯一选择。也可能值得添加外键和主键,但将它们定义为DISABLE和VALIDATE。

我想这篇评论的用处取决于对索引的厌恶程度如何,YMMV。

首先在此查询上创建一个视图,然后从该视图生成一个表。还可以在日期创建索引,创建作业并在系统空闲时的午夜时间安排它。

好吧,既然你不能创建索引,我会确保统计数据都是最新的,我会用这种方式重写查询:

<代码> 使用as(选择/ * + MATERIALIZE * / ItemType,ItemNum,DateStored,ItemDate,其中ItemType为(112,115,189,241)) SELECT c.ClaimNumber,a.ItemDate,c.DTN,b.FilePath 从a, 迭代b, keygroupdata c WHERE.ItemNum = b.ItemNum AND b.ItemNum = c.ItemNum 订购由.DateStored DESC

删除ORDER BY

在将行拉回应用程序后执行排序。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top