题
在不创建索引的情况下,我可以采取哪些措施来提高 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
在将行拉回应用程序后执行排序。